@amerged/ohmyhost-mcp 0.1.45 → 0.1.47
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.
- package/README.md +1 -1
- package/dist/{chunk-AJV4T4LM.js → chunk-AH764FGJ.js} +18 -9
- package/dist/index.js +1 -1
- package/dist/stdio-main.js +318 -37
- package/package.json +1 -1
- package/src/apps/mcp/package.json +1 -1
- package/src/apps/mcp/src/local-client.ts +27 -0
- package/src/apps/mcp/src/local-server.ts +65 -0
- package/src/apps/product-cli/package.json +1 -1
- package/src/apps/product-cli/src/cli.ts +77 -2
- package/src/apps/product-cli/src/command.ts +63 -0
- package/src/apps/product-cli/src/product-api.ts +116 -0
- package/src/apps/product-cli/src/repository-init.ts +5 -0
- package/src/packages/agent-skills/src/generated-skill-resources.ts +17 -8
- package/src/packages/contracts/package.json +5 -0
- package/src/packages/contracts/src/database-tables.ts +317 -0
- package/src/packages/contracts/src/framework-admission.ts +3 -3
- package/src/packages/contracts/src/framework-source-rules.ts +9 -1
- package/src/packages/contracts/src/index.ts +13 -0
- package/src/packages/contracts/src/problem-policy.ts +14 -0
- package/src/packages/contracts/src/secret-names.ts +1 -0
- package/src/packages/sdk-ts/package.json +1 -1
- package/src/packages/sdk-ts/src/generated/index.ts +12 -0
- package/src/packages/sdk-ts/src/generated/sdk.gen.ts +54 -0
- package/src/packages/sdk-ts/src/generated/types.gen.ts +141 -0
|
@@ -132,6 +132,11 @@
|
|
|
132
132
|
"types": "./dist/database-events.d.ts",
|
|
133
133
|
"import": "./dist/database-events.js"
|
|
134
134
|
},
|
|
135
|
+
"./database-tables": {
|
|
136
|
+
"source": "./src/database-tables.ts",
|
|
137
|
+
"types": "./dist/database-tables.d.ts",
|
|
138
|
+
"import": "./dist/database-tables.js"
|
|
139
|
+
},
|
|
135
140
|
"./functions": {
|
|
136
141
|
"source": "./src/functions.ts",
|
|
137
142
|
"types": "./dist/functions.d.ts",
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/** Column types a created table may declare; the closed list keeps type text out of the DDL. */
|
|
2
|
+
export const DATABASE_TABLE_COLUMN_TYPES = [
|
|
3
|
+
"text",
|
|
4
|
+
"integer",
|
|
5
|
+
"bigint",
|
|
6
|
+
"boolean",
|
|
7
|
+
"numeric",
|
|
8
|
+
"double precision",
|
|
9
|
+
"timestamptz",
|
|
10
|
+
"date",
|
|
11
|
+
"uuid",
|
|
12
|
+
"jsonb",
|
|
13
|
+
] as const;
|
|
14
|
+
export type DatabaseTableColumnType = (typeof DATABASE_TABLE_COLUMN_TYPES)[number];
|
|
15
|
+
/** `now` is DEFAULT now() on timestamptz; `uuid` is DEFAULT gen_random_uuid() on uuid. */
|
|
16
|
+
export const DATABASE_TABLE_DEFAULTS = ["now", "uuid"] as const;
|
|
17
|
+
export type DatabaseTableDefault = (typeof DATABASE_TABLE_DEFAULTS)[number];
|
|
18
|
+
export const DATABASE_TABLE_MAX_COLUMNS = 64;
|
|
19
|
+
export const DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS = 8;
|
|
20
|
+
/** Ordinary and partitioned tables that a database may hold in its public schema. */
|
|
21
|
+
export const DATABASE_TABLE_LIMIT = 100;
|
|
22
|
+
export const DATABASE_TABLE_SCHEMA = "public";
|
|
23
|
+
|
|
24
|
+
const DATABASE_TABLE_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/u;
|
|
25
|
+
/** PostgreSQL reserved words: a table or column of such a name would need quoting everywhere it is used. */
|
|
26
|
+
const RESERVED_WORDS: ReadonlySet<string> = new Set([
|
|
27
|
+
"all",
|
|
28
|
+
"analyse",
|
|
29
|
+
"analyze",
|
|
30
|
+
"and",
|
|
31
|
+
"any",
|
|
32
|
+
"array",
|
|
33
|
+
"as",
|
|
34
|
+
"asc",
|
|
35
|
+
"asymmetric",
|
|
36
|
+
"both",
|
|
37
|
+
"case",
|
|
38
|
+
"cast",
|
|
39
|
+
"check",
|
|
40
|
+
"collate",
|
|
41
|
+
"column",
|
|
42
|
+
"constraint",
|
|
43
|
+
"create",
|
|
44
|
+
"current_catalog",
|
|
45
|
+
"current_date",
|
|
46
|
+
"current_role",
|
|
47
|
+
"current_time",
|
|
48
|
+
"current_timestamp",
|
|
49
|
+
"current_user",
|
|
50
|
+
"default",
|
|
51
|
+
"deferrable",
|
|
52
|
+
"desc",
|
|
53
|
+
"distinct",
|
|
54
|
+
"do",
|
|
55
|
+
"else",
|
|
56
|
+
"end",
|
|
57
|
+
"except",
|
|
58
|
+
"false",
|
|
59
|
+
"fetch",
|
|
60
|
+
"for",
|
|
61
|
+
"foreign",
|
|
62
|
+
"from",
|
|
63
|
+
"grant",
|
|
64
|
+
"group",
|
|
65
|
+
"having",
|
|
66
|
+
"in",
|
|
67
|
+
"initially",
|
|
68
|
+
"intersect",
|
|
69
|
+
"into",
|
|
70
|
+
"lateral",
|
|
71
|
+
"leading",
|
|
72
|
+
"limit",
|
|
73
|
+
"localtime",
|
|
74
|
+
"localtimestamp",
|
|
75
|
+
"not",
|
|
76
|
+
"null",
|
|
77
|
+
"offset",
|
|
78
|
+
"on",
|
|
79
|
+
"only",
|
|
80
|
+
"or",
|
|
81
|
+
"order",
|
|
82
|
+
"placing",
|
|
83
|
+
"primary",
|
|
84
|
+
"references",
|
|
85
|
+
"returning",
|
|
86
|
+
"select",
|
|
87
|
+
"session_user",
|
|
88
|
+
"some",
|
|
89
|
+
"symmetric",
|
|
90
|
+
"table",
|
|
91
|
+
"then",
|
|
92
|
+
"to",
|
|
93
|
+
"trailing",
|
|
94
|
+
"true",
|
|
95
|
+
"union",
|
|
96
|
+
"unique",
|
|
97
|
+
"user",
|
|
98
|
+
"using",
|
|
99
|
+
"variadic",
|
|
100
|
+
"when",
|
|
101
|
+
"where",
|
|
102
|
+
"window",
|
|
103
|
+
"with",
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
export interface DatabaseTableColumn {
|
|
107
|
+
readonly name: string;
|
|
108
|
+
readonly type: DatabaseTableColumnType;
|
|
109
|
+
readonly nullable: boolean;
|
|
110
|
+
readonly identity: boolean;
|
|
111
|
+
readonly default: DatabaseTableDefault | null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** A create request after parsing: nullable is concrete and primaryKey is empty when the request names none. */
|
|
115
|
+
export interface DatabaseTableRequest {
|
|
116
|
+
readonly table: string;
|
|
117
|
+
readonly columns: readonly DatabaseTableColumn[];
|
|
118
|
+
readonly primaryKey: readonly string[];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface DatabaseTable {
|
|
122
|
+
readonly schema: typeof DATABASE_TABLE_SCHEMA;
|
|
123
|
+
readonly table: string;
|
|
124
|
+
readonly columns: readonly DatabaseTableColumn[];
|
|
125
|
+
readonly primaryKey: readonly string[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface DatabaseTableCreated {
|
|
129
|
+
readonly table: DatabaseTable;
|
|
130
|
+
readonly created: boolean;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface ColumnInput {
|
|
134
|
+
readonly name: string;
|
|
135
|
+
readonly type: DatabaseTableColumnType;
|
|
136
|
+
readonly nullable: boolean | undefined;
|
|
137
|
+
readonly identity: boolean;
|
|
138
|
+
readonly default: DatabaseTableDefault | null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Identifiers are plain lower-case SQL names; the renderer quotes them and no other caller text reaches the DDL. */
|
|
142
|
+
export function isDatabaseTableIdentifier(value: unknown): value is string {
|
|
143
|
+
return (
|
|
144
|
+
typeof value === "string" &&
|
|
145
|
+
DATABASE_TABLE_IDENTIFIER_PATTERN.test(value) &&
|
|
146
|
+
!value.startsWith("pg_") &&
|
|
147
|
+
!RESERVED_WORDS.has(value)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function parseDatabaseTableCreateRequest(value: unknown): DatabaseTableRequest {
|
|
152
|
+
if (
|
|
153
|
+
!record(value) ||
|
|
154
|
+
!onlyKeys(value, ["table", "columns", "primaryKey"]) ||
|
|
155
|
+
!isDatabaseTableIdentifier(value["table"]) ||
|
|
156
|
+
!Array.isArray(value["columns"]) ||
|
|
157
|
+
value["columns"].length < 1 ||
|
|
158
|
+
value["columns"].length > DATABASE_TABLE_MAX_COLUMNS
|
|
159
|
+
)
|
|
160
|
+
throw new TypeError("Invalid database table request");
|
|
161
|
+
const inputs = value["columns"].map(parseColumn);
|
|
162
|
+
const names = inputs.map((column) => column.name);
|
|
163
|
+
if (new Set(names).size !== names.length || inputs.filter((column) => column.identity).length > 1)
|
|
164
|
+
throw new TypeError("Invalid database table request");
|
|
165
|
+
const primaryKey = parsePrimaryKey(value["primaryKey"], names);
|
|
166
|
+
return {
|
|
167
|
+
table: value["table"],
|
|
168
|
+
columns: inputs.map((column) => completeColumn(column, primaryKey.includes(column.name))),
|
|
169
|
+
primaryKey,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* The one CREATE TABLE statement of a request, in the public schema. Identifiers are validated again here, so the
|
|
175
|
+
* renderer is safe for any caller; the statement has no trailing semicolon.
|
|
176
|
+
*/
|
|
177
|
+
export function renderCreateTableStatement(request: DatabaseTableRequest): string {
|
|
178
|
+
const definitions = request.columns.map(renderColumn);
|
|
179
|
+
if (request.primaryKey.length > 0)
|
|
180
|
+
definitions.push(`PRIMARY KEY (${request.primaryKey.map(quoted).join(",")})`);
|
|
181
|
+
return `CREATE TABLE ${databaseTableReference(request.table)} (${definitions.join(", ")})`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The quoted, schema-qualified name of a table of the public schema, as SQL statements use it. */
|
|
185
|
+
export function databaseTableReference(table: string): string {
|
|
186
|
+
return `${quoted(DATABASE_TABLE_SCHEMA)}.${quoted(table)}`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function assertDatabaseTableCreated(value: unknown): asserts value is DatabaseTableCreated {
|
|
190
|
+
if (
|
|
191
|
+
!record(value) ||
|
|
192
|
+
!exact(value, ["table", "created"]) ||
|
|
193
|
+
typeof value["created"] !== "boolean" ||
|
|
194
|
+
!isDatabaseTable(value["table"])
|
|
195
|
+
)
|
|
196
|
+
throw new TypeError("Invalid database table");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function parseColumn(value: unknown): ColumnInput {
|
|
200
|
+
if (
|
|
201
|
+
!record(value) ||
|
|
202
|
+
!onlyKeys(value, ["name", "type", "nullable", "identity", "default"]) ||
|
|
203
|
+
!isDatabaseTableIdentifier(value["name"]) ||
|
|
204
|
+
!oneOf(DATABASE_TABLE_COLUMN_TYPES, value["type"]) ||
|
|
205
|
+
(value["nullable"] !== undefined && typeof value["nullable"] !== "boolean") ||
|
|
206
|
+
(value["identity"] !== undefined && typeof value["identity"] !== "boolean") ||
|
|
207
|
+
(value["default"] !== undefined && !oneOf(DATABASE_TABLE_DEFAULTS, value["default"]))
|
|
208
|
+
)
|
|
209
|
+
throw new TypeError("Invalid database table request");
|
|
210
|
+
const type = value["type"];
|
|
211
|
+
const identity = value["identity"] === true;
|
|
212
|
+
const defaultValue = value["default"] ?? null;
|
|
213
|
+
if (identity && type !== "integer" && type !== "bigint")
|
|
214
|
+
throw new TypeError("Invalid database table request");
|
|
215
|
+
if (identity && defaultValue !== null) throw new TypeError("Invalid database table request");
|
|
216
|
+
if (defaultValue === "now" && type !== "timestamptz")
|
|
217
|
+
throw new TypeError("Invalid database table request");
|
|
218
|
+
if (defaultValue === "uuid" && type !== "uuid")
|
|
219
|
+
throw new TypeError("Invalid database table request");
|
|
220
|
+
return {
|
|
221
|
+
name: value["name"],
|
|
222
|
+
type,
|
|
223
|
+
nullable: value["nullable"],
|
|
224
|
+
identity,
|
|
225
|
+
default: defaultValue,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function parsePrimaryKey(value: unknown, names: readonly string[]): readonly string[] {
|
|
230
|
+
if (value === undefined) return [];
|
|
231
|
+
if (
|
|
232
|
+
!Array.isArray(value) ||
|
|
233
|
+
value.length < 1 ||
|
|
234
|
+
value.length > DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS ||
|
|
235
|
+
new Set(value).size !== value.length ||
|
|
236
|
+
!value.every((name) => typeof name === "string" && names.includes(name))
|
|
237
|
+
)
|
|
238
|
+
throw new TypeError("Invalid database table request");
|
|
239
|
+
return value as string[];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Identity and primary key columns are NOT NULL; asking for a nullable one of them is a contradiction. */
|
|
243
|
+
function completeColumn(column: ColumnInput, keyed: boolean): DatabaseTableColumn {
|
|
244
|
+
const required = column.identity || keyed;
|
|
245
|
+
if (required && column.nullable === true) throw new TypeError("Invalid database table request");
|
|
246
|
+
return {
|
|
247
|
+
name: column.name,
|
|
248
|
+
type: column.type,
|
|
249
|
+
nullable: required ? false : (column.nullable ?? true),
|
|
250
|
+
identity: column.identity,
|
|
251
|
+
default: column.default,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function renderColumn(column: DatabaseTableColumn): string {
|
|
256
|
+
if (!oneOf(DATABASE_TABLE_COLUMN_TYPES, column.type))
|
|
257
|
+
throw new TypeError("Invalid database table column type");
|
|
258
|
+
const parts = [quoted(column.name), column.type];
|
|
259
|
+
if (!column.nullable) parts.push("NOT NULL");
|
|
260
|
+
if (column.identity) parts.push("GENERATED ALWAYS AS IDENTITY");
|
|
261
|
+
if (column.default === "now") parts.push("DEFAULT now()");
|
|
262
|
+
if (column.default === "uuid") parts.push("DEFAULT gen_random_uuid()");
|
|
263
|
+
return parts.join(" ");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function quoted(identifier: string): string {
|
|
267
|
+
if (!isDatabaseTableIdentifier(identifier))
|
|
268
|
+
throw new TypeError("Invalid database table identifier");
|
|
269
|
+
return `"${identifier}"`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function isDatabaseTable(value: unknown): boolean {
|
|
273
|
+
if (!record(value) || !exact(value, ["schema", "table", "columns", "primaryKey"])) return false;
|
|
274
|
+
const columns = value["columns"];
|
|
275
|
+
const primaryKey = value["primaryKey"];
|
|
276
|
+
if (
|
|
277
|
+
value["schema"] !== DATABASE_TABLE_SCHEMA ||
|
|
278
|
+
!isDatabaseTableIdentifier(value["table"]) ||
|
|
279
|
+
!Array.isArray(columns) ||
|
|
280
|
+
columns.length < 1 ||
|
|
281
|
+
columns.length > DATABASE_TABLE_MAX_COLUMNS ||
|
|
282
|
+
!columns.every(isDatabaseTableColumn) ||
|
|
283
|
+
!Array.isArray(primaryKey) ||
|
|
284
|
+
primaryKey.length > DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS
|
|
285
|
+
)
|
|
286
|
+
return false;
|
|
287
|
+
const names = columns.map((column) => column.name);
|
|
288
|
+
return primaryKey.every((name) => typeof name === "string" && names.includes(name));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function isDatabaseTableColumn(value: unknown): value is DatabaseTableColumn {
|
|
292
|
+
return (
|
|
293
|
+
record(value) &&
|
|
294
|
+
exact(value, ["name", "type", "nullable", "identity", "default"]) &&
|
|
295
|
+
isDatabaseTableIdentifier(value["name"]) &&
|
|
296
|
+
oneOf(DATABASE_TABLE_COLUMN_TYPES, value["type"]) &&
|
|
297
|
+
typeof value["nullable"] === "boolean" &&
|
|
298
|
+
typeof value["identity"] === "boolean" &&
|
|
299
|
+
(value["default"] === null || oneOf(DATABASE_TABLE_DEFAULTS, value["default"]))
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function oneOf<T extends string>(allowed: readonly T[], value: unknown): value is T {
|
|
304
|
+
return typeof value === "string" && (allowed as readonly string[]).includes(value);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function record(value: unknown): value is Record<string, unknown> {
|
|
308
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function onlyKeys(value: Record<string, unknown>, allowed: readonly string[]): boolean {
|
|
312
|
+
return Object.keys(value).every((key) => allowed.includes(key));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function exact(value: Record<string, unknown>, keys: readonly string[]): boolean {
|
|
316
|
+
return Object.keys(value).sort().join(",") === [...keys].sort().join(",");
|
|
317
|
+
}
|
|
@@ -509,8 +509,8 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
509
509
|
text: {
|
|
510
510
|
nextjs: "runtime.mode: edge",
|
|
511
511
|
"vite-static":
|
|
512
|
-
"runtime.mode: edge with src/ohmyhost/companion.ts when database, auth, mail, storage or functions.crons is set, and static otherwise",
|
|
513
|
-
"tanstack-start": "runtime.mode: edge, or static without functions.crons and
|
|
512
|
+
"runtime.mode: edge with src/ohmyhost/companion.ts when database, auth, mail, ai, storage or functions.crons is set, and static otherwise",
|
|
513
|
+
"tanstack-start": "runtime.mode: edge, or static without functions.crons, storage and ai",
|
|
514
514
|
astro: "runtime.mode: static for prerendered sites, or edge with the Cloudflare adapter",
|
|
515
515
|
},
|
|
516
516
|
},
|
|
@@ -580,7 +580,7 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
580
580
|
companion_entry_required: {
|
|
581
581
|
paths: ["module"],
|
|
582
582
|
template:
|
|
583
|
-
'"{{path}}" is missing. A Vite app with runtime.mode: edge or with database, auth, mail, storage or functions.crons needs this Worker module with export default { fetch }. Add it, or use runtime.mode: static without those settings; commit and push the change, then plan the new commit.',
|
|
583
|
+
'"{{path}}" is missing. A Vite app with runtime.mode: edge or with database, auth, mail, ai, storage or functions.crons needs this Worker module with export default { fetch }. Add it, or use runtime.mode: static without those settings; commit and push the change, then plan the new commit.',
|
|
584
584
|
},
|
|
585
585
|
worker_module_required: {
|
|
586
586
|
paths: ["module"],
|
|
@@ -209,6 +209,7 @@ export function viteCompanionRequired(configuration: OhmyhostConfig): boolean {
|
|
|
209
209
|
configuration.database?.enabled === true ||
|
|
210
210
|
configuration.auth?.provider === "better-auth" ||
|
|
211
211
|
configuration.mail?.enabled === true ||
|
|
212
|
+
configuration.ai?.enabled === true ||
|
|
212
213
|
configuration.storage !== undefined ||
|
|
213
214
|
(configuration.functions?.crons.length ?? 0) > 0
|
|
214
215
|
);
|
|
@@ -637,12 +638,19 @@ function runtimeModeAdmitted(
|
|
|
637
638
|
configuration.storage === undefined &&
|
|
638
639
|
configuration.database?.enabled !== true &&
|
|
639
640
|
configuration.mail?.enabled !== true &&
|
|
641
|
+
configuration.ai?.enabled !== true &&
|
|
640
642
|
configuration.auth?.provider !== "better-auth")
|
|
641
643
|
);
|
|
642
644
|
if (framework === "nextjs") return mode === "edge";
|
|
643
645
|
if (framework === "vite-static")
|
|
644
646
|
return mode === (viteCompanionRequired(configuration) ? "edge" : "static");
|
|
645
|
-
return
|
|
647
|
+
return (
|
|
648
|
+
mode === "edge" ||
|
|
649
|
+
(mode === "static" &&
|
|
650
|
+
!crons &&
|
|
651
|
+
configuration.storage === undefined &&
|
|
652
|
+
configuration.ai?.enabled !== true)
|
|
653
|
+
);
|
|
646
654
|
}
|
|
647
655
|
|
|
648
656
|
function betterAuthFindings(
|
|
@@ -56,6 +56,11 @@ export interface OhmyhostConfig {
|
|
|
56
56
|
jurisdiction: "us" | "eu";
|
|
57
57
|
public: false;
|
|
58
58
|
}>;
|
|
59
|
+
/** `jurisdiction` is required when `enabled` is true; it has no default. */
|
|
60
|
+
readonly ai?: Readonly<{
|
|
61
|
+
enabled: boolean;
|
|
62
|
+
jurisdiction?: "eu" | "any";
|
|
63
|
+
}>;
|
|
59
64
|
readonly functions?: Readonly<{ crons: readonly string[] }>;
|
|
60
65
|
readonly credits?: Readonly<{
|
|
61
66
|
monthly_budget: number;
|
|
@@ -125,6 +130,14 @@ export function parseOhmyhostConfig(value: unknown): OhmyhostConfig {
|
|
|
125
130
|
public: input.storage.public,
|
|
126
131
|
}),
|
|
127
132
|
}),
|
|
133
|
+
...(input.ai === undefined
|
|
134
|
+
? {}
|
|
135
|
+
: {
|
|
136
|
+
ai: Object.freeze({
|
|
137
|
+
enabled: input.ai.enabled,
|
|
138
|
+
...(input.ai.jurisdiction === undefined ? {} : { jurisdiction: input.ai.jurisdiction }),
|
|
139
|
+
}),
|
|
140
|
+
}),
|
|
128
141
|
...(input.functions === undefined
|
|
129
142
|
? {}
|
|
130
143
|
: {
|
|
@@ -227,6 +227,20 @@ export const PROBLEM_POLICY = {
|
|
|
227
227
|
"A migration already attaches a capture trigger to this table: keep it and skip the watch, or remove it from the migrations, deploy and create the watch again. A table carries one capture trigger.",
|
|
228
228
|
title: "Table already has a capture trigger",
|
|
229
229
|
},
|
|
230
|
+
database_table_conflict: {
|
|
231
|
+
status: 409,
|
|
232
|
+
retryable: false,
|
|
233
|
+
action:
|
|
234
|
+
"A table with this name already exists with another definition. Choose another table name, or create the table again with the same columns, types, nullability, identity, defaults and primary key it has.",
|
|
235
|
+
title: "Table already exists with another definition",
|
|
236
|
+
},
|
|
237
|
+
database_table_limit: {
|
|
238
|
+
status: 409,
|
|
239
|
+
retryable: false,
|
|
240
|
+
action:
|
|
241
|
+
"This database already holds the maximum number of tables in its public schema, so no table can be added. Use an existing table, or remove a table you no longer need through a deployed migration, then create the table again.",
|
|
242
|
+
title: "Database table limit reached",
|
|
243
|
+
},
|
|
230
244
|
project_notes_conflict: {
|
|
231
245
|
status: 409,
|
|
232
246
|
retryable: false,
|
|
@@ -23,6 +23,7 @@ export {
|
|
|
23
23
|
createOrganization,
|
|
24
24
|
createProject,
|
|
25
25
|
createProjectDatabaseAccess,
|
|
26
|
+
createProjectDatabaseTable,
|
|
26
27
|
createProjectDatabaseWatch,
|
|
27
28
|
createProjectDatabaseWebhook,
|
|
28
29
|
createProjectDataChange,
|
|
@@ -274,6 +275,11 @@ export type {
|
|
|
274
275
|
CreateProjectDatabaseAccessErrors,
|
|
275
276
|
CreateProjectDatabaseAccessResponse,
|
|
276
277
|
CreateProjectDatabaseAccessResponses,
|
|
278
|
+
CreateProjectDatabaseTableData,
|
|
279
|
+
CreateProjectDatabaseTableError,
|
|
280
|
+
CreateProjectDatabaseTableErrors,
|
|
281
|
+
CreateProjectDatabaseTableResponse,
|
|
282
|
+
CreateProjectDatabaseTableResponses,
|
|
277
283
|
CreateProjectDatabaseWatchData,
|
|
278
284
|
CreateProjectDatabaseWatchError,
|
|
279
285
|
CreateProjectDatabaseWatchErrors,
|
|
@@ -333,6 +339,12 @@ export type {
|
|
|
333
339
|
DatabaseScheduleRunAccepted,
|
|
334
340
|
DatabaseScheduleRunPage,
|
|
335
341
|
DatabaseScheduleSetRequest,
|
|
342
|
+
DatabaseTable,
|
|
343
|
+
DatabaseTableColumn,
|
|
344
|
+
DatabaseTableColumnRequest,
|
|
345
|
+
DatabaseTableColumnType,
|
|
346
|
+
DatabaseTableCreated,
|
|
347
|
+
DatabaseTableCreateRequest,
|
|
336
348
|
DatabaseWatch,
|
|
337
349
|
DatabaseWatchCreateRequest,
|
|
338
350
|
DatabaseWatchDeleted,
|
|
@@ -60,6 +60,8 @@ import type {
|
|
|
60
60
|
CreateOrganizationResponses,
|
|
61
61
|
CreateProjectDatabaseAccessErrors,
|
|
62
62
|
CreateProjectDatabaseAccessResponses,
|
|
63
|
+
CreateProjectDatabaseTableErrors,
|
|
64
|
+
CreateProjectDatabaseTableResponses,
|
|
63
65
|
CreateProjectDatabaseWatchErrors,
|
|
64
66
|
CreateProjectDatabaseWatchResponses,
|
|
65
67
|
CreateProjectDatabaseWebhookErrors,
|
|
@@ -79,6 +81,7 @@ import type {
|
|
|
79
81
|
CreateWorkspaceMailDomainRequest,
|
|
80
82
|
CreateWorkspaceMailDomainResponses,
|
|
81
83
|
DatabaseScheduleSetRequest,
|
|
84
|
+
DatabaseTableCreateRequest,
|
|
82
85
|
DatabaseWatchCreateRequest,
|
|
83
86
|
DatabaseWebhookCreateRequest,
|
|
84
87
|
DeclareApplicationDomainIdentityErrors,
|
|
@@ -4766,6 +4769,57 @@ export const revokeProjectDatabaseAccess = <ThrowOnError extends boolean = true>
|
|
|
4766
4769
|
});
|
|
4767
4770
|
};
|
|
4768
4771
|
|
|
4772
|
+
/**
|
|
4773
|
+
* Create a table in the project's database
|
|
4774
|
+
*
|
|
4775
|
+
* Creates one ordinary table in the public schema of one environment's database, with the columns and the primary key the request names. Repeating an identical request answers the existing table with 200; a table of the same name with another definition is refused with database_table_conflict (409). The request wakes a sleeping database. A reached Stop budget refuses with project_budget_exceeded (402). At most 100 tables exist per database.
|
|
4776
|
+
*/
|
|
4777
|
+
export const createProjectDatabaseTable = <ThrowOnError extends boolean = true>(
|
|
4778
|
+
parameters: {
|
|
4779
|
+
"X-Request-Id"?: string;
|
|
4780
|
+
"Idempotency-Key": string;
|
|
4781
|
+
project_id: Ulid;
|
|
4782
|
+
databaseTableCreateRequest: DatabaseTableCreateRequest;
|
|
4783
|
+
},
|
|
4784
|
+
options?: Options<never, ThrowOnError>,
|
|
4785
|
+
): RequestResult<
|
|
4786
|
+
CreateProjectDatabaseTableResponses,
|
|
4787
|
+
CreateProjectDatabaseTableErrors,
|
|
4788
|
+
ThrowOnError,
|
|
4789
|
+
"data"
|
|
4790
|
+
> => {
|
|
4791
|
+
const params = buildClientParams(
|
|
4792
|
+
[parameters],
|
|
4793
|
+
[
|
|
4794
|
+
{
|
|
4795
|
+
args: [
|
|
4796
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
4797
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
4798
|
+
{ in: "path", key: "project_id" },
|
|
4799
|
+
{ key: "databaseTableCreateRequest", map: "body" },
|
|
4800
|
+
],
|
|
4801
|
+
},
|
|
4802
|
+
],
|
|
4803
|
+
);
|
|
4804
|
+
return (options?.client ?? client).post<
|
|
4805
|
+
CreateProjectDatabaseTableResponses,
|
|
4806
|
+
CreateProjectDatabaseTableErrors,
|
|
4807
|
+
ThrowOnError,
|
|
4808
|
+
"data"
|
|
4809
|
+
>({
|
|
4810
|
+
responseStyle: "data",
|
|
4811
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
4812
|
+
url: "/v1/projects/{project_id}/database/tables",
|
|
4813
|
+
...options,
|
|
4814
|
+
...params,
|
|
4815
|
+
headers: {
|
|
4816
|
+
"Content-Type": "application/json",
|
|
4817
|
+
...options?.headers,
|
|
4818
|
+
...params.headers,
|
|
4819
|
+
},
|
|
4820
|
+
});
|
|
4821
|
+
};
|
|
4822
|
+
|
|
4769
4823
|
/**
|
|
4770
4824
|
* List the project's database watches
|
|
4771
4825
|
*
|