@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
package/dist/index.js
CHANGED
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-AH764FGJ.js";
|
|
34
34
|
|
|
35
35
|
// node_modules/.pnpm/ignore@7.0.12/node_modules/ignore/index.js
|
|
36
36
|
var require_ignore = __commonJS({
|
|
@@ -24160,8 +24160,8 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
24160
24160
|
from: "framework",
|
|
24161
24161
|
text: {
|
|
24162
24162
|
nextjs: "runtime.mode: edge",
|
|
24163
|
-
"vite-static": "runtime.mode: edge with src/ohmyhost/companion.ts when database, auth, mail, storage or functions.crons is set, and static otherwise",
|
|
24164
|
-
"tanstack-start": "runtime.mode: edge, or static without functions.crons and
|
|
24163
|
+
"vite-static": "runtime.mode: edge with src/ohmyhost/companion.ts when database, auth, mail, ai, storage or functions.crons is set, and static otherwise",
|
|
24164
|
+
"tanstack-start": "runtime.mode: edge, or static without functions.crons, storage and ai",
|
|
24165
24165
|
astro: "runtime.mode: static for prerendered sites, or edge with the Cloudflare adapter"
|
|
24166
24166
|
}
|
|
24167
24167
|
}
|
|
@@ -24222,7 +24222,7 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
|
|
|
24222
24222
|
},
|
|
24223
24223
|
companion_entry_required: {
|
|
24224
24224
|
paths: ["module"],
|
|
24225
|
-
template: '"{{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.'
|
|
24225
|
+
template: '"{{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.'
|
|
24226
24226
|
},
|
|
24227
24227
|
worker_module_required: {
|
|
24228
24228
|
paths: ["module"],
|
|
@@ -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.47",
|
|
27405
27417
|
private: true,
|
|
27406
27418
|
ohmyhost: {
|
|
27407
27419
|
deployment: "production",
|
|
@@ -27462,6 +27474,7 @@ var FIXED_PLATFORM_NAMES = /* @__PURE__ */ new Set([
|
|
|
27462
27474
|
var INSTALLED_PLATFORM_KEYS = /* @__PURE__ */ new Set([
|
|
27463
27475
|
"OHMYHOST_STORAGE_KEY",
|
|
27464
27476
|
"OHMYHOST_MAIL_KEY",
|
|
27477
|
+
"OHMYHOST_AI_KEY",
|
|
27465
27478
|
"BETTER_AUTH_SECRET"
|
|
27466
27479
|
]);
|
|
27467
27480
|
function isUserSecretName(value, action = "set") {
|
|
@@ -27850,6 +27863,170 @@ function expectPositiveInteger(value, field, options = {}) {
|
|
|
27850
27863
|
return value;
|
|
27851
27864
|
}
|
|
27852
27865
|
|
|
27866
|
+
// packages/contracts/dist/database-tables.js
|
|
27867
|
+
var DATABASE_TABLE_COLUMN_TYPES = [
|
|
27868
|
+
"text",
|
|
27869
|
+
"integer",
|
|
27870
|
+
"bigint",
|
|
27871
|
+
"boolean",
|
|
27872
|
+
"numeric",
|
|
27873
|
+
"double precision",
|
|
27874
|
+
"timestamptz",
|
|
27875
|
+
"date",
|
|
27876
|
+
"uuid",
|
|
27877
|
+
"jsonb"
|
|
27878
|
+
];
|
|
27879
|
+
var DATABASE_TABLE_DEFAULTS = ["now", "uuid"];
|
|
27880
|
+
var DATABASE_TABLE_MAX_COLUMNS = 64;
|
|
27881
|
+
var DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS = 8;
|
|
27882
|
+
var DATABASE_TABLE_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/u;
|
|
27883
|
+
var RESERVED_WORDS = /* @__PURE__ */ new Set([
|
|
27884
|
+
"all",
|
|
27885
|
+
"analyse",
|
|
27886
|
+
"analyze",
|
|
27887
|
+
"and",
|
|
27888
|
+
"any",
|
|
27889
|
+
"array",
|
|
27890
|
+
"as",
|
|
27891
|
+
"asc",
|
|
27892
|
+
"asymmetric",
|
|
27893
|
+
"both",
|
|
27894
|
+
"case",
|
|
27895
|
+
"cast",
|
|
27896
|
+
"check",
|
|
27897
|
+
"collate",
|
|
27898
|
+
"column",
|
|
27899
|
+
"constraint",
|
|
27900
|
+
"create",
|
|
27901
|
+
"current_catalog",
|
|
27902
|
+
"current_date",
|
|
27903
|
+
"current_role",
|
|
27904
|
+
"current_time",
|
|
27905
|
+
"current_timestamp",
|
|
27906
|
+
"current_user",
|
|
27907
|
+
"default",
|
|
27908
|
+
"deferrable",
|
|
27909
|
+
"desc",
|
|
27910
|
+
"distinct",
|
|
27911
|
+
"do",
|
|
27912
|
+
"else",
|
|
27913
|
+
"end",
|
|
27914
|
+
"except",
|
|
27915
|
+
"false",
|
|
27916
|
+
"fetch",
|
|
27917
|
+
"for",
|
|
27918
|
+
"foreign",
|
|
27919
|
+
"from",
|
|
27920
|
+
"grant",
|
|
27921
|
+
"group",
|
|
27922
|
+
"having",
|
|
27923
|
+
"in",
|
|
27924
|
+
"initially",
|
|
27925
|
+
"intersect",
|
|
27926
|
+
"into",
|
|
27927
|
+
"lateral",
|
|
27928
|
+
"leading",
|
|
27929
|
+
"limit",
|
|
27930
|
+
"localtime",
|
|
27931
|
+
"localtimestamp",
|
|
27932
|
+
"not",
|
|
27933
|
+
"null",
|
|
27934
|
+
"offset",
|
|
27935
|
+
"on",
|
|
27936
|
+
"only",
|
|
27937
|
+
"or",
|
|
27938
|
+
"order",
|
|
27939
|
+
"placing",
|
|
27940
|
+
"primary",
|
|
27941
|
+
"references",
|
|
27942
|
+
"returning",
|
|
27943
|
+
"select",
|
|
27944
|
+
"session_user",
|
|
27945
|
+
"some",
|
|
27946
|
+
"symmetric",
|
|
27947
|
+
"table",
|
|
27948
|
+
"then",
|
|
27949
|
+
"to",
|
|
27950
|
+
"trailing",
|
|
27951
|
+
"true",
|
|
27952
|
+
"union",
|
|
27953
|
+
"unique",
|
|
27954
|
+
"user",
|
|
27955
|
+
"using",
|
|
27956
|
+
"variadic",
|
|
27957
|
+
"when",
|
|
27958
|
+
"where",
|
|
27959
|
+
"window",
|
|
27960
|
+
"with"
|
|
27961
|
+
]);
|
|
27962
|
+
function isDatabaseTableIdentifier(value) {
|
|
27963
|
+
return typeof value === "string" && DATABASE_TABLE_IDENTIFIER_PATTERN.test(value) && !value.startsWith("pg_") && !RESERVED_WORDS.has(value);
|
|
27964
|
+
}
|
|
27965
|
+
function parseDatabaseTableCreateRequest(value) {
|
|
27966
|
+
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)
|
|
27967
|
+
throw new TypeError("Invalid database table request");
|
|
27968
|
+
const inputs = value["columns"].map(parseColumn);
|
|
27969
|
+
const names = inputs.map((column) => column.name);
|
|
27970
|
+
if (new Set(names).size !== names.length || inputs.filter((column) => column.identity).length > 1)
|
|
27971
|
+
throw new TypeError("Invalid database table request");
|
|
27972
|
+
const primaryKey = parsePrimaryKey(value["primaryKey"], names);
|
|
27973
|
+
return {
|
|
27974
|
+
table: value["table"],
|
|
27975
|
+
columns: inputs.map((column) => completeColumn(column, primaryKey.includes(column.name))),
|
|
27976
|
+
primaryKey
|
|
27977
|
+
};
|
|
27978
|
+
}
|
|
27979
|
+
function parseColumn(value) {
|
|
27980
|
+
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"]))
|
|
27981
|
+
throw new TypeError("Invalid database table request");
|
|
27982
|
+
const type = value["type"];
|
|
27983
|
+
const identity = value["identity"] === true;
|
|
27984
|
+
const defaultValue = value["default"] ?? null;
|
|
27985
|
+
if (identity && type !== "integer" && type !== "bigint")
|
|
27986
|
+
throw new TypeError("Invalid database table request");
|
|
27987
|
+
if (identity && defaultValue !== null)
|
|
27988
|
+
throw new TypeError("Invalid database table request");
|
|
27989
|
+
if (defaultValue === "now" && type !== "timestamptz")
|
|
27990
|
+
throw new TypeError("Invalid database table request");
|
|
27991
|
+
if (defaultValue === "uuid" && type !== "uuid")
|
|
27992
|
+
throw new TypeError("Invalid database table request");
|
|
27993
|
+
return {
|
|
27994
|
+
name: value["name"],
|
|
27995
|
+
type,
|
|
27996
|
+
nullable: value["nullable"],
|
|
27997
|
+
identity,
|
|
27998
|
+
default: defaultValue
|
|
27999
|
+
};
|
|
28000
|
+
}
|
|
28001
|
+
function parsePrimaryKey(value, names) {
|
|
28002
|
+
if (value === void 0)
|
|
28003
|
+
return [];
|
|
28004
|
+
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)))
|
|
28005
|
+
throw new TypeError("Invalid database table request");
|
|
28006
|
+
return value;
|
|
28007
|
+
}
|
|
28008
|
+
function completeColumn(column, keyed) {
|
|
28009
|
+
const required = column.identity || keyed;
|
|
28010
|
+
if (required && column.nullable === true)
|
|
28011
|
+
throw new TypeError("Invalid database table request");
|
|
28012
|
+
return {
|
|
28013
|
+
name: column.name,
|
|
28014
|
+
type: column.type,
|
|
28015
|
+
nullable: required ? false : column.nullable ?? true,
|
|
28016
|
+
identity: column.identity,
|
|
28017
|
+
default: column.default
|
|
28018
|
+
};
|
|
28019
|
+
}
|
|
28020
|
+
function oneOf2(allowed, value) {
|
|
28021
|
+
return typeof value === "string" && allowed.includes(value);
|
|
28022
|
+
}
|
|
28023
|
+
function record7(value) {
|
|
28024
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28025
|
+
}
|
|
28026
|
+
function onlyKeys(value, allowed) {
|
|
28027
|
+
return Object.keys(value).every((key) => allowed.includes(key));
|
|
28028
|
+
}
|
|
28029
|
+
|
|
27853
28030
|
// packages/workos-auth-contracts/dist/user-api-keys.js
|
|
27854
28031
|
var WORKOS_USER_API_KEY_PATTERN = /^sk_[A-Za-z0-9_-]{20,128}$/u;
|
|
27855
28032
|
|
|
@@ -28518,6 +28695,7 @@ var HELP_USAGE = Object.freeze({
|
|
|
28518
28695
|
"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
28696
|
"database watch list": "ohmyhost database watch list --project ULID [--environment dev|prod] --json (dev when omitted; a sleeping database wakes)",
|
|
28520
28697
|
"database watch delete": "ohmyhost database watch delete --project ULID --environment dev|prod --watch ID --idempotency-key KEY --yes --json",
|
|
28698
|
+
"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
28699
|
"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
28700
|
"database webhook list": "ohmyhost database webhook list --project ULID [--environment dev|prod] --json (dev when omitted; the secret is never listed)",
|
|
28523
28701
|
"database webhook get": "ohmyhost database webhook get --project ULID [--environment dev|prod] --webhook ID --json",
|
|
@@ -28660,12 +28838,12 @@ function buildClientParams(args, fields) {
|
|
|
28660
28838
|
};
|
|
28661
28839
|
const map = buildKeyMap(fields);
|
|
28662
28840
|
function writeSlot(slot, key, value) {
|
|
28663
|
-
let
|
|
28664
|
-
if (
|
|
28665
|
-
|
|
28666
|
-
params[slot] =
|
|
28841
|
+
let record9 = params[slot];
|
|
28842
|
+
if (record9 === void 0) {
|
|
28843
|
+
record9 = /* @__PURE__ */ Object.create(null);
|
|
28844
|
+
params[slot] = record9;
|
|
28667
28845
|
}
|
|
28668
|
-
|
|
28846
|
+
record9[key] = value;
|
|
28669
28847
|
}
|
|
28670
28848
|
let config;
|
|
28671
28849
|
for (const [index, arg] of args.entries()) {
|
|
@@ -31312,6 +31490,30 @@ var revokeProjectDatabaseAccess = (parameters, options) => {
|
|
|
31312
31490
|
...params
|
|
31313
31491
|
});
|
|
31314
31492
|
};
|
|
31493
|
+
var createProjectDatabaseTable = (parameters, options) => {
|
|
31494
|
+
const params = buildClientParams([parameters], [
|
|
31495
|
+
{
|
|
31496
|
+
args: [
|
|
31497
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
31498
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
31499
|
+
{ in: "path", key: "project_id" },
|
|
31500
|
+
{ key: "databaseTableCreateRequest", map: "body" }
|
|
31501
|
+
]
|
|
31502
|
+
}
|
|
31503
|
+
]);
|
|
31504
|
+
return (options?.client ?? client).post({
|
|
31505
|
+
responseStyle: "data",
|
|
31506
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
31507
|
+
url: "/v1/projects/{project_id}/database/tables",
|
|
31508
|
+
...options,
|
|
31509
|
+
...params,
|
|
31510
|
+
headers: {
|
|
31511
|
+
"Content-Type": "application/json",
|
|
31512
|
+
...options?.headers,
|
|
31513
|
+
...params.headers
|
|
31514
|
+
}
|
|
31515
|
+
});
|
|
31516
|
+
};
|
|
31315
31517
|
var listProjectDatabaseWatches = (parameters, options) => {
|
|
31316
31518
|
const params = buildClientParams([parameters], [
|
|
31317
31519
|
{
|
|
@@ -32779,7 +32981,24 @@ function checkedResponse(kind, value) {
|
|
|
32779
32981
|
// apps/product-cli/dist/product-api.js
|
|
32780
32982
|
var WEBHOOK_SCOPE_MISMATCH = "Webhook response scope mismatch";
|
|
32781
32983
|
var WATCH_SCOPE_MISMATCH = "Watch response scope mismatch";
|
|
32984
|
+
var TABLE_SCOPE_MISMATCH = "Table response scope mismatch";
|
|
32782
32985
|
var SCHEDULE_SCOPE_MISMATCH = "Schedule response scope mismatch";
|
|
32986
|
+
function assertDatabaseTableAnswer(value) {
|
|
32987
|
+
const table = isRecordValue(value) ? value["table"] : void 0;
|
|
32988
|
+
const columns = isRecordValue(table) ? table["columns"] : void 0;
|
|
32989
|
+
const primaryKey = isRecordValue(table) ? table["primary_key"] : void 0;
|
|
32990
|
+
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)))
|
|
32991
|
+
throw new TypeError("Invalid database table answer");
|
|
32992
|
+
}
|
|
32993
|
+
function isDatabaseTableAnswerColumn(value) {
|
|
32994
|
+
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"]));
|
|
32995
|
+
}
|
|
32996
|
+
function isRecordValue(value) {
|
|
32997
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32998
|
+
}
|
|
32999
|
+
function hasExactKeys(value, keys) {
|
|
33000
|
+
return Object.keys(value).sort().join(",") === [...keys].sort().join(",");
|
|
33001
|
+
}
|
|
32783
33002
|
var GeneratedSdkProductApi = class {
|
|
32784
33003
|
#client;
|
|
32785
33004
|
managedSource;
|
|
@@ -33012,6 +33231,22 @@ var GeneratedSdkProductApi = class {
|
|
|
33012
33231
|
throw new TypeError(WATCH_SCOPE_MISMATCH);
|
|
33013
33232
|
return value;
|
|
33014
33233
|
}
|
|
33234
|
+
async createProjectDatabaseTable(input) {
|
|
33235
|
+
const value = await createProjectDatabaseTable({
|
|
33236
|
+
project_id: input.projectId,
|
|
33237
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
33238
|
+
databaseTableCreateRequest: {
|
|
33239
|
+
environment: input.environment,
|
|
33240
|
+
table: input.request.table,
|
|
33241
|
+
columns: [...input.request.columns],
|
|
33242
|
+
...input.request.primaryKey.length === 0 ? {} : { primary_key: [...input.request.primaryKey] }
|
|
33243
|
+
}
|
|
33244
|
+
}, { client: this.#client });
|
|
33245
|
+
assertDatabaseTableAnswer(value);
|
|
33246
|
+
if (value.table.environment !== input.environment || value.table.table !== input.request.table)
|
|
33247
|
+
throw new TypeError(TABLE_SCOPE_MISMATCH);
|
|
33248
|
+
return value;
|
|
33249
|
+
}
|
|
33015
33250
|
/** The signing secret exists only in this answer; the CLI prints it once and stores nothing. */
|
|
33016
33251
|
async createProjectDatabaseWebhook(input) {
|
|
33017
33252
|
const value = await createProjectDatabaseWebhook({
|
|
@@ -33419,6 +33654,7 @@ var MAIL_RUNTIME_BINDINGS = Object.freeze([
|
|
|
33419
33654
|
"OHMYHOST_MAIL_KEY",
|
|
33420
33655
|
"OHMYHOST_PROJECT_ID"
|
|
33421
33656
|
]);
|
|
33657
|
+
var AI_RUNTIME_BINDINGS = Object.freeze(["OHMYHOST_AI_BASE_URL", "OHMYHOST_AI_KEY"]);
|
|
33422
33658
|
var CUSTOMER_RUNTIME_SOURCE = `npm:@amerged/ohmyhost-runtime@${package_default2.version}`;
|
|
33423
33659
|
var PENDING_CHECKS = Object.freeze({
|
|
33424
33660
|
installed_version: "compatibility.frameworks lists a version range that no lockfile ohmyho.st reads (package-lock.json v2/v3 or pnpm-lock.yaml v6/v9) resolves. Planning admits it; after the frozen install, the build checks the installed version against the same security minimum.",
|
|
@@ -34312,6 +34548,21 @@ var GeneratedSdkLocalMcpClient = class {
|
|
|
34312
34548
|
requireScope(value.environment === input.environment && value.table === input.table && value.schema === (input.schema ?? DATABASE_WATCH_DEFAULT_SCHEMA));
|
|
34313
34549
|
return value;
|
|
34314
34550
|
}
|
|
34551
|
+
async createDatabaseTable(input) {
|
|
34552
|
+
const value = await createProjectDatabaseTable({
|
|
34553
|
+
project_id: input.projectId,
|
|
34554
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
34555
|
+
databaseTableCreateRequest: {
|
|
34556
|
+
environment: input.environment,
|
|
34557
|
+
table: input.table,
|
|
34558
|
+
columns: [...input.columns],
|
|
34559
|
+
...input.primaryKey === void 0 || input.primaryKey.length === 0 ? {} : { primary_key: [...input.primaryKey] }
|
|
34560
|
+
}
|
|
34561
|
+
}, { client: this.#client });
|
|
34562
|
+
assertDatabaseTableAnswer(value);
|
|
34563
|
+
requireScope(value.table.environment === input.environment && value.table.table === input.table);
|
|
34564
|
+
return value;
|
|
34565
|
+
}
|
|
34315
34566
|
async deleteDatabaseWatch(input) {
|
|
34316
34567
|
const value = await deleteProjectDatabaseWatch({
|
|
34317
34568
|
project_id: input.projectId,
|
|
@@ -34672,13 +34923,13 @@ function normalizeMcpSourceChanges(value) {
|
|
|
34672
34923
|
}
|
|
34673
34924
|
}
|
|
34674
34925
|
function normalizeSourceChanges(value) {
|
|
34675
|
-
const body =
|
|
34926
|
+
const body = record8(value);
|
|
34676
34927
|
const changes = body["changes"];
|
|
34677
34928
|
if (!Array.isArray(changes) || changes.length < 1 || changes.length > MANAGED_SOURCE_LIMITS.files)
|
|
34678
34929
|
invalid7();
|
|
34679
34930
|
let textBytes = 0;
|
|
34680
34931
|
const normalized = changes.map((change) => {
|
|
34681
|
-
const entry =
|
|
34932
|
+
const entry = record8(change);
|
|
34682
34933
|
const hasText = Object.hasOwn(entry, "content_text");
|
|
34683
34934
|
if (hasText === Object.hasOwn(entry, "content_base64"))
|
|
34684
34935
|
invalid7();
|
|
@@ -34737,7 +34988,7 @@ function encodeBase64(bytes) {
|
|
|
34737
34988
|
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
|
|
34738
34989
|
return btoa(binary);
|
|
34739
34990
|
}
|
|
34740
|
-
function
|
|
34991
|
+
function record8(value) {
|
|
34741
34992
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
34742
34993
|
invalid7();
|
|
34743
34994
|
return value;
|
|
@@ -34753,6 +35004,7 @@ var databaseWebhookId = external_exports.string().regex(/^whk_[a-z0-9]{20}$/u);
|
|
|
34753
35004
|
var databaseWatchId = external_exports.string().regex(/^pgcf_watch_[0-9a-f]{8}$/u);
|
|
34754
35005
|
var databaseIdentifier = external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,62}$/u);
|
|
34755
35006
|
var databaseDeliveryId = external_exports.string().regex(/^dlv_[0-9a-f]{20}$/u);
|
|
35007
|
+
var databaseTableIdentifier = external_exports.string().refine(isDatabaseTableIdentifier);
|
|
34756
35008
|
var databaseScheduleName = external_exports.string().regex(/^[a-z][a-z0-9_-]{0,62}$/u);
|
|
34757
35009
|
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
35010
|
var idempotencyKey = external_exports.string().min(1).max(128);
|
|
@@ -35037,6 +35289,35 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
35037
35289
|
watchId: input.watch_id,
|
|
35038
35290
|
idempotencyKey: input.idempotency_key
|
|
35039
35291
|
}), destructiveAnnotations());
|
|
35292
|
+
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({
|
|
35293
|
+
project_id: identifier2,
|
|
35294
|
+
environment: databaseEnvironment,
|
|
35295
|
+
table: databaseTableIdentifier,
|
|
35296
|
+
columns: external_exports.array(external_exports.object({
|
|
35297
|
+
name: databaseTableIdentifier,
|
|
35298
|
+
type: external_exports.enum(DATABASE_TABLE_COLUMN_TYPES),
|
|
35299
|
+
nullable: external_exports.boolean().optional(),
|
|
35300
|
+
identity: external_exports.boolean().optional(),
|
|
35301
|
+
default: external_exports.enum(DATABASE_TABLE_DEFAULTS).optional()
|
|
35302
|
+
})).min(1).max(DATABASE_TABLE_MAX_COLUMNS),
|
|
35303
|
+
primary_key: external_exports.array(databaseTableIdentifier).min(1).max(DATABASE_TABLE_MAX_PRIMARY_KEY_COLUMNS).optional(),
|
|
35304
|
+
idempotency_key: idempotencyKey,
|
|
35305
|
+
confirmed: external_exports.literal(true)
|
|
35306
|
+
}), (client2, input) => {
|
|
35307
|
+
const request = parseDatabaseTableCreateRequest({
|
|
35308
|
+
table: input.table,
|
|
35309
|
+
columns: input.columns,
|
|
35310
|
+
...input.primary_key === void 0 ? {} : { primaryKey: input.primary_key }
|
|
35311
|
+
});
|
|
35312
|
+
return client2.createDatabaseTable({
|
|
35313
|
+
projectId: input.project_id,
|
|
35314
|
+
environment: input.environment,
|
|
35315
|
+
table: request.table,
|
|
35316
|
+
columns: input.columns,
|
|
35317
|
+
...request.primaryKey.length === 0 ? {} : { primaryKey: request.primaryKey },
|
|
35318
|
+
idempotencyKey: input.idempotency_key
|
|
35319
|
+
});
|
|
35320
|
+
}, mutationAnnotations());
|
|
35040
35321
|
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
35322
|
projectId: input.project_id,
|
|
35042
35323
|
...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
|
) {
|