@amerged/ohmyhost-mcp 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.
- package/README.md +1 -1
- package/dist/{chunk-AJV4T4LM.js → chunk-2GRH5YCK.js} +4 -4
- package/dist/index.js +1 -1
- package/dist/stdio-main.js +313 -34
- 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 +76 -1
- package/src/apps/product-cli/src/command.ts +63 -0
- package/src/apps/product-cli/src/product-api.ts +116 -0
- package/src/packages/agent-skills/src/generated-skill-resources.ts +3 -3
- package/src/packages/contracts/package.json +5 -0
- package/src/packages/contracts/src/database-tables.ts +317 -0
- package/src/packages/contracts/src/problem-policy.ts +14 -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
package/dist/stdio-main.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
serverIdentityOf,
|
|
31
31
|
setNegotiatedProtocolVersion,
|
|
32
32
|
validateEnvelopeMeta
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-2GRH5YCK.js";
|
|
34
34
|
|
|
35
35
|
// node_modules/.pnpm/ignore@7.0.12/node_modules/ignore/index.js
|
|
36
36
|
var require_ignore = __commonJS({
|
|
@@ -24293,14 +24293,14 @@ function isFrameworkConversionDiagnosticCode(value) {
|
|
|
24293
24293
|
function parseFrameworkConversionDiagnostic(value) {
|
|
24294
24294
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
24295
24295
|
return null;
|
|
24296
|
-
const
|
|
24297
|
-
const code = Object.hasOwn(
|
|
24298
|
-
const path2 = Object.hasOwn(
|
|
24296
|
+
const record9 = value;
|
|
24297
|
+
const code = Object.hasOwn(record9, "code") ? record9["code"] : void 0;
|
|
24298
|
+
const path2 = Object.hasOwn(record9, "path") ? record9["path"] : void 0;
|
|
24299
24299
|
if (!isFrameworkConversionDiagnosticCode(code) || typeof path2 !== "string")
|
|
24300
24300
|
return null;
|
|
24301
24301
|
const definition = DETAIL_DEFINITIONS[code];
|
|
24302
|
-
const fields = Object.entries(definition.fields ?? {}).map(([name, grammar]) => [name, grammar, Object.hasOwn(
|
|
24303
|
-
if (Object.keys(
|
|
24302
|
+
const fields = Object.entries(definition.fields ?? {}).map(([name, grammar]) => [name, grammar, Object.hasOwn(record9, name) ? record9[name] : void 0]);
|
|
24303
|
+
if (Object.keys(record9).length !== fields.length + 2 || pathClassOf(definition, path2) === null || fields.some(([, grammar, field]) => !fieldMatches(grammar, field)))
|
|
24304
24304
|
return null;
|
|
24305
24305
|
return Object.freeze(Object.fromEntries([
|
|
24306
24306
|
["code", code],
|
|
@@ -25602,6 +25602,18 @@ var PROBLEM_POLICY = {
|
|
|
25602
25602
|
action: "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.",
|
|
25603
25603
|
title: "Table already has a capture trigger"
|
|
25604
25604
|
},
|
|
25605
|
+
database_table_conflict: {
|
|
25606
|
+
status: 409,
|
|
25607
|
+
retryable: false,
|
|
25608
|
+
action: "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.",
|
|
25609
|
+
title: "Table already exists with another definition"
|
|
25610
|
+
},
|
|
25611
|
+
database_table_limit: {
|
|
25612
|
+
status: 409,
|
|
25613
|
+
retryable: false,
|
|
25614
|
+
action: "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.",
|
|
25615
|
+
title: "Database table limit reached"
|
|
25616
|
+
},
|
|
25605
25617
|
project_notes_conflict: {
|
|
25606
25618
|
status: 409,
|
|
25607
25619
|
retryable: false,
|
|
@@ -26285,8 +26297,8 @@ var isPaidValidationRecord = (value) => {
|
|
|
26285
26297
|
if (typeof value !== "object" || value === null || Array.isArray(value) || Object.keys(value).sort().join(",") !== "content,name,purpose,type") {
|
|
26286
26298
|
return false;
|
|
26287
26299
|
}
|
|
26288
|
-
const
|
|
26289
|
-
return (
|
|
26300
|
+
const record9 = value;
|
|
26301
|
+
return (record9["type"] === "CNAME" || record9["type"] === "TXT") && boundedString(record9["name"], 1, 253) && boundedString(record9["content"], 1, 2048) && ["traffic", "ownership", "ssl", "dcv_delegation"].includes(String(record9["purpose"]));
|
|
26290
26302
|
};
|
|
26291
26303
|
|
|
26292
26304
|
// apps/product-cli/dist/source-publisher.js
|
|
@@ -26556,7 +26568,7 @@ async function prepareLocalSourcePublication(input) {
|
|
|
26556
26568
|
request = { ...request, expected_commit_sha: link2.source.last_confirmed_commit_sha };
|
|
26557
26569
|
}
|
|
26558
26570
|
parseManagedSourceRequest("upload", request);
|
|
26559
|
-
const
|
|
26571
|
+
const record9 = {
|
|
26560
26572
|
version: 1,
|
|
26561
26573
|
...scope,
|
|
26562
26574
|
operation_id: null,
|
|
@@ -26565,16 +26577,16 @@ async function prepareLocalSourcePublication(input) {
|
|
|
26565
26577
|
request
|
|
26566
26578
|
};
|
|
26567
26579
|
if (original !== null) {
|
|
26568
|
-
assertSameAttempt(original,
|
|
26580
|
+
assertSameAttempt(original, record9);
|
|
26569
26581
|
} else
|
|
26570
|
-
await writePending(
|
|
26582
|
+
await writePending(record9, true);
|
|
26571
26583
|
return {
|
|
26572
26584
|
request,
|
|
26573
26585
|
accepted: async (operation) => {
|
|
26574
26586
|
const current = await readPending(scope, replay);
|
|
26575
26587
|
if (current === null)
|
|
26576
26588
|
throw new LocalSourcePublicationError("source_publication_missing");
|
|
26577
|
-
assertSameAttempt(current,
|
|
26589
|
+
assertSameAttempt(current, record9);
|
|
26578
26590
|
if (current.operation_id !== null && current.operation_id !== operation.id)
|
|
26579
26591
|
throw new ResponseContractError();
|
|
26580
26592
|
if (!replay)
|
|
@@ -26593,7 +26605,7 @@ async function prepareLocalSourcePublication(input) {
|
|
|
26593
26605
|
const current = await readPending(scope);
|
|
26594
26606
|
if (current === null || current.operation_id !== null)
|
|
26595
26607
|
return;
|
|
26596
|
-
assertSameAttempt(current,
|
|
26608
|
+
assertSameAttempt(current, record9);
|
|
26597
26609
|
} catch (error2) {
|
|
26598
26610
|
if (error2 instanceof LocalSourcePublicationError && (error2.code === "source_publication_scope_mismatch" || error2.code === "source_publication_pending"))
|
|
26599
26611
|
return;
|
|
@@ -26796,12 +26808,12 @@ async function readRecord(path2) {
|
|
|
26796
26808
|
await handle?.close();
|
|
26797
26809
|
}
|
|
26798
26810
|
}
|
|
26799
|
-
async function writePending(
|
|
26800
|
-
const parent = join3(
|
|
26811
|
+
async function writePending(record9, create, completed = false) {
|
|
26812
|
+
const parent = join3(record9.directory, ".ohmyhost");
|
|
26801
26813
|
for (const directory of [
|
|
26802
26814
|
parent,
|
|
26803
|
-
|
|
26804
|
-
join3(
|
|
26815
|
+
record9.metadata_directory,
|
|
26816
|
+
join3(record9.metadata_directory, "publications")
|
|
26805
26817
|
]) {
|
|
26806
26818
|
try {
|
|
26807
26819
|
await fs2.mkdir(directory, { mode: 448 });
|
|
@@ -26812,10 +26824,10 @@ async function writePending(record8, create, completed = false) {
|
|
|
26812
26824
|
await checkedDirectory(directory);
|
|
26813
26825
|
await fs2.chmod(directory, 448);
|
|
26814
26826
|
}
|
|
26815
|
-
const target = completed ? completedPath(
|
|
26827
|
+
const target = completed ? completedPath(record9) : pendingPath(record9);
|
|
26816
26828
|
const temporary = create ? target : `${target}.${randomUUID()}.tmp`;
|
|
26817
26829
|
try {
|
|
26818
|
-
await fs2.writeFile(temporary, `${JSON.stringify(
|
|
26830
|
+
await fs2.writeFile(temporary, `${JSON.stringify(record9)}
|
|
26819
26831
|
`, { mode: 384, flag: "wx" });
|
|
26820
26832
|
if (!create)
|
|
26821
26833
|
await fs2.rename(temporary, target);
|
|
@@ -26945,7 +26957,7 @@ function exact2(value, keys) {
|
|
|
26945
26957
|
|
|
26946
26958
|
// packages/contracts/dist/credit-pricing.js
|
|
26947
26959
|
function assertOrganizationCreditUsage(value) {
|
|
26948
|
-
const
|
|
26960
|
+
const record9 = (input, keys) => {
|
|
26949
26961
|
if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).sort().join() !== keys.split(",").sort().join())
|
|
26950
26962
|
throw new TypeError("Invalid usage fields");
|
|
26951
26963
|
return input;
|
|
@@ -26953,30 +26965,30 @@ function assertOrganizationCreditUsage(value) {
|
|
|
26953
26965
|
const identifier3 = (input) => typeof input === "string" && /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u.test(input);
|
|
26954
26966
|
const amount = (input) => typeof input === "string" && /^(0|[1-9][0-9]{0,37})$/u.test(input);
|
|
26955
26967
|
const instant2 = (input) => typeof input === "string" && Number.isFinite(Date.parse(input)) && new Date(input).toISOString() === input;
|
|
26956
|
-
const report =
|
|
26968
|
+
const report = record9(value, "organization_id,as_of,unit,period,from,projects,days");
|
|
26957
26969
|
if (!identifier3(report["organization_id"]) || !instant2(report["as_of"]) || !instant2(report["from"]) || report["unit"] !== "microcredits" || typeof report["period"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(report["period"]) || !Array.isArray(report["projects"]) || report["projects"].length > 1e3 || !Array.isArray(report["days"]) || report["days"].length > 15)
|
|
26958
26970
|
throw new TypeError("Invalid usage report");
|
|
26959
26971
|
let previous = "";
|
|
26960
26972
|
for (const input of report["projects"]) {
|
|
26961
|
-
const project =
|
|
26973
|
+
const project = record9(input, "project_id,used_micros");
|
|
26962
26974
|
if (!identifier3(project["project_id"]) || String(project["project_id"]) <= previous || !amount(project["used_micros"]))
|
|
26963
26975
|
throw new TypeError("Invalid usage project");
|
|
26964
26976
|
previous = String(project["project_id"]);
|
|
26965
26977
|
}
|
|
26966
26978
|
let previousDay = "";
|
|
26967
26979
|
for (const input of report["days"]) {
|
|
26968
|
-
const day =
|
|
26980
|
+
const day = record9(input, "day,projects");
|
|
26969
26981
|
if (typeof day["day"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/u.test(day["day"]) || day["day"] <= previousDay || !Array.isArray(day["projects"]) || day["projects"].length > 1e3)
|
|
26970
26982
|
throw new TypeError("Invalid usage day");
|
|
26971
26983
|
previousDay = day["day"];
|
|
26972
26984
|
previous = "";
|
|
26973
26985
|
for (const projectInput of day["projects"]) {
|
|
26974
|
-
const project =
|
|
26986
|
+
const project = record9(projectInput, "project_id,meters");
|
|
26975
26987
|
if (!identifier3(project["project_id"]) || String(project["project_id"]) <= previous || !Array.isArray(project["meters"]) || project["meters"].length > 1e3)
|
|
26976
26988
|
throw new TypeError("Invalid usage project");
|
|
26977
26989
|
previous = String(project["project_id"]);
|
|
26978
26990
|
for (const meterInput of project["meters"]) {
|
|
26979
|
-
const meter =
|
|
26991
|
+
const meter = record9(meterInput, "environment_id,meter,unit,rate_card_id,quantity,charged_micros");
|
|
26980
26992
|
if (meter["environment_id"] !== null && !identifier3(meter["environment_id"]))
|
|
26981
26993
|
throw new TypeError("Invalid usage environment");
|
|
26982
26994
|
for (const key of ["meter", "unit", "rate_card_id"])
|
|
@@ -27401,7 +27413,7 @@ function exact4(value, keys) {
|
|
|
27401
27413
|
// apps/product-cli/package.json
|
|
27402
27414
|
var package_default2 = {
|
|
27403
27415
|
name: "@ohmyhost/product-cli",
|
|
27404
|
-
version: "0.1.
|
|
27416
|
+
version: "0.1.46",
|
|
27405
27417
|
private: true,
|
|
27406
27418
|
ohmyhost: {
|
|
27407
27419
|
deployment: "production",
|
|
@@ -27850,6 +27862,170 @@ function expectPositiveInteger(value, field, options = {}) {
|
|
|
27850
27862
|
return value;
|
|
27851
27863
|
}
|
|
27852
27864
|
|
|
27865
|
+
// packages/contracts/dist/database-tables.js
|
|
27866
|
+
var DATABASE_TABLE_COLUMN_TYPES = [
|
|
27867
|
+
"text",
|
|
27868
|
+
"integer",
|
|
27869
|
+
"bigint",
|
|
27870
|
+
"boolean",
|
|
27871
|
+
"numeric",
|
|
27872
|
+
"double precision",
|
|
27873
|
+
"timestamptz",
|
|
27874
|
+
"date",
|
|
27875
|
+
"uuid",
|
|
27876
|
+
"jsonb"
|
|
27877
|
+
];
|
|
27878
|
+
var DATABASE_TABLE_DEFAULTS = ["now", "uuid"];
|
|
27879
|
+
var DATABASE_TABLE_MAX_COLUMNS = 64;
|
|
27880
|
+
var DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS = 8;
|
|
27881
|
+
var DATABASE_TABLE_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/u;
|
|
27882
|
+
var RESERVED_WORDS = /* @__PURE__ */ new Set([
|
|
27883
|
+
"all",
|
|
27884
|
+
"analyse",
|
|
27885
|
+
"analyze",
|
|
27886
|
+
"and",
|
|
27887
|
+
"any",
|
|
27888
|
+
"array",
|
|
27889
|
+
"as",
|
|
27890
|
+
"asc",
|
|
27891
|
+
"asymmetric",
|
|
27892
|
+
"both",
|
|
27893
|
+
"case",
|
|
27894
|
+
"cast",
|
|
27895
|
+
"check",
|
|
27896
|
+
"collate",
|
|
27897
|
+
"column",
|
|
27898
|
+
"constraint",
|
|
27899
|
+
"create",
|
|
27900
|
+
"current_catalog",
|
|
27901
|
+
"current_date",
|
|
27902
|
+
"current_role",
|
|
27903
|
+
"current_time",
|
|
27904
|
+
"current_timestamp",
|
|
27905
|
+
"current_user",
|
|
27906
|
+
"default",
|
|
27907
|
+
"deferrable",
|
|
27908
|
+
"desc",
|
|
27909
|
+
"distinct",
|
|
27910
|
+
"do",
|
|
27911
|
+
"else",
|
|
27912
|
+
"end",
|
|
27913
|
+
"except",
|
|
27914
|
+
"false",
|
|
27915
|
+
"fetch",
|
|
27916
|
+
"for",
|
|
27917
|
+
"foreign",
|
|
27918
|
+
"from",
|
|
27919
|
+
"grant",
|
|
27920
|
+
"group",
|
|
27921
|
+
"having",
|
|
27922
|
+
"in",
|
|
27923
|
+
"initially",
|
|
27924
|
+
"intersect",
|
|
27925
|
+
"into",
|
|
27926
|
+
"lateral",
|
|
27927
|
+
"leading",
|
|
27928
|
+
"limit",
|
|
27929
|
+
"localtime",
|
|
27930
|
+
"localtimestamp",
|
|
27931
|
+
"not",
|
|
27932
|
+
"null",
|
|
27933
|
+
"offset",
|
|
27934
|
+
"on",
|
|
27935
|
+
"only",
|
|
27936
|
+
"or",
|
|
27937
|
+
"order",
|
|
27938
|
+
"placing",
|
|
27939
|
+
"primary",
|
|
27940
|
+
"references",
|
|
27941
|
+
"returning",
|
|
27942
|
+
"select",
|
|
27943
|
+
"session_user",
|
|
27944
|
+
"some",
|
|
27945
|
+
"symmetric",
|
|
27946
|
+
"table",
|
|
27947
|
+
"then",
|
|
27948
|
+
"to",
|
|
27949
|
+
"trailing",
|
|
27950
|
+
"true",
|
|
27951
|
+
"union",
|
|
27952
|
+
"unique",
|
|
27953
|
+
"user",
|
|
27954
|
+
"using",
|
|
27955
|
+
"variadic",
|
|
27956
|
+
"when",
|
|
27957
|
+
"where",
|
|
27958
|
+
"window",
|
|
27959
|
+
"with"
|
|
27960
|
+
]);
|
|
27961
|
+
function isDatabaseTableIdentifier(value) {
|
|
27962
|
+
return typeof value === "string" && DATABASE_TABLE_IDENTIFIER_PATTERN.test(value) && !value.startsWith("pg_") && !RESERVED_WORDS.has(value);
|
|
27963
|
+
}
|
|
27964
|
+
function parseDatabaseTableCreateRequest(value) {
|
|
27965
|
+
if (!record7(value) || !onlyKeys(value, ["table", "columns", "primaryKey"]) || !isDatabaseTableIdentifier(value["table"]) || !Array.isArray(value["columns"]) || value["columns"].length < 1 || value["columns"].length > DATABASE_TABLE_MAX_COLUMNS)
|
|
27966
|
+
throw new TypeError("Invalid database table request");
|
|
27967
|
+
const inputs = value["columns"].map(parseColumn);
|
|
27968
|
+
const names = inputs.map((column) => column.name);
|
|
27969
|
+
if (new Set(names).size !== names.length || inputs.filter((column) => column.identity).length > 1)
|
|
27970
|
+
throw new TypeError("Invalid database table request");
|
|
27971
|
+
const primaryKey = parsePrimaryKey(value["primaryKey"], names);
|
|
27972
|
+
return {
|
|
27973
|
+
table: value["table"],
|
|
27974
|
+
columns: inputs.map((column) => completeColumn(column, primaryKey.includes(column.name))),
|
|
27975
|
+
primaryKey
|
|
27976
|
+
};
|
|
27977
|
+
}
|
|
27978
|
+
function parseColumn(value) {
|
|
27979
|
+
if (!record7(value) || !onlyKeys(value, ["name", "type", "nullable", "identity", "default"]) || !isDatabaseTableIdentifier(value["name"]) || !oneOf2(DATABASE_TABLE_COLUMN_TYPES, value["type"]) || value["nullable"] !== void 0 && typeof value["nullable"] !== "boolean" || value["identity"] !== void 0 && typeof value["identity"] !== "boolean" || value["default"] !== void 0 && !oneOf2(DATABASE_TABLE_DEFAULTS, value["default"]))
|
|
27980
|
+
throw new TypeError("Invalid database table request");
|
|
27981
|
+
const type = value["type"];
|
|
27982
|
+
const identity = value["identity"] === true;
|
|
27983
|
+
const defaultValue = value["default"] ?? null;
|
|
27984
|
+
if (identity && type !== "integer" && type !== "bigint")
|
|
27985
|
+
throw new TypeError("Invalid database table request");
|
|
27986
|
+
if (identity && defaultValue !== null)
|
|
27987
|
+
throw new TypeError("Invalid database table request");
|
|
27988
|
+
if (defaultValue === "now" && type !== "timestamptz")
|
|
27989
|
+
throw new TypeError("Invalid database table request");
|
|
27990
|
+
if (defaultValue === "uuid" && type !== "uuid")
|
|
27991
|
+
throw new TypeError("Invalid database table request");
|
|
27992
|
+
return {
|
|
27993
|
+
name: value["name"],
|
|
27994
|
+
type,
|
|
27995
|
+
nullable: value["nullable"],
|
|
27996
|
+
identity,
|
|
27997
|
+
default: defaultValue
|
|
27998
|
+
};
|
|
27999
|
+
}
|
|
28000
|
+
function parsePrimaryKey(value, names) {
|
|
28001
|
+
if (value === void 0)
|
|
28002
|
+
return [];
|
|
28003
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS || new Set(value).size !== value.length || !value.every((name) => typeof name === "string" && names.includes(name)))
|
|
28004
|
+
throw new TypeError("Invalid database table request");
|
|
28005
|
+
return value;
|
|
28006
|
+
}
|
|
28007
|
+
function completeColumn(column, keyed) {
|
|
28008
|
+
const required = column.identity || keyed;
|
|
28009
|
+
if (required && column.nullable === true)
|
|
28010
|
+
throw new TypeError("Invalid database table request");
|
|
28011
|
+
return {
|
|
28012
|
+
name: column.name,
|
|
28013
|
+
type: column.type,
|
|
28014
|
+
nullable: required ? false : column.nullable ?? true,
|
|
28015
|
+
identity: column.identity,
|
|
28016
|
+
default: column.default
|
|
28017
|
+
};
|
|
28018
|
+
}
|
|
28019
|
+
function oneOf2(allowed, value) {
|
|
28020
|
+
return typeof value === "string" && allowed.includes(value);
|
|
28021
|
+
}
|
|
28022
|
+
function record7(value) {
|
|
28023
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28024
|
+
}
|
|
28025
|
+
function onlyKeys(value, allowed) {
|
|
28026
|
+
return Object.keys(value).every((key) => allowed.includes(key));
|
|
28027
|
+
}
|
|
28028
|
+
|
|
27853
28029
|
// packages/workos-auth-contracts/dist/user-api-keys.js
|
|
27854
28030
|
var WORKOS_USER_API_KEY_PATTERN = /^sk_[A-Za-z0-9_-]{20,128}$/u;
|
|
27855
28031
|
|
|
@@ -28518,6 +28694,7 @@ var HELP_USAGE = Object.freeze({
|
|
|
28518
28694
|
"database watch create": "ohmyhost database watch create --project ULID --environment dev|prod --table NAME [--schema public] --columns COL[,COL] [--operations insert,update,delete] --idempotency-key KEY --yes --json (publishes only the listed columns, at most 32, of each row change as the event type data.<topic> printed in this answer; the table must exist as an ordinary table of the application; a sleeping database wakes; next, subscribe with 'ohmyhost database webhook create ... --event-types data.<topic>')",
|
|
28519
28695
|
"database watch list": "ohmyhost database watch list --project ULID [--environment dev|prod] --json (dev when omitted; a sleeping database wakes)",
|
|
28520
28696
|
"database watch delete": "ohmyhost database watch delete --project ULID --environment dev|prod --watch ID --idempotency-key KEY --yes --json",
|
|
28697
|
+
"database table create": "ohmyhost database table create --project ULID --environment dev|prod --table NAME --columns-file PATH [--primary-key COL[,COL]] --idempotency-key KEY --yes --json (the table is created in the public schema as the migration role, with the same access as migration tables, so a database watch can attach later; the columns file is a UTF-8 JSON array of 1 to 64 column objects, at most 64 KiB, each with name, type and optional nullable, identity and default; types: text, integer, bigint, boolean, numeric, double precision, timestamptz, date, uuid, jsonb; identity needs integer or bigint; default now needs timestamptz and default uuid needs uuid; identical repeats answer created false; at most 100 tables, 64 columns per table)",
|
|
28521
28698
|
"database webhook create": "ohmyhost database webhook create --project ULID --environment dev|prod --url HTTPS_URL --event-types TYPE[,TYPE] [--headers-file PATH] --idempotency-key KEY --yes --json (the signing secret is shown once in this answer; types: database.created, database.ready, database.woke, database.slept, database.suspended, database.resized, database.deleted, data.<topic> for the rows of one watched table printed by database watch create, or data.* for every watched table; a bare * is not accepted and does not include data events; the headers file is a UTF-8 JSON object of at most 8 KiB)",
|
|
28522
28699
|
"database webhook list": "ohmyhost database webhook list --project ULID [--environment dev|prod] --json (dev when omitted; the secret is never listed)",
|
|
28523
28700
|
"database webhook get": "ohmyhost database webhook get --project ULID [--environment dev|prod] --webhook ID --json",
|
|
@@ -28660,12 +28837,12 @@ function buildClientParams(args, fields) {
|
|
|
28660
28837
|
};
|
|
28661
28838
|
const map = buildKeyMap(fields);
|
|
28662
28839
|
function writeSlot(slot, key, value) {
|
|
28663
|
-
let
|
|
28664
|
-
if (
|
|
28665
|
-
|
|
28666
|
-
params[slot] =
|
|
28840
|
+
let record9 = params[slot];
|
|
28841
|
+
if (record9 === void 0) {
|
|
28842
|
+
record9 = /* @__PURE__ */ Object.create(null);
|
|
28843
|
+
params[slot] = record9;
|
|
28667
28844
|
}
|
|
28668
|
-
|
|
28845
|
+
record9[key] = value;
|
|
28669
28846
|
}
|
|
28670
28847
|
let config;
|
|
28671
28848
|
for (const [index, arg] of args.entries()) {
|
|
@@ -31312,6 +31489,30 @@ var revokeProjectDatabaseAccess = (parameters, options) => {
|
|
|
31312
31489
|
...params
|
|
31313
31490
|
});
|
|
31314
31491
|
};
|
|
31492
|
+
var createProjectDatabaseTable = (parameters, options) => {
|
|
31493
|
+
const params = buildClientParams([parameters], [
|
|
31494
|
+
{
|
|
31495
|
+
args: [
|
|
31496
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
31497
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
31498
|
+
{ in: "path", key: "project_id" },
|
|
31499
|
+
{ key: "databaseTableCreateRequest", map: "body" }
|
|
31500
|
+
]
|
|
31501
|
+
}
|
|
31502
|
+
]);
|
|
31503
|
+
return (options?.client ?? client).post({
|
|
31504
|
+
responseStyle: "data",
|
|
31505
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
31506
|
+
url: "/v1/projects/{project_id}/database/tables",
|
|
31507
|
+
...options,
|
|
31508
|
+
...params,
|
|
31509
|
+
headers: {
|
|
31510
|
+
"Content-Type": "application/json",
|
|
31511
|
+
...options?.headers,
|
|
31512
|
+
...params.headers
|
|
31513
|
+
}
|
|
31514
|
+
});
|
|
31515
|
+
};
|
|
31315
31516
|
var listProjectDatabaseWatches = (parameters, options) => {
|
|
31316
31517
|
const params = buildClientParams([parameters], [
|
|
31317
31518
|
{
|
|
@@ -32779,7 +32980,24 @@ function checkedResponse(kind, value) {
|
|
|
32779
32980
|
// apps/product-cli/dist/product-api.js
|
|
32780
32981
|
var WEBHOOK_SCOPE_MISMATCH = "Webhook response scope mismatch";
|
|
32781
32982
|
var WATCH_SCOPE_MISMATCH = "Watch response scope mismatch";
|
|
32983
|
+
var TABLE_SCOPE_MISMATCH = "Table response scope mismatch";
|
|
32782
32984
|
var SCHEDULE_SCOPE_MISMATCH = "Schedule response scope mismatch";
|
|
32985
|
+
function assertDatabaseTableAnswer(value) {
|
|
32986
|
+
const table = isRecordValue(value) ? value["table"] : void 0;
|
|
32987
|
+
const columns = isRecordValue(table) ? table["columns"] : void 0;
|
|
32988
|
+
const primaryKey = isRecordValue(table) ? table["primary_key"] : void 0;
|
|
32989
|
+
if (!isRecordValue(table) || !hasExactKeys(table, ["environment", "schema", "table", "columns", "primary_key", "created"]) || table["environment"] !== "dev" && table["environment"] !== "prod" || table["schema"] !== "public" || !isDatabaseTableIdentifier(table["table"]) || typeof table["created"] !== "boolean" || !Array.isArray(columns) || columns.length < 1 || !columns.every(isDatabaseTableAnswerColumn) || !Array.isArray(primaryKey) || !primaryKey.every((name) => columns.some((column) => column["name"] === name)))
|
|
32990
|
+
throw new TypeError("Invalid database table answer");
|
|
32991
|
+
}
|
|
32992
|
+
function isDatabaseTableAnswerColumn(value) {
|
|
32993
|
+
return isRecordValue(value) && hasExactKeys(value, ["name", "type", "nullable", "identity", "default"]) && isDatabaseTableIdentifier(value["name"]) && DATABASE_TABLE_COLUMN_TYPES.includes(value["type"]) && typeof value["nullable"] === "boolean" && typeof value["identity"] === "boolean" && (value["default"] === null || DATABASE_TABLE_DEFAULTS.includes(value["default"]));
|
|
32994
|
+
}
|
|
32995
|
+
function isRecordValue(value) {
|
|
32996
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32997
|
+
}
|
|
32998
|
+
function hasExactKeys(value, keys) {
|
|
32999
|
+
return Object.keys(value).sort().join(",") === [...keys].sort().join(",");
|
|
33000
|
+
}
|
|
32783
33001
|
var GeneratedSdkProductApi = class {
|
|
32784
33002
|
#client;
|
|
32785
33003
|
managedSource;
|
|
@@ -33012,6 +33230,22 @@ var GeneratedSdkProductApi = class {
|
|
|
33012
33230
|
throw new TypeError(WATCH_SCOPE_MISMATCH);
|
|
33013
33231
|
return value;
|
|
33014
33232
|
}
|
|
33233
|
+
async createProjectDatabaseTable(input) {
|
|
33234
|
+
const value = await createProjectDatabaseTable({
|
|
33235
|
+
project_id: input.projectId,
|
|
33236
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
33237
|
+
databaseTableCreateRequest: {
|
|
33238
|
+
environment: input.environment,
|
|
33239
|
+
table: input.request.table,
|
|
33240
|
+
columns: [...input.request.columns],
|
|
33241
|
+
...input.request.primaryKey.length === 0 ? {} : { primary_key: [...input.request.primaryKey] }
|
|
33242
|
+
}
|
|
33243
|
+
}, { client: this.#client });
|
|
33244
|
+
assertDatabaseTableAnswer(value);
|
|
33245
|
+
if (value.table.environment !== input.environment || value.table.table !== input.request.table)
|
|
33246
|
+
throw new TypeError(TABLE_SCOPE_MISMATCH);
|
|
33247
|
+
return value;
|
|
33248
|
+
}
|
|
33015
33249
|
/** The signing secret exists only in this answer; the CLI prints it once and stores nothing. */
|
|
33016
33250
|
async createProjectDatabaseWebhook(input) {
|
|
33017
33251
|
const value = await createProjectDatabaseWebhook({
|
|
@@ -34312,6 +34546,21 @@ var GeneratedSdkLocalMcpClient = class {
|
|
|
34312
34546
|
requireScope(value.environment === input.environment && value.table === input.table && value.schema === (input.schema ?? DATABASE_WATCH_DEFAULT_SCHEMA));
|
|
34313
34547
|
return value;
|
|
34314
34548
|
}
|
|
34549
|
+
async createDatabaseTable(input) {
|
|
34550
|
+
const value = await createProjectDatabaseTable({
|
|
34551
|
+
project_id: input.projectId,
|
|
34552
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
34553
|
+
databaseTableCreateRequest: {
|
|
34554
|
+
environment: input.environment,
|
|
34555
|
+
table: input.table,
|
|
34556
|
+
columns: [...input.columns],
|
|
34557
|
+
...input.primaryKey === void 0 || input.primaryKey.length === 0 ? {} : { primary_key: [...input.primaryKey] }
|
|
34558
|
+
}
|
|
34559
|
+
}, { client: this.#client });
|
|
34560
|
+
assertDatabaseTableAnswer(value);
|
|
34561
|
+
requireScope(value.table.environment === input.environment && value.table.table === input.table);
|
|
34562
|
+
return value;
|
|
34563
|
+
}
|
|
34315
34564
|
async deleteDatabaseWatch(input) {
|
|
34316
34565
|
const value = await deleteProjectDatabaseWatch({
|
|
34317
34566
|
project_id: input.projectId,
|
|
@@ -34672,13 +34921,13 @@ function normalizeMcpSourceChanges(value) {
|
|
|
34672
34921
|
}
|
|
34673
34922
|
}
|
|
34674
34923
|
function normalizeSourceChanges(value) {
|
|
34675
|
-
const body =
|
|
34924
|
+
const body = record8(value);
|
|
34676
34925
|
const changes = body["changes"];
|
|
34677
34926
|
if (!Array.isArray(changes) || changes.length < 1 || changes.length > MANAGED_SOURCE_LIMITS.files)
|
|
34678
34927
|
invalid7();
|
|
34679
34928
|
let textBytes = 0;
|
|
34680
34929
|
const normalized = changes.map((change) => {
|
|
34681
|
-
const entry =
|
|
34930
|
+
const entry = record8(change);
|
|
34682
34931
|
const hasText = Object.hasOwn(entry, "content_text");
|
|
34683
34932
|
if (hasText === Object.hasOwn(entry, "content_base64"))
|
|
34684
34933
|
invalid7();
|
|
@@ -34737,7 +34986,7 @@ function encodeBase64(bytes) {
|
|
|
34737
34986
|
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
|
|
34738
34987
|
return btoa(binary);
|
|
34739
34988
|
}
|
|
34740
|
-
function
|
|
34989
|
+
function record8(value) {
|
|
34741
34990
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
34742
34991
|
invalid7();
|
|
34743
34992
|
return value;
|
|
@@ -34753,6 +35002,7 @@ var databaseWebhookId = external_exports.string().regex(/^whk_[a-z0-9]{20}$/u);
|
|
|
34753
35002
|
var databaseWatchId = external_exports.string().regex(/^pgcf_watch_[0-9a-f]{8}$/u);
|
|
34754
35003
|
var databaseIdentifier = external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,62}$/u);
|
|
34755
35004
|
var databaseDeliveryId = external_exports.string().regex(/^dlv_[0-9a-f]{20}$/u);
|
|
35005
|
+
var databaseTableIdentifier = external_exports.string().refine(isDatabaseTableIdentifier);
|
|
34756
35006
|
var databaseScheduleName = external_exports.string().regex(/^[a-z][a-z0-9_-]{0,62}$/u);
|
|
34757
35007
|
var profileName = external_exports.string().regex(/^[a-z0-9][a-z0-9_-]{0,62}$/u).optional().describe("Saved login to act as (profile_list shows them). Needed only when several logins could run this call; OHMYHOST_PROFILE of this server must match it.");
|
|
34758
35008
|
var idempotencyKey = external_exports.string().min(1).max(128);
|
|
@@ -35037,6 +35287,35 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
35037
35287
|
watchId: input.watch_id,
|
|
35038
35288
|
idempotencyKey: input.idempotency_key
|
|
35039
35289
|
}), destructiveAnnotations());
|
|
35290
|
+
registerProductTool(server, dependencies, "database_table_create", "Create one ordinary table in the public schema of a Dev or Prod database, as the migration role with the same access as migration tables, so a database_watch_create can attach later. Each column has a lower-case name, a type (text, integer, bigint, boolean, numeric, double precision, timestamptz, date, uuid or jsonb) and optional nullable, identity (integer or bigint only) and default (now for timestamptz, uuid for uuid); at most 64 columns, 8 primary-key columns and 100 tables per database. An identical repeat answers created: false; a table of the same name with another definition is refused with database_table_conflict. Tables created this way are not in the repository's migration files: record them in project notes and add a migration when the source should reproduce the database. Requires confirmed: true and an idempotency key. Refused with project_budget_exceeded while the Stop budget is reached.", external_exports.object({
|
|
35291
|
+
project_id: identifier2,
|
|
35292
|
+
environment: databaseEnvironment,
|
|
35293
|
+
table: databaseTableIdentifier,
|
|
35294
|
+
columns: external_exports.array(external_exports.object({
|
|
35295
|
+
name: databaseTableIdentifier,
|
|
35296
|
+
type: external_exports.enum(DATABASE_TABLE_COLUMN_TYPES),
|
|
35297
|
+
nullable: external_exports.boolean().optional(),
|
|
35298
|
+
identity: external_exports.boolean().optional(),
|
|
35299
|
+
default: external_exports.enum(DATABASE_TABLE_DEFAULTS).optional()
|
|
35300
|
+
})).min(1).max(DATABASE_TABLE_MAX_COLUMNS),
|
|
35301
|
+
primary_key: external_exports.array(databaseTableIdentifier).min(1).max(DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS).optional(),
|
|
35302
|
+
idempotency_key: idempotencyKey,
|
|
35303
|
+
confirmed: external_exports.literal(true)
|
|
35304
|
+
}), (client2, input) => {
|
|
35305
|
+
const request = parseDatabaseTableCreateRequest({
|
|
35306
|
+
table: input.table,
|
|
35307
|
+
columns: input.columns,
|
|
35308
|
+
...input.primary_key === void 0 ? {} : { primaryKey: input.primary_key }
|
|
35309
|
+
});
|
|
35310
|
+
return client2.createDatabaseTable({
|
|
35311
|
+
projectId: input.project_id,
|
|
35312
|
+
environment: input.environment,
|
|
35313
|
+
table: request.table,
|
|
35314
|
+
columns: input.columns,
|
|
35315
|
+
...request.primaryKey.length === 0 ? {} : { primaryKey: request.primaryKey },
|
|
35316
|
+
idempotencyKey: input.idempotency_key
|
|
35317
|
+
});
|
|
35318
|
+
}, mutationAnnotations());
|
|
35040
35319
|
registerProductTool(server, dependencies, "database_webhook_list", "List this project's database webhooks of one Dev or Prod environment (dev when omitted), without signing secrets. Each webhook lists its event types and header names only.", external_exports.object({ project_id: identifier2, environment: databaseEnvironment.optional() }), (client2, input) => client2.listDatabaseWebhooks({
|
|
35041
35320
|
projectId: input.project_id,
|
|
35042
35321
|
...input.environment === void 0 ? {} : { environment: input.environment }
|
package/package.json
CHANGED
|
@@ -119,6 +119,7 @@ import {
|
|
|
119
119
|
createProjectDatabaseWebhook,
|
|
120
120
|
listProjectDatabaseWebhooks,
|
|
121
121
|
deleteProjectDatabaseWebhook,
|
|
122
|
+
createProjectDatabaseTable,
|
|
122
123
|
createProjectDatabaseWatch,
|
|
123
124
|
listProjectDatabaseWatches,
|
|
124
125
|
deleteProjectDatabaseWatch,
|
|
@@ -184,6 +185,8 @@ import {
|
|
|
184
185
|
type LocalProfile,
|
|
185
186
|
type ProfileRegistry,
|
|
186
187
|
type WorkspaceSession,
|
|
188
|
+
type DatabaseTableAnswer,
|
|
189
|
+
assertDatabaseTableAnswer,
|
|
187
190
|
} from "@ohmyhost/product-cli";
|
|
188
191
|
|
|
189
192
|
export class OperationEventsUnavailableError extends Error {
|
|
@@ -893,6 +896,30 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
893
896
|
);
|
|
894
897
|
return value;
|
|
895
898
|
}
|
|
899
|
+
public async createDatabaseTable(
|
|
900
|
+
input: Parameters<LocalMcpProductClient["createDatabaseTable"]>[0],
|
|
901
|
+
): Promise<DatabaseTableAnswer> {
|
|
902
|
+
const value = await createProjectDatabaseTable(
|
|
903
|
+
{
|
|
904
|
+
project_id: input.projectId,
|
|
905
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
906
|
+
databaseTableCreateRequest: {
|
|
907
|
+
environment: input.environment,
|
|
908
|
+
table: input.table,
|
|
909
|
+
columns: [...input.columns],
|
|
910
|
+
...(input.primaryKey === undefined || input.primaryKey.length === 0
|
|
911
|
+
? {}
|
|
912
|
+
: { primary_key: [...input.primaryKey] }),
|
|
913
|
+
},
|
|
914
|
+
},
|
|
915
|
+
{ client: this.#client },
|
|
916
|
+
);
|
|
917
|
+
assertDatabaseTableAnswer(value);
|
|
918
|
+
requireScope(
|
|
919
|
+
value.table.environment === input.environment && value.table.table === input.table,
|
|
920
|
+
);
|
|
921
|
+
return value;
|
|
922
|
+
}
|
|
896
923
|
public async deleteDatabaseWatch(
|
|
897
924
|
input: Parameters<LocalMcpProductClient["deleteDatabaseWatch"]>[0],
|
|
898
925
|
) {
|