@amerged/ohmyhost-mcp 0.1.44 → 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.
@@ -30,7 +30,7 @@ import {
30
30
  serverIdentityOf,
31
31
  setNegotiatedProtocolVersion,
32
32
  validateEnvelopeMeta
33
- } from "./chunk-NUWAJ4TH.js";
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 record8 = value;
24297
- const code = Object.hasOwn(record8, "code") ? record8["code"] : void 0;
24298
- const path2 = Object.hasOwn(record8, "path") ? record8["path"] : void 0;
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(record8, name) ? record8[name] : void 0]);
24303
- if (Object.keys(record8).length !== fields.length + 2 || pathClassOf(definition, path2) === null || fields.some(([, grammar, field]) => !fieldMatches(grammar, field)))
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],
@@ -25572,6 +25572,48 @@ var PROBLEM_POLICY = {
25572
25572
  action: "The platform is still retrying this webhook delivery. Read the delivery in the delivery list; replay it only if it ends dead_lettered or the receiver needs the event again.",
25573
25573
  title: "Webhook delivery still pending"
25574
25574
  },
25575
+ database_watch_limit: {
25576
+ status: 409,
25577
+ retryable: false,
25578
+ action: "List the project's database watches for this environment and delete one you no longer need, then create the watch again.",
25579
+ title: "Database watch limit reached"
25580
+ },
25581
+ database_watch_table_unavailable: {
25582
+ status: 409,
25583
+ retryable: false,
25584
+ action: "The table must exist as an ordinary table owned by the application, created by a deployed migration; views, partitions, temporary tables and the schemas pgcf, ohmyhost, information_schema and pg_* cannot be watched. Fix the name or deploy the migration, then create the watch again.",
25585
+ title: "Table cannot be watched"
25586
+ },
25587
+ database_watch_column_unavailable: {
25588
+ status: 409,
25589
+ retryable: false,
25590
+ action: "List only existing column names exactly as written, names are case-sensitive. Delete the watch before a migration drops a published column, because the write would fail.",
25591
+ title: "Watched column does not exist"
25592
+ },
25593
+ database_watch_events_unavailable: {
25594
+ status: 409,
25595
+ retryable: false,
25596
+ action: "The platform event schema is installed when the database wakes: run any query against that environment, wait for the answer, then create the watch again. If it still fails, report the request_id through feedback.",
25597
+ title: "Database events not installed yet"
25598
+ },
25599
+ database_watch_conflict: {
25600
+ status: 409,
25601
+ retryable: false,
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
+ title: "Table already has a capture trigger"
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
+ },
25575
25617
  project_notes_conflict: {
25576
25618
  status: 409,
25577
25619
  retryable: false,
@@ -25836,7 +25878,7 @@ var PROBLEM_POLICY = {
25836
25878
  api_key_permissions_unavailable: {
25837
25879
  status: 503,
25838
25880
  retryable: false,
25839
- action: "Report the platform user-key permission configuration through feedback. Repeated login or creation will not fix it.",
25881
+ action: "Report the platform user-key permission configuration through feedback with this request_id; it affects every token the same way, whatever the integration. Repeated login does not fix it. After the platform confirms the fix, repeat the same create with the same name and Idempotency-Key.",
25840
25882
  title: "Token permissions unavailable"
25841
25883
  },
25842
25884
  reconciliation_exhausted: {
@@ -26255,8 +26297,8 @@ var isPaidValidationRecord = (value) => {
26255
26297
  if (typeof value !== "object" || value === null || Array.isArray(value) || Object.keys(value).sort().join(",") !== "content,name,purpose,type") {
26256
26298
  return false;
26257
26299
  }
26258
- const record8 = value;
26259
- return (record8["type"] === "CNAME" || record8["type"] === "TXT") && boundedString(record8["name"], 1, 253) && boundedString(record8["content"], 1, 2048) && ["traffic", "ownership", "ssl", "dcv_delegation"].includes(String(record8["purpose"]));
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"]));
26260
26302
  };
26261
26303
 
26262
26304
  // apps/product-cli/dist/source-publisher.js
@@ -26526,7 +26568,7 @@ async function prepareLocalSourcePublication(input) {
26526
26568
  request = { ...request, expected_commit_sha: link2.source.last_confirmed_commit_sha };
26527
26569
  }
26528
26570
  parseManagedSourceRequest("upload", request);
26529
- const record8 = {
26571
+ const record9 = {
26530
26572
  version: 1,
26531
26573
  ...scope,
26532
26574
  operation_id: null,
@@ -26535,16 +26577,16 @@ async function prepareLocalSourcePublication(input) {
26535
26577
  request
26536
26578
  };
26537
26579
  if (original !== null) {
26538
- assertSameAttempt(original, record8);
26580
+ assertSameAttempt(original, record9);
26539
26581
  } else
26540
- await writePending(record8, true);
26582
+ await writePending(record9, true);
26541
26583
  return {
26542
26584
  request,
26543
26585
  accepted: async (operation) => {
26544
26586
  const current = await readPending(scope, replay);
26545
26587
  if (current === null)
26546
26588
  throw new LocalSourcePublicationError("source_publication_missing");
26547
- assertSameAttempt(current, record8);
26589
+ assertSameAttempt(current, record9);
26548
26590
  if (current.operation_id !== null && current.operation_id !== operation.id)
26549
26591
  throw new ResponseContractError();
26550
26592
  if (!replay)
@@ -26563,7 +26605,7 @@ async function prepareLocalSourcePublication(input) {
26563
26605
  const current = await readPending(scope);
26564
26606
  if (current === null || current.operation_id !== null)
26565
26607
  return;
26566
- assertSameAttempt(current, record8);
26608
+ assertSameAttempt(current, record9);
26567
26609
  } catch (error2) {
26568
26610
  if (error2 instanceof LocalSourcePublicationError && (error2.code === "source_publication_scope_mismatch" || error2.code === "source_publication_pending"))
26569
26611
  return;
@@ -26766,12 +26808,12 @@ async function readRecord(path2) {
26766
26808
  await handle?.close();
26767
26809
  }
26768
26810
  }
26769
- async function writePending(record8, create, completed = false) {
26770
- const parent = join3(record8.directory, ".ohmyhost");
26811
+ async function writePending(record9, create, completed = false) {
26812
+ const parent = join3(record9.directory, ".ohmyhost");
26771
26813
  for (const directory of [
26772
26814
  parent,
26773
- record8.metadata_directory,
26774
- join3(record8.metadata_directory, "publications")
26815
+ record9.metadata_directory,
26816
+ join3(record9.metadata_directory, "publications")
26775
26817
  ]) {
26776
26818
  try {
26777
26819
  await fs2.mkdir(directory, { mode: 448 });
@@ -26782,10 +26824,10 @@ async function writePending(record8, create, completed = false) {
26782
26824
  await checkedDirectory(directory);
26783
26825
  await fs2.chmod(directory, 448);
26784
26826
  }
26785
- const target = completed ? completedPath(record8) : pendingPath(record8);
26827
+ const target = completed ? completedPath(record9) : pendingPath(record9);
26786
26828
  const temporary = create ? target : `${target}.${randomUUID()}.tmp`;
26787
26829
  try {
26788
- await fs2.writeFile(temporary, `${JSON.stringify(record8)}
26830
+ await fs2.writeFile(temporary, `${JSON.stringify(record9)}
26789
26831
  `, { mode: 384, flag: "wx" });
26790
26832
  if (!create)
26791
26833
  await fs2.rename(temporary, target);
@@ -26915,7 +26957,7 @@ function exact2(value, keys) {
26915
26957
 
26916
26958
  // packages/contracts/dist/credit-pricing.js
26917
26959
  function assertOrganizationCreditUsage(value) {
26918
- const record8 = (input, keys) => {
26960
+ const record9 = (input, keys) => {
26919
26961
  if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).sort().join() !== keys.split(",").sort().join())
26920
26962
  throw new TypeError("Invalid usage fields");
26921
26963
  return input;
@@ -26923,30 +26965,30 @@ function assertOrganizationCreditUsage(value) {
26923
26965
  const identifier3 = (input) => typeof input === "string" && /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u.test(input);
26924
26966
  const amount = (input) => typeof input === "string" && /^(0|[1-9][0-9]{0,37})$/u.test(input);
26925
26967
  const instant2 = (input) => typeof input === "string" && Number.isFinite(Date.parse(input)) && new Date(input).toISOString() === input;
26926
- const report = record8(value, "organization_id,as_of,unit,period,from,projects,days");
26968
+ const report = record9(value, "organization_id,as_of,unit,period,from,projects,days");
26927
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)
26928
26970
  throw new TypeError("Invalid usage report");
26929
26971
  let previous = "";
26930
26972
  for (const input of report["projects"]) {
26931
- const project = record8(input, "project_id,used_micros");
26973
+ const project = record9(input, "project_id,used_micros");
26932
26974
  if (!identifier3(project["project_id"]) || String(project["project_id"]) <= previous || !amount(project["used_micros"]))
26933
26975
  throw new TypeError("Invalid usage project");
26934
26976
  previous = String(project["project_id"]);
26935
26977
  }
26936
26978
  let previousDay = "";
26937
26979
  for (const input of report["days"]) {
26938
- const day = record8(input, "day,projects");
26980
+ const day = record9(input, "day,projects");
26939
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)
26940
26982
  throw new TypeError("Invalid usage day");
26941
26983
  previousDay = day["day"];
26942
26984
  previous = "";
26943
26985
  for (const projectInput of day["projects"]) {
26944
- const project = record8(projectInput, "project_id,meters");
26986
+ const project = record9(projectInput, "project_id,meters");
26945
26987
  if (!identifier3(project["project_id"]) || String(project["project_id"]) <= previous || !Array.isArray(project["meters"]) || project["meters"].length > 1e3)
26946
26988
  throw new TypeError("Invalid usage project");
26947
26989
  previous = String(project["project_id"]);
26948
26990
  for (const meterInput of project["meters"]) {
26949
- const meter = record8(meterInput, "environment_id,meter,unit,rate_card_id,quantity,charged_micros");
26991
+ const meter = record9(meterInput, "environment_id,meter,unit,rate_card_id,quantity,charged_micros");
26950
26992
  if (meter["environment_id"] !== null && !identifier3(meter["environment_id"]))
26951
26993
  throw new TypeError("Invalid usage environment");
26952
26994
  for (const key of ["meter", "unit", "rate_card_id"])
@@ -27093,6 +27135,9 @@ var DATABASE_WEBHOOK_EVENT_TYPES = [
27093
27135
  "database.resized",
27094
27136
  "database.deleted"
27095
27137
  ];
27138
+ var DATABASE_WATCH_OPERATIONS = ["insert", "update", "delete"];
27139
+ var DATABASE_WATCH_MAX_COLUMNS = 32;
27140
+ var DATABASE_WATCH_DEFAULT_SCHEMA = "public";
27096
27141
  var DATABASE_WEBHOOK_MAX_EVENT_TYPES = 16;
27097
27142
  var DATABASE_WEBHOOK_MAX_HEADERS = 8;
27098
27143
  var DATABASE_WEBHOOK_URL_MAX_LENGTH = 2048;
@@ -27135,15 +27180,61 @@ var USAGE_MAX_RANGE_MS = 31 * 24 * USAGE_HOUR_MS;
27135
27180
  var WEBHOOK_KEYS = ["id", "environment", "url", "event_types", "header_names", "created_at"];
27136
27181
  var WEBHOOK_ID_PATTERN = /^whk_[a-z0-9]{20}$/u;
27137
27182
  var DELIVERY_ID_PATTERN = /^dlv_[0-9a-f]{20}$/u;
27138
- var EVENT_ID_PATTERN = /^evt_[0-9a-f]{20}$/u;
27183
+ var EVENT_ID_PATTERN = /^(?:evt_[0-9a-f]{20}|[a-z][a-z0-9]{19}:[1-9][0-9]{0,15}:[1-9][0-9]{0,15})$/u;
27184
+ var DATA_SUBSCRIPTION_PATTERN = /^data\.(?:\*|[a-z][a-z0-9_]{0,47})$/u;
27185
+ var DATA_EVENT_TYPE_PATTERN = /^data\.[a-z][a-z0-9_]{0,47}$/u;
27186
+ var DATABASE_WATCH_ID_PATTERN = /^pgcf_watch_[0-9a-f]{8}$/u;
27187
+ var DATABASE_WATCH_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]{0,62}$/u;
27188
+ var DATABASE_WATCH_FORBIDDEN_SCHEMAS = ["information_schema", "pgcf", "ohmyhost"];
27189
+ var DATABASE_WATCH_KEYS = [
27190
+ "id",
27191
+ "environment",
27192
+ "schema",
27193
+ "table",
27194
+ "columns",
27195
+ "operations",
27196
+ "topic",
27197
+ "event_type"
27198
+ ];
27139
27199
  var SCHEDULE_NAME_PATTERN = /^[a-z][a-z0-9_-]{0,62}$/u;
27140
27200
  var CURSOR_PATTERN = /^[A-Za-z0-9._|:=+/-]{1,200}$/u;
27141
27201
  var HEADER_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9-]{0,63}$/u;
27202
+ function isDatabaseWatchIdentifier(value) {
27203
+ return matches(value, DATABASE_WATCH_IDENTIFIER_PATTERN);
27204
+ }
27205
+ function isDatabaseWatchSchema(value) {
27206
+ if (!isDatabaseWatchIdentifier(value))
27207
+ return false;
27208
+ const lower = value.toLowerCase();
27209
+ return !lower.startsWith("pg_") && !DATABASE_WATCH_FORBIDDEN_SCHEMAS.includes(lower);
27210
+ }
27211
+ function dataEventTopic(tableName) {
27212
+ const mapped = Array.from(tableName, (character) => {
27213
+ const lower = Array.from(character.toLowerCase())[0] ?? "_";
27214
+ return /^[a-z0-9_]$/u.test(lower) ? lower : "_";
27215
+ }).join("");
27216
+ const topic = /^[a-z]/u.test(mapped) ? mapped : `t_${mapped}`;
27217
+ return topic.slice(0, 48);
27218
+ }
27142
27219
  function assertDatabaseWebhook(value) {
27143
27220
  if (!record4(value) || !exact4(value, WEBHOOK_KEYS))
27144
27221
  throw new TypeError("Invalid database webhook");
27145
27222
  assertWebhookFields(value);
27146
27223
  }
27224
+ function assertDatabaseWatch(value) {
27225
+ if (!record4(value) || !exact4(value, DATABASE_WATCH_KEYS) || !matches(value["id"], DATABASE_WATCH_ID_PATTERN) || !oneOf(["dev", "prod"], value["environment"]) || !isDatabaseWatchSchema(value["schema"]) || !isDatabaseWatchIdentifier(value["table"]) || !Array.isArray(value["columns"]) || value["columns"].length < 1 || value["columns"].length > DATABASE_WATCH_MAX_COLUMNS || !value["columns"].every(isDatabaseWatchIdentifier) || !isCanonicalOperations(value["operations"]) || value["topic"] !== dataEventTopic(value["table"]) || value["event_type"] !== `data.${value["topic"]}`)
27226
+ throw new TypeError("Invalid database watch");
27227
+ }
27228
+ function assertDatabaseWatchPage(value) {
27229
+ if (!record4(value) || !exact4(value, ["items"]) || !pageItems(value["items"]))
27230
+ throw new TypeError("Invalid database watch page");
27231
+ for (const item of value["items"])
27232
+ assertDatabaseWatch(item);
27233
+ }
27234
+ function assertDatabaseWatchDeleted(value) {
27235
+ if (!record4(value) || !exact4(value, ["id", "deleted"]) || !matches(value["id"], DATABASE_WATCH_ID_PATTERN) || value["deleted"] !== true)
27236
+ throw new TypeError("Invalid database watch deletion");
27237
+ }
27147
27238
  function assertDatabaseWebhookCreated(value) {
27148
27239
  if (!record4(value) || !exact4(value, [...WEBHOOK_KEYS, "secret"]) || typeof value["secret"] !== "string" || value["secret"].length === 0)
27149
27240
  throw new TypeError("Invalid database webhook");
@@ -27172,7 +27263,7 @@ function assertDatabaseWebhookDelivery(value) {
27172
27263
  "delivered_at",
27173
27264
  "last_status",
27174
27265
  "last_error"
27175
- ]) || !matches(value["id"], DELIVERY_ID_PATTERN) || !matches(value["event_id"], EVENT_ID_PATTERN) || !oneOf(DATABASE_WEBHOOK_EVENT_TYPES, value["event_type"]) || !matches(value["webhook_id"], WEBHOOK_ID_PATTERN) || !oneOf(["pending", "delivered", "dead_lettered"], value["state"]) || !nonNegativeInteger(value["attempts"]) || !timestamp3(value["created_at"]) || !nullable(value["next_attempt_at"], timestamp3) || !nullable(value["delivered_at"], timestamp3) || !nullable(value["last_status"], Number.isSafeInteger) || !nullable(value["last_error"], (error) => oneOf(["timeout", "network", "http", "expired", "permanent"], error)))
27266
+ ]) || !matches(value["id"], DELIVERY_ID_PATTERN) || !matches(value["event_id"], EVENT_ID_PATTERN) || !isDeliveredEventType(value["event_type"]) || !matches(value["webhook_id"], WEBHOOK_ID_PATTERN) || !oneOf(["pending", "delivered", "dead_lettered"], value["state"]) || !nonNegativeInteger(value["attempts"]) || !timestamp3(value["created_at"]) || !nullable(value["next_attempt_at"], timestamp3) || !nullable(value["delivered_at"], timestamp3) || !nullable(value["last_status"], Number.isSafeInteger) || !nullable(value["last_error"], (error) => oneOf(["timeout", "network", "http", "expired", "permanent"], error)))
27176
27267
  throw new TypeError("Invalid database webhook delivery");
27177
27268
  }
27178
27269
  function assertDatabaseWebhookDeliveryPage(value) {
@@ -27255,7 +27346,7 @@ function assertUsageRow(value) {
27255
27346
  throw new TypeError("Invalid database execution usage row");
27256
27347
  }
27257
27348
  function assertWebhookFields(value) {
27258
- if (!matches(value["id"], WEBHOOK_ID_PATTERN) || !oneOf(["dev", "prod"], value["environment"]) || !isHttpsUrl2(value["url"]) || !Array.isArray(value["event_types"]) || value["event_types"].length < 1 || value["event_types"].length > DATABASE_WEBHOOK_MAX_EVENT_TYPES || !value["event_types"].every((type) => oneOf(DATABASE_WEBHOOK_EVENT_TYPES, type)) || !Array.isArray(value["header_names"]) || value["header_names"].length > DATABASE_WEBHOOK_MAX_HEADERS || !value["header_names"].every((name) => matches(name, HEADER_NAME_PATTERN)) || !timestamp3(value["created_at"]))
27349
+ if (!matches(value["id"], WEBHOOK_ID_PATTERN) || !oneOf(["dev", "prod"], value["environment"]) || !isHttpsUrl2(value["url"]) || !Array.isArray(value["event_types"]) || value["event_types"].length < 1 || value["event_types"].length > DATABASE_WEBHOOK_MAX_EVENT_TYPES || !value["event_types"].every(isDatabaseWebhookEventPattern) || !Array.isArray(value["header_names"]) || value["header_names"].length > DATABASE_WEBHOOK_MAX_HEADERS || !value["header_names"].every((name) => matches(name, HEADER_NAME_PATTERN)) || !timestamp3(value["created_at"]))
27259
27350
  throw new TypeError("Invalid database webhook");
27260
27351
  }
27261
27352
  function isHttpsUrl2(value) {
@@ -27267,6 +27358,18 @@ function isHttpsUrl2(value) {
27267
27358
  return false;
27268
27359
  }
27269
27360
  }
27361
+ function isDatabaseWebhookEventPattern(value) {
27362
+ return oneOf(DATABASE_WEBHOOK_EVENT_TYPES, value) || matches(value, DATA_SUBSCRIPTION_PATTERN);
27363
+ }
27364
+ function isDeliveredEventType(value) {
27365
+ return oneOf(DATABASE_WEBHOOK_EVENT_TYPES, value) || matches(value, DATA_EVENT_TYPE_PATTERN);
27366
+ }
27367
+ function isCanonicalOperations(value) {
27368
+ if (!Array.isArray(value) || value.length < 1)
27369
+ return false;
27370
+ const canonical = DATABASE_WATCH_OPERATIONS.filter((operation) => value.includes(operation));
27371
+ return canonical.length === value.length && canonical.every((op, index) => op === value[index]);
27372
+ }
27270
27373
  function isCronText(value) {
27271
27374
  return typeof value === "string" && value.length >= DATABASE_SCHEDULE_CRON_MIN_LENGTH && value.length <= DATABASE_SCHEDULE_CRON_MAX_LENGTH;
27272
27375
  }
@@ -27310,7 +27413,7 @@ function exact4(value, keys) {
27310
27413
  // apps/product-cli/package.json
27311
27414
  var package_default2 = {
27312
27415
  name: "@ohmyhost/product-cli",
27313
- version: "0.1.44",
27416
+ version: "0.1.46",
27314
27417
  private: true,
27315
27418
  ohmyhost: {
27316
27419
  deployment: "production",
@@ -27759,6 +27862,170 @@ function expectPositiveInteger(value, field, options = {}) {
27759
27862
  return value;
27760
27863
  }
27761
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
+
27762
28029
  // packages/workos-auth-contracts/dist/user-api-keys.js
27763
28030
  var WORKOS_USER_API_KEY_PATTERN = /^sk_[A-Za-z0-9_-]{20,128}$/u;
27764
28031
 
@@ -28424,7 +28691,11 @@ var HELP_USAGE = Object.freeze({
28424
28691
  "database access create": "ohmyhost database access create --project ULID --environment dev|prod [--mode read|write] [--ttl 5m|1h|24h|SECONDS] [--label TEXT] --yes --json\n The connection URI is shown once. Use it immediately, never store it in files, notes or source, and revoke it when finished.",
28425
28692
  "database access list": "ohmyhost database access list --project ULID [--environment dev|prod] --json",
28426
28693
  "database access revoke": "ohmyhost database access revoke --project ULID --access ULID --yes --json",
28427
- "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; the headers file is a UTF-8 JSON object of at most 8 KiB)",
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>')",
28695
+ "database watch list": "ohmyhost database watch list --project ULID [--environment dev|prod] --json (dev when omitted; a sleeping database wakes)",
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)",
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)",
28428
28699
  "database webhook list": "ohmyhost database webhook list --project ULID [--environment dev|prod] --json (dev when omitted; the secret is never listed)",
28429
28700
  "database webhook get": "ohmyhost database webhook get --project ULID [--environment dev|prod] --webhook ID --json",
28430
28701
  "database webhook delete": "ohmyhost database webhook delete --project ULID --environment dev|prod --webhook ID --yes --json",
@@ -28566,12 +28837,12 @@ function buildClientParams(args, fields) {
28566
28837
  };
28567
28838
  const map = buildKeyMap(fields);
28568
28839
  function writeSlot(slot, key, value) {
28569
- let record8 = params[slot];
28570
- if (record8 === void 0) {
28571
- record8 = /* @__PURE__ */ Object.create(null);
28572
- params[slot] = record8;
28840
+ let record9 = params[slot];
28841
+ if (record9 === void 0) {
28842
+ record9 = /* @__PURE__ */ Object.create(null);
28843
+ params[slot] = record9;
28573
28844
  }
28574
- record8[key] = value;
28845
+ record9[key] = value;
28575
28846
  }
28576
28847
  let config;
28577
28848
  for (const [index, arg] of args.entries()) {
@@ -31218,6 +31489,92 @@ var revokeProjectDatabaseAccess = (parameters, options) => {
31218
31489
  ...params
31219
31490
  });
31220
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
+ };
31516
+ var listProjectDatabaseWatches = (parameters, options) => {
31517
+ const params = buildClientParams([parameters], [
31518
+ {
31519
+ args: [
31520
+ { in: "headers", key: "X-Request-Id" },
31521
+ { in: "path", key: "project_id" },
31522
+ { in: "query", key: "environment" }
31523
+ ]
31524
+ }
31525
+ ]);
31526
+ return (options?.client ?? client).get({
31527
+ responseStyle: "data",
31528
+ security: [{ scheme: "bearer", type: "http" }],
31529
+ url: "/v1/projects/{project_id}/database/watches",
31530
+ ...options,
31531
+ ...params
31532
+ });
31533
+ };
31534
+ var createProjectDatabaseWatch = (parameters, options) => {
31535
+ const params = buildClientParams([parameters], [
31536
+ {
31537
+ args: [
31538
+ { in: "headers", key: "X-Request-Id" },
31539
+ { in: "headers", key: "Idempotency-Key" },
31540
+ { in: "path", key: "project_id" },
31541
+ { key: "databaseWatchCreateRequest", map: "body" }
31542
+ ]
31543
+ }
31544
+ ]);
31545
+ return (options?.client ?? client).post({
31546
+ responseStyle: "data",
31547
+ security: [{ scheme: "bearer", type: "http" }],
31548
+ url: "/v1/projects/{project_id}/database/watches",
31549
+ ...options,
31550
+ ...params,
31551
+ headers: {
31552
+ "Content-Type": "application/json",
31553
+ ...options?.headers,
31554
+ ...params.headers
31555
+ }
31556
+ });
31557
+ };
31558
+ var deleteProjectDatabaseWatch = (parameters, options) => {
31559
+ const params = buildClientParams([parameters], [
31560
+ {
31561
+ args: [
31562
+ { in: "headers", key: "X-Request-Id" },
31563
+ { in: "headers", key: "Idempotency-Key" },
31564
+ { in: "path", key: "project_id" },
31565
+ { in: "path", key: "watch_id" },
31566
+ { in: "query", key: "environment" }
31567
+ ]
31568
+ }
31569
+ ]);
31570
+ return (options?.client ?? client).delete({
31571
+ responseStyle: "data",
31572
+ security: [{ scheme: "bearer", type: "http" }],
31573
+ url: "/v1/projects/{project_id}/database/watches/{watch_id}",
31574
+ ...options,
31575
+ ...params
31576
+ });
31577
+ };
31221
31578
  var listProjectDatabaseWebhooks = (parameters, options) => {
31222
31579
  const params = buildClientParams([parameters], [
31223
31580
  {
@@ -32622,7 +32979,25 @@ function checkedResponse(kind, value) {
32622
32979
 
32623
32980
  // apps/product-cli/dist/product-api.js
32624
32981
  var WEBHOOK_SCOPE_MISMATCH = "Webhook response scope mismatch";
32982
+ var WATCH_SCOPE_MISMATCH = "Watch response scope mismatch";
32983
+ var TABLE_SCOPE_MISMATCH = "Table response scope mismatch";
32625
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
+ }
32626
33001
  var GeneratedSdkProductApi = class {
32627
33002
  #client;
32628
33003
  managedSource;
@@ -32819,6 +33194,58 @@ var GeneratedSdkProductApi = class {
32819
33194
  assertProjectDatabaseAccess(value);
32820
33195
  return value;
32821
33196
  }
33197
+ async createProjectDatabaseWatch(input) {
33198
+ const value = await createProjectDatabaseWatch({
33199
+ project_id: input.projectId,
33200
+ "Idempotency-Key": input.idempotencyKey,
33201
+ databaseWatchCreateRequest: {
33202
+ environment: input.environment,
33203
+ schema: input.request.schema,
33204
+ table: input.request.table,
33205
+ columns: [...input.request.columns],
33206
+ operations: [...input.request.operations]
33207
+ }
33208
+ }, { client: this.#client });
33209
+ assertDatabaseWatch(value);
33210
+ if (value.environment !== input.environment || value.schema !== input.request.schema || value.table !== input.request.table)
33211
+ throw new TypeError(WATCH_SCOPE_MISMATCH);
33212
+ return value;
33213
+ }
33214
+ async listProjectDatabaseWatches(input) {
33215
+ const value = await listProjectDatabaseWatches({ project_id: input.projectId, environment: input.environment }, { client: this.#client });
33216
+ assertDatabaseWatchPage(value);
33217
+ if (value.items.some((item) => item.environment !== input.environment))
33218
+ throw new TypeError(WATCH_SCOPE_MISMATCH);
33219
+ return value;
33220
+ }
33221
+ async deleteProjectDatabaseWatch(input) {
33222
+ const value = await deleteProjectDatabaseWatch({
33223
+ project_id: input.projectId,
33224
+ environment: input.environment,
33225
+ "Idempotency-Key": input.idempotencyKey,
33226
+ watch_id: input.watchId
33227
+ }, { client: this.#client });
33228
+ assertDatabaseWatchDeleted(value);
33229
+ if (value.id !== input.watchId)
33230
+ throw new TypeError(WATCH_SCOPE_MISMATCH);
33231
+ return value;
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
+ }
32822
33249
  /** The signing secret exists only in this answer; the CLI prints it once and stores nothing. */
32823
33250
  async createProjectDatabaseWebhook(input) {
32824
33251
  const value = await createProjectDatabaseWebhook({
@@ -34096,6 +34523,55 @@ var GeneratedSdkLocalMcpClient = class {
34096
34523
  requireScope(value.items.every((webhook) => webhook.environment === environment2));
34097
34524
  return value;
34098
34525
  }
34526
+ async listDatabaseWatches(input) {
34527
+ const environment2 = input.environment ?? "dev";
34528
+ const value = await listProjectDatabaseWatches({ project_id: input.projectId, environment: environment2 }, { client: this.#client });
34529
+ assertDatabaseWatchPage(value);
34530
+ requireScope(value.items.every((watch) => watch.environment === environment2));
34531
+ return value;
34532
+ }
34533
+ async createDatabaseWatch(input) {
34534
+ const value = await createProjectDatabaseWatch({
34535
+ project_id: input.projectId,
34536
+ "Idempotency-Key": input.idempotencyKey,
34537
+ databaseWatchCreateRequest: {
34538
+ environment: input.environment,
34539
+ ...input.schema === void 0 ? {} : { schema: input.schema },
34540
+ table: input.table,
34541
+ columns: [...input.columns],
34542
+ ...input.operations === void 0 ? {} : { operations: [...input.operations] }
34543
+ }
34544
+ }, { client: this.#client });
34545
+ assertDatabaseWatch(value);
34546
+ requireScope(value.environment === input.environment && value.table === input.table && value.schema === (input.schema ?? DATABASE_WATCH_DEFAULT_SCHEMA));
34547
+ return value;
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
+ }
34564
+ async deleteDatabaseWatch(input) {
34565
+ const value = await deleteProjectDatabaseWatch({
34566
+ project_id: input.projectId,
34567
+ environment: input.environment,
34568
+ "Idempotency-Key": input.idempotencyKey,
34569
+ watch_id: input.watchId
34570
+ }, { client: this.#client });
34571
+ assertDatabaseWatchDeleted(value);
34572
+ requireScope(value.id === input.watchId);
34573
+ return value;
34574
+ }
34099
34575
  /** The signing secret exists only in this response and is never stored by the client. */
34100
34576
  async createDatabaseWebhook(input) {
34101
34577
  const value = await createProjectDatabaseWebhook({
@@ -34445,13 +34921,13 @@ function normalizeMcpSourceChanges(value) {
34445
34921
  }
34446
34922
  }
34447
34923
  function normalizeSourceChanges(value) {
34448
- const body = record7(value);
34924
+ const body = record8(value);
34449
34925
  const changes = body["changes"];
34450
34926
  if (!Array.isArray(changes) || changes.length < 1 || changes.length > MANAGED_SOURCE_LIMITS.files)
34451
34927
  invalid7();
34452
34928
  let textBytes = 0;
34453
34929
  const normalized = changes.map((change) => {
34454
- const entry = record7(change);
34930
+ const entry = record8(change);
34455
34931
  const hasText = Object.hasOwn(entry, "content_text");
34456
34932
  if (hasText === Object.hasOwn(entry, "content_base64"))
34457
34933
  invalid7();
@@ -34510,7 +34986,7 @@ function encodeBase64(bytes) {
34510
34986
  binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
34511
34987
  return btoa(binary);
34512
34988
  }
34513
- function record7(value) {
34989
+ function record8(value) {
34514
34990
  if (typeof value !== "object" || value === null || Array.isArray(value))
34515
34991
  invalid7();
34516
34992
  return value;
@@ -34523,7 +34999,10 @@ function invalid7() {
34523
34999
  var identifier2 = external_exports.string().min(1).max(256);
34524
35000
  var databaseEnvironment = external_exports.enum(["dev", "prod"]);
34525
35001
  var databaseWebhookId = external_exports.string().regex(/^whk_[a-z0-9]{20}$/u);
35002
+ var databaseWatchId = external_exports.string().regex(/^pgcf_watch_[0-9a-f]{8}$/u);
35003
+ var databaseIdentifier = external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,62}$/u);
34526
35004
  var databaseDeliveryId = external_exports.string().regex(/^dlv_[0-9a-f]{20}$/u);
35005
+ var databaseTableIdentifier = external_exports.string().refine(isDatabaseTableIdentifier);
34527
35006
  var databaseScheduleName = external_exports.string().regex(/^[a-z][a-z0-9_-]{0,62}$/u);
34528
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.");
34529
35008
  var idempotencyKey = external_exports.string().min(1).max(128);
@@ -34774,15 +35253,81 @@ function createLocalOhmyhostMcpServer(dependencies) {
34774
35253
  ...input.environment === void 0 ? {} : { environment: input.environment }
34775
35254
  }));
34776
35255
  registerProductTool(server, dependencies, "database_access_revoke", "Revoke one issued database credential immediately: open sessions end and its PostgreSQL role is removed. Revocation is idempotent and never touches application roles or data.", external_exports.object({ project_id: identifier2, access_id: identifier2 }), (client2, input) => client2.revokeDatabaseAccess({ projectId: input.project_id, accessId: input.access_id }), destructiveAnnotations());
35256
+ registerProductTool(server, dependencies, "database_watch_list", "List this project's database watches of one Dev or Prod environment (dev when omitted). Each watch shows its table, columns, operations and the event type data.<topic> it publishes. Listing wakes a sleeping database.", external_exports.object({ project_id: identifier2, environment: databaseEnvironment.optional() }), (client2, input) => client2.listDatabaseWatches({
35257
+ projectId: input.project_id,
35258
+ ...input.environment === void 0 ? {} : { environment: input.environment }
35259
+ }));
35260
+ registerProductTool(server, dependencies, "database_watch_create", "Publish row changes of one table of a Dev or Prod database as data events: only the listed columns (at most 32) of each insert, update or delete are published, with the event type data.<topic> returned by this call. Pass that event type to database_webhook_create. The table must exist as an ordinary table of the application, created by a deployed migration; a sleeping database wakes. Rows written before the watch exists are not published, and a published column must not be dropped while the watch exists. Requires confirmed: true and an idempotency key. Refused with project_budget_exceeded while the Stop budget is reached.", external_exports.object({
35261
+ project_id: identifier2,
35262
+ environment: databaseEnvironment,
35263
+ schema: databaseIdentifier.refine(isDatabaseWatchSchema).optional(),
35264
+ table: databaseIdentifier,
35265
+ columns: external_exports.array(databaseIdentifier).min(1).max(32).refine((columns) => new Set(columns).size === columns.length),
35266
+ operations: external_exports.array(external_exports.enum(DATABASE_WATCH_OPERATIONS)).min(1).max(3).refine((operations) => new Set(operations).size === operations.length).optional(),
35267
+ idempotency_key: idempotencyKey,
35268
+ confirmed: external_exports.literal(true)
35269
+ }), (client2, input) => client2.createDatabaseWatch({
35270
+ projectId: input.project_id,
35271
+ environment: input.environment,
35272
+ ...input.schema === void 0 ? {} : { schema: input.schema },
35273
+ table: input.table,
35274
+ columns: input.columns,
35275
+ ...input.operations === void 0 ? {} : { operations: input.operations },
35276
+ idempotencyKey: input.idempotency_key
35277
+ }), mutationAnnotations());
35278
+ registerProductTool(server, dependencies, "database_watch_delete", "Remove the capture trigger of one database watch: its table publishes no more data events. Destructive: requires confirmed: true and an idempotency key. Deleting an already deleted watch answers not found.", external_exports.object({
35279
+ project_id: identifier2,
35280
+ environment: databaseEnvironment,
35281
+ watch_id: databaseWatchId,
35282
+ idempotency_key: idempotencyKey,
35283
+ confirmed: external_exports.literal(true)
35284
+ }), (client2, input) => client2.deleteDatabaseWatch({
35285
+ projectId: input.project_id,
35286
+ environment: input.environment,
35287
+ watchId: input.watch_id,
35288
+ idempotencyKey: input.idempotency_key
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());
34777
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({
34778
35320
  projectId: input.project_id,
34779
35321
  ...input.environment === void 0 ? {} : { environment: input.environment }
34780
35322
  }));
34781
- registerProductTool(server, dependencies, "database_webhook_create", "Subscribe one HTTPS receiver to database lifecycle events (database.created, ready, woke, slept, suspended, resized, deleted) of one Dev or Prod database. The signing secret is RETURNED EXACTLY ONCE: store it in a secret manager and never write it into files, notes, source, commit messages or later messages. Deliveries are signed, retried and dead-lettered when retries stop. At most five webhooks exist per project environment. Requires confirmed: true and an idempotency key; the same key with the same request returns the stored answer.", external_exports.object({
35323
+ registerProductTool(server, dependencies, "database_webhook_create", "Subscribe one HTTPS receiver to database lifecycle events (database.created, ready, woke, slept, suspended, resized, deleted) of one Dev or Prod database, or to data events: data.<topic> for the rows of one watched table (the event type database_watch_create returns) or data.* for every watched table; a bare * never matches data events. The signing secret is RETURNED EXACTLY ONCE: store it in a secret manager and never write it into files, notes, source, commit messages or later messages. Deliveries are signed, retried and dead-lettered when retries stop. At most five webhooks exist per project environment. Requires confirmed: true and an idempotency key; the same key with the same request returns the stored answer.", external_exports.object({
34782
35324
  project_id: identifier2,
34783
35325
  environment: databaseEnvironment,
34784
35326
  url: external_exports.string().max(2048).regex(/^https:\/\//u),
34785
- event_types: external_exports.array(external_exports.enum(DATABASE_WEBHOOK_EVENT_TYPES)).min(1).max(16),
35327
+ event_types: external_exports.array(external_exports.union([
35328
+ external_exports.enum(DATABASE_WEBHOOK_EVENT_TYPES),
35329
+ external_exports.string().regex(/^data\.(?:\*|[a-z][a-z0-9_]{0,47})$/u).refine(isDatabaseWebhookEventPattern)
35330
+ ])).min(1).max(16),
34786
35331
  headers: external_exports.record(external_exports.string(), external_exports.string()).optional(),
34787
35332
  idempotency_key: idempotencyKey,
34788
35333
  confirmed: external_exports.literal(true)