@amerged/ohmyhost-cli 0.1.45 → 0.1.46

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.
@@ -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
+ }
@@ -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,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohmyhost/sdk-ts",
3
- "version": "0.1.45",
3
+ "version": "0.1.46",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -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
  *
@@ -962,6 +962,75 @@ export type DatabaseWebhookEventType =
962
962
  */
963
963
  export type DatabaseWebhookEventPattern = DatabaseWebhookEventType | string;
964
964
 
965
+ export type DatabaseTableCreateRequest = {
966
+ environment: "dev" | "prod";
967
+ /**
968
+ * Name of the new table in the public schema. Lower-case, not a PostgreSQL reserved word and not starting with pg_.
969
+ */
970
+ table: string;
971
+ /**
972
+ * Columns in the order written. Names are unique, and at most one column is an identity column.
973
+ */
974
+ columns: Array<DatabaseTableColumnRequest>;
975
+ /**
976
+ * Columns of the primary key, each one of the table's columns. Identity and primary key columns are NOT NULL; omitted when the table has no primary key.
977
+ */
978
+ primary_key?: Array<string>;
979
+ };
980
+
981
+ export type DatabaseTableColumnRequest = {
982
+ name: string;
983
+ type: DatabaseTableColumnType;
984
+ /**
985
+ * Whether the column accepts NULL. Identity and primary key columns never do.
986
+ */
987
+ nullable?: boolean;
988
+ /**
989
+ * Generated always as identity. Only integer and bigint columns can be identity columns, and an identity column has no default.
990
+ */
991
+ identity?: boolean;
992
+ /**
993
+ * now is now() on a timestamptz column; uuid is gen_random_uuid() on a uuid column. Omitted when the column has no default.
994
+ */
995
+ default?: "now" | "uuid";
996
+ };
997
+
998
+ export type DatabaseTableColumnType =
999
+ | "text"
1000
+ | "integer"
1001
+ | "bigint"
1002
+ | "boolean"
1003
+ | "numeric"
1004
+ | "double precision"
1005
+ | "timestamptz"
1006
+ | "date"
1007
+ | "uuid"
1008
+ | "jsonb";
1009
+
1010
+ export type DatabaseTableColumn = {
1011
+ name: string;
1012
+ type: DatabaseTableColumnType;
1013
+ nullable: boolean;
1014
+ identity: boolean;
1015
+ default: "now" | "uuid" | null;
1016
+ };
1017
+
1018
+ export type DatabaseTable = {
1019
+ environment: "dev" | "prod";
1020
+ schema: "public";
1021
+ table: string;
1022
+ columns: Array<DatabaseTableColumn>;
1023
+ primary_key: Array<string>;
1024
+ /**
1025
+ * true when this request created the table, false when an identical table already existed.
1026
+ */
1027
+ created: boolean;
1028
+ };
1029
+
1030
+ export type DatabaseTableCreated = {
1031
+ table: DatabaseTable;
1032
+ };
1033
+
965
1034
  export type DatabaseWatchCreateRequest = {
966
1035
  environment: "dev" | "prod";
967
1036
  /**
@@ -1661,6 +1730,8 @@ export type ProblemDetails = {
1661
1730
  | "database_watch_column_unavailable"
1662
1731
  | "database_watch_events_unavailable"
1663
1732
  | "database_watch_conflict"
1733
+ | "database_table_conflict"
1734
+ | "database_table_limit"
1664
1735
  | "compute_change_pending"
1665
1736
  | "compute_change_conflict"
1666
1737
  | "billing_purchase_conflict"
@@ -8182,6 +8253,76 @@ export type RevokeProjectDatabaseAccessResponses = {
8182
8253
  export type RevokeProjectDatabaseAccessResponse =
8183
8254
  RevokeProjectDatabaseAccessResponses[keyof RevokeProjectDatabaseAccessResponses];
8184
8255
 
8256
+ export type CreateProjectDatabaseTableData = {
8257
+ body: DatabaseTableCreateRequest;
8258
+ headers: {
8259
+ /**
8260
+ * Optional caller-provided correlation identifier.
8261
+ */
8262
+ "X-Request-Id"?: string;
8263
+ /**
8264
+ * Identifies one mutation and its canonical request payload.
8265
+ */
8266
+ "Idempotency-Key": string;
8267
+ };
8268
+ path: {
8269
+ /**
8270
+ * Project identifier.
8271
+ */
8272
+ project_id: Ulid;
8273
+ };
8274
+ query?: never;
8275
+ url: "/v1/projects/{project_id}/database/tables";
8276
+ };
8277
+
8278
+ export type CreateProjectDatabaseTableErrors = {
8279
+ /**
8280
+ * The request failed.
8281
+ */
8282
+ 400: ProblemDetails;
8283
+ /**
8284
+ * The request failed.
8285
+ */
8286
+ 401: ProblemDetails;
8287
+ /**
8288
+ * The request failed.
8289
+ */
8290
+ 402: ProblemDetails;
8291
+ /**
8292
+ * The resource does not exist or is not visible to the authenticated principal.
8293
+ */
8294
+ 404: ProblemDetails;
8295
+ /**
8296
+ * The request failed.
8297
+ */
8298
+ 409: ProblemDetails;
8299
+ /**
8300
+ * The request failed.
8301
+ */
8302
+ 429: ProblemDetails;
8303
+ /**
8304
+ * The request failed.
8305
+ */
8306
+ 503: ProblemDetails;
8307
+ };
8308
+
8309
+ export type CreateProjectDatabaseTableError =
8310
+ CreateProjectDatabaseTableErrors[keyof CreateProjectDatabaseTableErrors];
8311
+
8312
+ export type CreateProjectDatabaseTableResponses = {
8313
+ /**
8314
+ * The table already exists with the same columns, types, nullability, identity, defaults and primary key.
8315
+ */
8316
+ 200: DatabaseTableCreated;
8317
+ /**
8318
+ * The table this request created.
8319
+ */
8320
+ 201: DatabaseTableCreated;
8321
+ };
8322
+
8323
+ export type CreateProjectDatabaseTableResponse =
8324
+ CreateProjectDatabaseTableResponses[keyof CreateProjectDatabaseTableResponses];
8325
+
8185
8326
  export type ListProjectDatabaseWatchesData = {
8186
8327
  body?: never;
8187
8328
  headers?: {