@amerged/ohmyhost-cli 0.1.14 → 0.1.17

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.
@@ -15004,6 +15004,10 @@ var recognizedCommandLabel = (argv) => {
15004
15004
  return "project handle check";
15005
15005
  if (value === "project" && values[0] === "handle" && values[1] === "set")
15006
15006
  return "project handle set";
15007
+ if (value === "project" && values[0] === "dev-share" && ["link", "rotate", "revoke"].includes(values[1] ?? ""))
15008
+ return values[1] === "link" ? "project dev-share link" : values[1] === "rotate" ? "project dev-share rotate" : "project dev-share revoke";
15009
+ if (value === "project" && values[0] === "dev-access" && values[1] === "mode")
15010
+ return "project dev-access mode";
15007
15011
  if (value === "project" && values[0] === "dev-access" && values[1] === "create")
15008
15012
  return "project dev-access create";
15009
15013
  if (value === "database" && values[0] === "compute" && values[1] === "set")
@@ -15095,6 +15099,8 @@ var recognizedCommandLabel = (argv) => {
15095
15099
  return "mail domain set";
15096
15100
  if (values[1] === "status")
15097
15101
  return "mail domain status";
15102
+ if (values[1] === "delete")
15103
+ return "mail domain delete";
15098
15104
  }
15099
15105
  return "unknown";
15100
15106
  }
@@ -15493,6 +15499,40 @@ var parseProductCliCommand = (argv) => {
15493
15499
  const options2 = parseOptions(values, ["--handle"]);
15494
15500
  return { kind: "project-handle-check", handle: options2["--handle"], credentialStore };
15495
15501
  }
15502
+ if (subcommand === "dev-share") {
15503
+ const action = values.shift();
15504
+ if (action === "link") {
15505
+ if (yes || wait || follow || stdin)
15506
+ throw new InvalidCommandError();
15507
+ const options2 = parseOptions(values, ["--project"]);
15508
+ return { kind: "project-dev-share-link", projectId: options2["--project"], credentialStore };
15509
+ }
15510
+ if ((action === "rotate" || action === "revoke") && yes && !wait && !follow && !stdin) {
15511
+ const options2 = parseOptions(values, ["--project", "--idempotency-key"]);
15512
+ return {
15513
+ kind: action === "rotate" ? "project-dev-share-rotate" : "project-dev-share-revoke",
15514
+ projectId: options2["--project"],
15515
+ idempotencyKey: options2["--idempotency-key"],
15516
+ credentialStore
15517
+ };
15518
+ }
15519
+ throw new InvalidCommandError();
15520
+ }
15521
+ if (subcommand === "dev-access" && values[0] === "mode") {
15522
+ values.shift();
15523
+ if (!yes || wait || follow || stdin)
15524
+ throw new InvalidCommandError();
15525
+ const options2 = parseOptions(values, ["--project", "--mode", "--idempotency-key"]);
15526
+ if (options2["--mode"] !== "protected" && options2["--mode"] !== "public")
15527
+ throw new InvalidCommandError();
15528
+ return {
15529
+ kind: "project-dev-access-mode-set",
15530
+ projectId: options2["--project"],
15531
+ mode: options2["--mode"],
15532
+ idempotencyKey: options2["--idempotency-key"],
15533
+ credentialStore
15534
+ };
15535
+ }
15496
15536
  if (subcommand === "dev-access" && values.shift() === "create") {
15497
15537
  if (yes || wait || follow || stdin)
15498
15538
  throw new InvalidCommandError();
@@ -15559,17 +15599,20 @@ var parseProductCliCommand = (argv) => {
15559
15599
  "--name",
15560
15600
  "--idempotency-key",
15561
15601
  "--data-mode",
15602
+ "--dev-access-mode",
15562
15603
  "--region"
15563
15604
  ]);
15564
15605
  const dataMode = options["--data-mode"];
15606
+ const devAccessMode = options["--dev-access-mode"];
15565
15607
  const region = options["--region"];
15566
- if (!options["--organization"] || !options["--name"] || !options["--idempotency-key"] || dataMode !== void 0 && dataMode !== "shared" && dataMode !== "isolated" || region !== void 0 && region !== "us" && region !== "eu")
15608
+ if (!options["--organization"] || !options["--name"] || !options["--idempotency-key"] || dataMode !== void 0 && dataMode !== "shared" && dataMode !== "isolated" || devAccessMode !== void 0 && devAccessMode !== "protected" && devAccessMode !== "public" || region !== void 0 && region !== "us" && region !== "eu")
15567
15609
  throw new InvalidCommandError();
15568
15610
  return {
15569
15611
  kind: "project-create",
15570
15612
  organizationId: options["--organization"],
15571
15613
  name: options["--name"],
15572
15614
  ...dataMode === void 0 ? {} : { dataMode },
15615
+ ...devAccessMode === void 0 ? {} : { devAccessMode },
15573
15616
  ...region === void 0 ? {} : { region },
15574
15617
  idempotencyKey: options["--idempotency-key"],
15575
15618
  credentialStore
@@ -15814,23 +15857,42 @@ var parseProductCliCommand = (argv) => {
15814
15857
  if (first === "plan") {
15815
15858
  if (yes || wait || follow || stdin)
15816
15859
  throw new InvalidCommandError();
15817
- const options = parseOptions(values, ["--project", "--commit"]);
15860
+ const options = parseOptionalOptions(values, ["--project", "--commit", "--environment"]);
15861
+ const projectId = options["--project"];
15862
+ const commitSha = options["--commit"];
15863
+ if (projectId === void 0 || commitSha === void 0)
15864
+ throw new InvalidCommandError();
15818
15865
  return {
15819
15866
  kind: "plan",
15820
- projectId: options["--project"],
15821
- commitSha: options["--commit"],
15867
+ projectId,
15868
+ commitSha,
15869
+ environment: deploymentEnvironment(options["--environment"]),
15822
15870
  credentialStore
15823
15871
  };
15824
15872
  }
15825
15873
  if (first === "deploy") {
15826
15874
  if (!yes || follow || stdin)
15827
15875
  throw new InvalidCommandError();
15828
- const options = parseOptions(values, ["--project", "--plan-id", "--idempotency-key"]);
15876
+ const options = parseOptionalOptions(values, [
15877
+ "--project",
15878
+ "--plan-id",
15879
+ "--commit",
15880
+ "--environment",
15881
+ "--idempotency-key"
15882
+ ]);
15883
+ const projectId = options["--project"];
15884
+ const idempotencyKey = options["--idempotency-key"];
15885
+ const planId = options["--plan-id"] ?? null;
15886
+ const commitSha = options["--commit"] ?? null;
15887
+ if (projectId === void 0 || idempotencyKey === void 0 || planId === null === (commitSha === null) || planId !== null && options["--environment"] !== void 0)
15888
+ throw new InvalidCommandError();
15829
15889
  return {
15830
15890
  kind: "deploy",
15831
- projectId: options["--project"],
15832
- planId: options["--plan-id"],
15833
- idempotencyKey: options["--idempotency-key"],
15891
+ projectId,
15892
+ planId,
15893
+ commitSha,
15894
+ environment: deploymentEnvironment(options["--environment"]),
15895
+ idempotencyKey,
15834
15896
  yes,
15835
15897
  wait,
15836
15898
  credentialStore
@@ -16127,10 +16189,11 @@ var parseProductCliCommand = (argv) => {
16127
16189
  throw new InvalidCommandError();
16128
16190
  }
16129
16191
  if (first === "mail") {
16130
- if (yes || wait || follow || stdin)
16131
- throw new InvalidCommandError();
16132
16192
  const area = values.shift();
16133
16193
  const sub = area === "webhook" || area === "messages" || area === "domain" ? values.shift() : void 0;
16194
+ const retiring = area === "domain" && sub === "delete";
16195
+ if (yes !== retiring || wait || follow || stdin)
16196
+ throw new InvalidCommandError();
16134
16197
  const options = parseOptionalOptions(values, [
16135
16198
  "--project",
16136
16199
  "--environment",
@@ -16166,6 +16229,13 @@ var parseProductCliCommand = (argv) => {
16166
16229
  } else if (area === "status" || area === "domain" && sub === "status") {
16167
16230
  request = { ...scope, action: "status" };
16168
16231
  label = area === "domain" ? "mail domain status" : "mail status";
16232
+ } else if (retiring) {
16233
+ request = {
16234
+ ...scope,
16235
+ action: "domain_delete",
16236
+ idempotencyKey: required("--idempotency-key")
16237
+ };
16238
+ label = "mail domain delete";
16169
16239
  } else if (area === "webhook" && sub === "set") {
16170
16240
  request = {
16171
16241
  ...scope,
@@ -16230,6 +16300,13 @@ var parseOptions = (values, allowed) => {
16230
16300
  throw new InvalidCommandError();
16231
16301
  return result;
16232
16302
  };
16303
+ var deploymentEnvironment = (value) => {
16304
+ if (value === void 0 || value === "dev")
16305
+ return "dev";
16306
+ if (value === "prod")
16307
+ return "prod";
16308
+ throw new InvalidCommandError();
16309
+ };
16233
16310
  var parseOptionalOptions = (values, allowed) => {
16234
16311
  const result = {};
16235
16312
  for (let index = 0; index < values.length; index += 2) {
@@ -16754,7 +16831,7 @@ var PROBLEM_POLICY = {
16754
16831
  cloudflare_zone_not_bound: {
16755
16832
  status: 409,
16756
16833
  retryable: false,
16757
- action: "Configure the project domain first with 'ohmyhost domain paid plan' then 'ohmyhost domain paid apply', or configure its sender domain with 'ohmyhost mail domain set'. Then request Cloudflare authorization for that domain's zone."
16834
+ action: "Configure the project domain first with 'ohmyhost domain paid plan' then 'ohmyhost domain paid apply', or configure its sender domain with 'ohmyhost mail setup'. Then request Cloudflare authorization for that domain's zone."
16758
16835
  },
16759
16836
  github_connection_required: {
16760
16837
  status: 409,
@@ -16909,6 +16986,11 @@ var PROBLEM_POLICY = {
16909
16986
  retryable: false,
16910
16987
  action: "Select the current succeeded dev deployment and target prod."
16911
16988
  },
16989
+ mail_capacity_unavailable: {
16990
+ status: 503,
16991
+ retryable: true,
16992
+ action: "Report this request ID through feedback. The stored mail setup continues automatically once ohmyho.st has capacity; follow mail status and keep the original idempotency key."
16993
+ },
16912
16994
  mail_domain_conflict: {
16913
16995
  status: 409,
16914
16996
  retryable: false,
@@ -16917,13 +16999,23 @@ var PROBLEM_POLICY = {
16917
16999
  mail_domain_required: {
16918
17000
  status: 409,
16919
17001
  retryable: false,
16920
- action: "Run 'ohmyhost mail domain set' for this project, then plan again."
17002
+ action: "This app declares mail.enabled. Configure the project's own sender domain with 'ohmyhost mail setup' using its Prod environment ID, or set mail.enabled to false if the app sends no mail, then plan again."
16921
17003
  },
16922
17004
  storage_jurisdiction_conflict: {
16923
17005
  status: 409,
16924
17006
  retryable: false,
16925
17007
  action: "Set storage.jurisdiction in ohmyhost.yaml to the project's hosting region shown by project status, then plan again."
16926
17008
  },
17009
+ shared_data_requires_promotion: {
17010
+ status: 409,
17011
+ retryable: false,
17012
+ action: "Plan and deploy this commit to Dev, then run 'ohmyhost deployment promote plan' to reach Prod."
17013
+ },
17014
+ production_deployment_required: {
17015
+ status: 409,
17016
+ retryable: false,
17017
+ action: "Deploy to Prod first: run 'ohmyhost plan --environment prod' and deploy that plan, or promote the current Dev deployment with 'ohmyhost deployment promote plan'. Then plan the domain again."
17018
+ },
16927
17019
  framework_conversion_required: {
16928
17020
  status: 409,
16929
17021
  retryable: false,
@@ -17181,6 +17273,12 @@ var parseCloudflareDnsAuthorizationStatus = (value) => {
17181
17273
  }
17182
17274
  return input;
17183
17275
  };
17276
+ var parseDevAccessState = (value) => {
17277
+ const input = exactRecord2(value, ["project_id", "mode", "share_url"]);
17278
+ if (!isUlid(input["project_id"]) || input["mode"] !== "protected" && input["mode"] !== "public" || input["mode"] === "public" && input["share_url"] !== null || input["share_url"] !== null && (typeof input["share_url"] !== "string" || !/^https:\/\/dev-[a-z0-9]+(?:-[a-z0-9]+){0,4}\.(?:dev\.)?check\.omh\.st\/\.ohmyhost\/dev-access\/redeem\?stage=dev&ticket=[A-Za-z0-9_-]{43}$/u.test(input["share_url"])))
17279
+ throw new ResponseContractError();
17280
+ return input;
17281
+ };
17184
17282
  var parseDevAccessTicket = (value) => {
17185
17283
  const input = exactRecord2(value, [
17186
17284
  "ticket_id",
@@ -17336,6 +17434,7 @@ var parseProjectStatus = (value) => {
17336
17434
  "etag",
17337
17435
  "handle",
17338
17436
  "region",
17437
+ "dev_access_mode",
17339
17438
  "lifecycle",
17340
17439
  "source",
17341
17440
  "default_environment",
@@ -17347,7 +17446,7 @@ var parseProjectStatus = (value) => {
17347
17446
  "cleanup_state"
17348
17447
  ]);
17349
17448
  const handle = input["handle"];
17350
- if (!isUlid(input["project_id"]) || typeof input["etag"] !== "string" || !/^"sha256-[a-f0-9]{64}"$/u.test(input["etag"]) || !boundedString(handle, 3, 59) || !/^[a-z0-9]+(?:-[a-z0-9]+){0,4}$/u.test(handle) || input["region"] !== "us" && input["region"] !== "eu" || input["lifecycle"] !== "active" && input["lifecycle"] !== "deleting" && input["lifecycle"] !== "deleted" || input["dev_url"] !== null && ![`https://dev-${handle}.dev.check.omh.st`, `https://dev-${handle}.check.omh.st`].includes(String(input["dev_url"])) || input["prod_url"] !== null && ![`https://${handle}.dev.check.omh.st`, `https://${handle}.check.omh.st`].includes(String(input["prod_url"])) || input["cleanup_state"] !== "not_started" && input["cleanup_state"] !== "pending" && input["cleanup_state"] !== "completed" && input["cleanup_state"] !== "reconciliation_required") {
17449
+ if (!isUlid(input["project_id"]) || typeof input["etag"] !== "string" || !/^"sha256-[a-f0-9]{64}"$/u.test(input["etag"]) || !boundedString(handle, 3, 59) || !/^[a-z0-9]+(?:-[a-z0-9]+){0,4}$/u.test(handle) || input["region"] !== "us" && input["region"] !== "eu" || input["dev_access_mode"] !== "protected" && input["dev_access_mode"] !== "public" || input["lifecycle"] !== "active" && input["lifecycle"] !== "deleting" && input["lifecycle"] !== "deleted" || input["dev_url"] !== null && ![`https://dev-${handle}.dev.check.omh.st`, `https://dev-${handle}.check.omh.st`].includes(String(input["dev_url"])) || input["prod_url"] !== null && ![`https://${handle}.dev.check.omh.st`, `https://${handle}.check.omh.st`].includes(String(input["prod_url"])) || input["cleanup_state"] !== "not_started" && input["cleanup_state"] !== "pending" && input["cleanup_state"] !== "completed" && input["cleanup_state"] !== "reconciliation_required") {
17351
17450
  throw new ResponseContractError();
17352
17451
  }
17353
17452
  if (input["source"] !== null)
@@ -17518,6 +17617,7 @@ var parseDeploymentPlan = (value) => {
17518
17617
  const input = exactRecord2(value, [
17519
17618
  "id",
17520
17619
  "project_id",
17620
+ "environment",
17521
17621
  "commit_sha",
17522
17622
  "source_digest",
17523
17623
  "build_plan_digest",
@@ -17539,11 +17639,12 @@ var parseDeploymentPlan = (value) => {
17539
17639
  "currency",
17540
17640
  "rate_card_version",
17541
17641
  "credit_micros",
17642
+ "credits",
17542
17643
  "provider_cost_micros",
17543
17644
  "scope",
17544
17645
  "reserved_seconds"
17545
17646
  ]);
17546
- if (!isUlid(input["id"]) || !isUlid(input["project_id"]) || !isCommitSha(input["commit_sha"]) || !isDigest(input["source_digest"]) || !isDigest(input["build_plan_digest"]) || !isApplicationRoot(input["application_root"]) || input["artifact_digest"] !== void 0 && !isDigest(input["artifact_digest"]) || input["runtime"] !== "cloudflare_workers_static_assets" && input["runtime"] !== "cloudflare_workers_edge_ssr" || !isHttpsUrlValue(input["route"]) || !stringArray(input["resource_effects"]) || !stringArray(input["limits"]) || !stringArray(input["risks"]) || !stringArray(input["destructive_effects"]) || !stringArray(input["required_confirmations"]) || !isIsoInstant(input["created_at"]) || !isIsoInstant(input["expires_at"]) || !decimal(cost["amount_micros"]) || !boundedString(cost["currency"], 1, 16) || !boundedString(cost["rate_card_version"], 1, 128) || !decimal(cost["credit_micros"]) || !decimal(cost["provider_cost_micros"]) || cost["scope"] !== "build_compute" || !decimal(cost["reserved_seconds"]) || cost["reserved_seconds"] === "0")
17647
+ if (!isUlid(input["id"]) || !isUlid(input["project_id"]) || input["environment"] !== "dev" && input["environment"] !== "prod" || !isCommitSha(input["commit_sha"]) || !isDigest(input["source_digest"]) || !isDigest(input["build_plan_digest"]) || !isApplicationRoot(input["application_root"]) || input["artifact_digest"] !== void 0 && !isDigest(input["artifact_digest"]) || input["runtime"] !== "cloudflare_workers_static_assets" && input["runtime"] !== "cloudflare_workers_edge_ssr" || !isHttpsUrlValue(input["route"]) || !stringArray(input["resource_effects"]) || !stringArray(input["limits"]) || !stringArray(input["risks"]) || !stringArray(input["destructive_effects"]) || !stringArray(input["required_confirmations"]) || !isIsoInstant(input["created_at"]) || !isIsoInstant(input["expires_at"]) || !decimal(cost["amount_micros"]) || !boundedString(cost["currency"], 1, 16) || !boundedString(cost["rate_card_version"], 1, 128) || !decimal(cost["credit_micros"]) || typeof cost["credits"] !== "string" || !/^[0-9]+(?:\.[0-9]{1,6})?$/u.test(cost["credits"]) || !decimal(cost["provider_cost_micros"]) || cost["scope"] !== "build_compute" || !decimal(cost["reserved_seconds"]) || cost["reserved_seconds"] === "0")
17547
17648
  throw new ResponseContractError();
17548
17649
  return input;
17549
17650
  };
@@ -17624,8 +17725,10 @@ var parseSafeProblem = (value) => {
17624
17725
  const retryAfter = input["retry_after_seconds"];
17625
17726
  if (retryAfter !== void 0 && (code !== "rate_limited" || typeof retryAfter !== "number" || !Number.isSafeInteger(retryAfter) || retryAfter < 1 || retryAfter > 86400))
17626
17727
  throw new ResponseContractError();
17728
+ const docsUrl = String(input["type"]);
17627
17729
  return {
17628
17730
  requestId: input["request_id"],
17731
+ ...docsUrl.startsWith("https://docs.ohmyho.st/errors/") ? { docsUrl } : {},
17629
17732
  code,
17630
17733
  retryable: policy.retryable,
17631
17734
  suggestedAction: (code === "framework_conversion_required" ? parseFrameworkConversionDetail(input["detail"]) ?? policy.action : policy.action) + (retryAfter === void 0 ? "" : ` Retry after ${String(retryAfter)} seconds.`),
@@ -17899,7 +18002,7 @@ function exact2(v, keys) {
17899
18002
  // apps/product-cli/package.json
17900
18003
  var package_default = {
17901
18004
  name: "@ohmyhost/product-cli",
17902
- version: "0.1.14",
18005
+ version: "0.1.17",
17903
18006
  private: true,
17904
18007
  ohmyhost: {
17905
18008
  deployment: "production",
@@ -18256,12 +18359,16 @@ var HELP_USAGE = Object.freeze({
18256
18359
  "token list": "ohmyhost token list --organization ULID [--after KEY_ID] --json",
18257
18360
  "token revoke": "ohmyhost token revoke --organization ULID --key KEY_ID --yes --json",
18258
18361
  "feedback submit": "ohmyhost feedback submit --organization ULID --kind bug|issue|feature_request --title TITLE --description REDACTED_REPORT [--project ULID] [--environment ULID] [--operation ULID] [--error-code CODE] [--client-version VERSION] --idempotency-key KEY --json",
18259
- "project create": "ohmyhost project create --organization ULID --name NAME [--data-mode shared|isolated] [--region us|eu] --idempotency-key KEY --json (the region is chosen once: us is the default, eu places the database, files and builds in the EU; it cannot be changed later)",
18362
+ "project create": "ohmyhost project create --organization ULID --name NAME [--data-mode shared|isolated] [--dev-access-mode protected|public] [--region us|eu] --idempotency-key KEY --json (the region is chosen once: us is the default, eu places the database, files and builds in the EU; it cannot be changed later)",
18260
18363
  "project list": "ohmyhost project list [--cursor ULID] [--limit LIMIT] --json",
18261
18364
  "project context": "ohmyhost project context --project ULID --json",
18262
18365
  "project notes set": "ohmyhost project notes set --project ULID --version NUMBER --markdown TEXT --idempotency-key KEY --json (no credentials or signed URLs)",
18263
18366
  "project status": "ohmyhost project status --project ULID --json",
18264
18367
  "project dev-access create": "ohmyhost project dev-access create --project ULID --json",
18368
+ "project dev-share link": "ohmyhost project dev-share link --project ULID --json",
18369
+ "project dev-share rotate": "ohmyhost project dev-share rotate --project ULID --idempotency-key KEY --yes --json",
18370
+ "project dev-share revoke": "ohmyhost project dev-share revoke --project ULID --idempotency-key KEY --yes --json",
18371
+ "project dev-access mode": "ohmyhost project dev-access mode --project ULID --mode protected|public --idempotency-key KEY --yes --json",
18265
18372
  "project handle check": "ohmyhost project handle check --handle HANDLE --json (is this address free? answers with a reason and free alternatives; the address becomes HANDLE.check.omh.st)",
18266
18373
  "project handle set": "ohmyhost project handle set --project ULID --handle HANDLE --if-match ETAG --idempotency-key KEY --json (moves the project to a free address; the old one stops working and anyone may claim it)",
18267
18374
  "database compute set": "ohmyhost database compute set --project ULID --environment dev|prod --profile standard|performance --idempotency-key KEY --yes [--wait] --json\n standard: Free 0.25 CU/1 GB/60s idle, Paid 0.5 CU/2 GB/60s idle. performance: Paid 1 CU/4 GB/300s idle, 2.5x database compute credits per equal active minute; longer idle time also consumes credits.",
@@ -18282,8 +18389,8 @@ var HELP_USAGE = Object.freeze({
18282
18389
  "domain paid apply": "ohmyhost domain paid apply --project ULID --hostname HOST --idempotency-key KEY --yes --json",
18283
18390
  "domain paid status": "ohmyhost domain paid status --project ULID --json",
18284
18391
  "domain paid delete": "ohmyhost domain paid delete --project ULID --hostname HOST --idempotency-key KEY --yes --json",
18285
- plan: "ohmyhost plan --project ULID --commit SHA --json",
18286
- deploy: "ohmyhost deploy --project ULID --plan-id ULID --idempotency-key KEY --yes [--wait] --json",
18392
+ plan: "ohmyhost plan --project ULID --commit SHA [--environment dev|prod] --json",
18393
+ deploy: "ohmyhost deploy --project ULID (--plan-id ULID | --commit SHA [--environment dev|prod]) --idempotency-key KEY --yes [--wait] --json",
18287
18394
  logs: "ohmyhost logs OPERATION_ULID --follow --json",
18288
18395
  "deployment logs": "ohmyhost deployment logs --project ULID --deployment ULID --follow --json",
18289
18396
  "rollback plan": "ohmyhost rollback plan --project ULID --deployment DEPLOYMENT_ULID --json",
@@ -18305,7 +18412,8 @@ var HELP_USAGE = Object.freeze({
18305
18412
  "mail messages get": "ohmyhost mail messages get --project ULID --environment ULID --message ULID --json",
18306
18413
  "mail messages retry": "ohmyhost mail messages retry --project ULID --environment ULID --message ULID --idempotency-key KEY --json",
18307
18414
  "mail domain set": "ohmyhost mail domain set --project ULID --environment ULID --domain DOMAIN --sending true --receiving false --idempotency-key KEY --json",
18308
- "mail domain status": "ohmyhost mail domain status --project ULID --environment ULID --json"
18415
+ "mail domain status": "ohmyhost mail domain status --project ULID --environment ULID --json",
18416
+ "mail domain delete": "ohmyhost mail domain delete --project ULID --environment ULID --idempotency-key KEY --yes --json"
18309
18417
  });
18310
18418
  var HELP_COMMANDS = Object.freeze(Object.entries(HELP_USAGE).map(([command, usage]) => Object.freeze({ command, usage })));
18311
18419
  var cliMetadataResult = (kind, topic) => kind === "help" ? success("help", {
@@ -18581,12 +18689,17 @@ var ProductCli = class {
18581
18689
  return await this.getProjectStatus(command, signal);
18582
18690
  if (command.kind === "project-dev-access-create")
18583
18691
  return await this.createDevAccessTicket(command, signal);
18692
+ if (command.kind === "project-dev-share-link" || command.kind === "project-dev-share-rotate" || command.kind === "project-dev-share-revoke" || command.kind === "project-dev-access-mode-set") {
18693
+ const api = await this.authenticatedApi(command.credentialStore, signal);
18694
+ const state = parseDevAccessState(command.kind === "project-dev-share-link" ? await api.ensureDevShareLink(command.projectId) : command.kind === "project-dev-share-rotate" ? await api.rotateDevShareLink(command.projectId, command.idempotencyKey) : command.kind === "project-dev-share-revoke" ? await api.revokeDevShareLink(command.projectId, command.idempotencyKey) : await api.setDevAccessMode(command.projectId, command.mode, command.idempotencyKey));
18695
+ return success(command.kind === "project-dev-share-link" ? "project dev-share link" : command.kind === "project-dev-share-rotate" ? "project dev-share rotate" : command.kind === "project-dev-share-revoke" ? "project dev-share revoke" : "project dev-access mode", { status: "succeeded", state });
18696
+ }
18584
18697
  if (command.kind === "database-write") {
18585
18698
  const file = await open2(command.statementFile, "r"), buffer = Buffer.alloc(65537);
18586
18699
  let statement;
18587
18700
  try {
18588
- const stat2 = await file.stat();
18589
- if (!stat2.isFile() || stat2.size > 65536)
18701
+ const stat3 = await file.stat();
18702
+ if (!stat3.isFile() || stat3.size > 65536)
18590
18703
  throw new InvalidCommandError();
18591
18704
  let length = 0;
18592
18705
  while (length < buffer.length) {
@@ -18878,6 +18991,7 @@ var ProductCli = class {
18878
18991
  organizationId: command.organizationId,
18879
18992
  name: command.name,
18880
18993
  ...command.dataMode === void 0 ? {} : { dataMode: command.dataMode },
18994
+ ...command.devAccessMode === void 0 ? {} : { devAccessMode: command.devAccessMode },
18881
18995
  ...command.region === void 0 ? {} : { region: command.region },
18882
18996
  idempotencyKey: command.idempotencyKey
18883
18997
  }));
@@ -19069,7 +19183,10 @@ var ProductCli = class {
19069
19183
  async getAutoDeploy(command, signal) {
19070
19184
  const api = await this.authenticatedApi(command.credentialStore, signal);
19071
19185
  const autoDeploy = await api.getAutoDeploy(command.projectId);
19072
- return success("source auto-deploy status", { status: "ready", auto_deploy: autoDeploy });
19186
+ return success("source auto-deploy status", {
19187
+ status: autoDeploy.generation === 0 ? "not_configured" : "ready",
19188
+ auto_deploy: autoDeploy
19189
+ });
19073
19190
  }
19074
19191
  async authorizeCloudflareDns(command, signal) {
19075
19192
  const api = await this.authenticatedApi(command.credentialStore, signal);
@@ -19103,20 +19220,35 @@ var ProductCli = class {
19103
19220
  async planDeployment(command, signal) {
19104
19221
  const api = await this.authenticatedApi(command.credentialStore, signal);
19105
19222
  const plan = parseDeploymentPlan(await api.planDeployment(command));
19106
- return success("plan", { status: "planned", plan });
19223
+ const notes = plan["environment"] === "prod" ? [
19224
+ `This plan builds straight into Prod (${String(plan["route"])}); Prod traffic switches once it is activated.`
19225
+ ] : [
19226
+ `This plan updates Dev only (${String(plan["route"])}). To go live, deploy with --environment prod or promote the Dev deployment with '${this.dependencies.commandPrefix} deployment promote plan --project ULID --deployment DEV_DEPLOYMENT_ULID --json'.`
19227
+ ];
19228
+ return success("plan", { status: "planned", plan, notes });
19107
19229
  }
19108
19230
  async deploy(command, signal) {
19109
19231
  const api = await this.authenticatedApi(command.credentialStore, signal);
19110
- let operation = parseOperation(await api.createDeployment(command));
19232
+ const plan = command.commitSha === null ? null : parseDeploymentPlan(await api.planDeployment({
19233
+ projectId: command.projectId,
19234
+ commitSha: command.commitSha,
19235
+ environment: command.environment
19236
+ }));
19237
+ let operation = parseOperation(await api.createDeployment({
19238
+ projectId: command.projectId,
19239
+ planId: plan === null ? String(command.planId) : String(plan["id"]),
19240
+ idempotencyKey: command.idempotencyKey
19241
+ }));
19111
19242
  if (command.wait)
19112
19243
  operation = await this.waitForOperation(api, operation, signal);
19113
19244
  const notes = operation.state === "succeeded" ? [
19114
- `A Dev URL answers 404 until you redeem an access ticket: run '${this.dependencies.commandPrefix} project dev-access create --project ULID --json' and open its redeem_url once.`
19245
+ `Check project status for dev_access_mode. For protected Dev, run '${this.dependencies.commandPrefix} project dev-share link --project ULID --json' and open or share its persistent share_url; public Dev opens directly.`
19115
19246
  ] : [];
19116
19247
  return success("deploy", {
19117
19248
  status: command.wait ? "completed" : "accepted",
19118
19249
  operation,
19119
- ...notes.length > 0 ? { notes } : {}
19250
+ ...plan === null ? {} : { plan },
19251
+ ...notes.length > 0 && plan?.["environment"] !== "prod" ? { notes } : {}
19120
19252
  });
19121
19253
  }
19122
19254
  async logs(command, signal) {
@@ -19396,7 +19528,7 @@ var classifyFailure = (command, error, signal) => {
19396
19528
  if (looksLikeProblem(error)) {
19397
19529
  try {
19398
19530
  const problem = parseSafeProblem(error);
19399
- return failure(command, 7, problem.code, problem.retryable, problem.suggestedAction, void 0, problem.retryAfterSeconds, problem.requestId);
19531
+ return failure(command, 7, problem.code, problem.retryable, problem.suggestedAction, void 0, problem.retryAfterSeconds, problem.requestId, problem.docsUrl);
19400
19532
  } catch {
19401
19533
  return failure(command, 7, "response_contract_invalid", false, "Retry only after the client or server contract is repaired.");
19402
19534
  }
@@ -19416,7 +19548,7 @@ var success = (command, body) => ({
19416
19548
  `,
19417
19549
  stderr: ""
19418
19550
  });
19419
- var failure = (command, exitCode, code, retryable, suggestedAction, operation, retryAfterSeconds, requestId) => {
19551
+ var failure = (command, exitCode, code, retryable, suggestedAction, operation, retryAfterSeconds, requestId, docsUrl) => {
19420
19552
  const document = {
19421
19553
  version: 1,
19422
19554
  command,
@@ -19428,6 +19560,7 @@ var failure = (command, exitCode, code, retryable, suggestedAction, operation, r
19428
19560
  suggested_action: suggestedAction,
19429
19561
  ...retryAfterSeconds === void 0 ? {} : { retry_after_seconds: retryAfterSeconds },
19430
19562
  ...requestId === void 0 ? {} : { request_id: requestId },
19563
+ ...docsUrl === void 0 ? {} : { docs_url: docsUrl },
19431
19564
  ...operation?.error === void 0 ? {} : { message: operation.error.message }
19432
19565
  }
19433
19566
  };
@@ -19497,6 +19630,14 @@ var parsedCommandName = (command) => {
19497
19630
  return "project status";
19498
19631
  if (command.kind === "project-dev-access-create")
19499
19632
  return "project dev-access create";
19633
+ if (command.kind === "project-dev-share-link")
19634
+ return "project dev-share link";
19635
+ if (command.kind === "project-dev-share-rotate")
19636
+ return "project dev-share rotate";
19637
+ if (command.kind === "project-dev-share-revoke")
19638
+ return "project dev-share revoke";
19639
+ if (command.kind === "project-dev-access-mode-set")
19640
+ return "project dev-access mode";
19500
19641
  if (command.kind === "project-handle-check")
19501
19642
  return "project handle check";
19502
19643
  if (command.kind === "project-handle-set")
@@ -21046,6 +21187,83 @@ var getProjectHandleAvailability = (parameters, options) => {
21046
21187
  ...params
21047
21188
  });
21048
21189
  };
21190
+ var revokeProjectDevShareLink = (parameters, options) => {
21191
+ const params = buildClientParams([parameters], [
21192
+ {
21193
+ args: [
21194
+ { in: "headers", key: "X-Request-Id" },
21195
+ { in: "headers", key: "Idempotency-Key" },
21196
+ { in: "path", key: "project_id" }
21197
+ ]
21198
+ }
21199
+ ]);
21200
+ return (options?.client ?? client).delete({
21201
+ responseStyle: "data",
21202
+ security: [{ scheme: "bearer", type: "http" }],
21203
+ url: "/v1/projects/{project_id}/dev-share-link",
21204
+ ...options,
21205
+ ...params
21206
+ });
21207
+ };
21208
+ var ensureProjectDevShareLink = (parameters, options) => {
21209
+ const params = buildClientParams([parameters], [
21210
+ {
21211
+ args: [
21212
+ { in: "headers", key: "X-Request-Id" },
21213
+ { in: "path", key: "project_id" }
21214
+ ]
21215
+ }
21216
+ ]);
21217
+ return (options?.client ?? client).post({
21218
+ responseStyle: "data",
21219
+ security: [{ scheme: "bearer", type: "http" }],
21220
+ url: "/v1/projects/{project_id}/dev-share-link",
21221
+ ...options,
21222
+ ...params
21223
+ });
21224
+ };
21225
+ var rotateProjectDevShareLink = (parameters, options) => {
21226
+ const params = buildClientParams([parameters], [
21227
+ {
21228
+ args: [
21229
+ { in: "headers", key: "X-Request-Id" },
21230
+ { in: "headers", key: "Idempotency-Key" },
21231
+ { in: "path", key: "project_id" }
21232
+ ]
21233
+ }
21234
+ ]);
21235
+ return (options?.client ?? client).post({
21236
+ responseStyle: "data",
21237
+ security: [{ scheme: "bearer", type: "http" }],
21238
+ url: "/v1/projects/{project_id}/dev-share-link:rotate",
21239
+ ...options,
21240
+ ...params
21241
+ });
21242
+ };
21243
+ var setProjectDevAccessMode = (parameters, options) => {
21244
+ const params = buildClientParams([parameters], [
21245
+ {
21246
+ args: [
21247
+ { in: "headers", key: "X-Request-Id" },
21248
+ { in: "headers", key: "Idempotency-Key" },
21249
+ { in: "path", key: "project_id" },
21250
+ { key: "setDevAccessModeRequest", map: "body" }
21251
+ ]
21252
+ }
21253
+ ]);
21254
+ return (options?.client ?? client).put({
21255
+ responseStyle: "data",
21256
+ security: [{ scheme: "bearer", type: "http" }],
21257
+ url: "/v1/projects/{project_id}/dev-access-mode",
21258
+ ...options,
21259
+ ...params,
21260
+ headers: {
21261
+ "Content-Type": "application/json",
21262
+ ...options?.headers,
21263
+ ...params.headers
21264
+ }
21265
+ });
21266
+ };
21049
21267
  var createProjectDevAccessTicket = (parameters, options) => {
21050
21268
  const params = buildClientParams([parameters], [
21051
21269
  {
@@ -21783,6 +22001,25 @@ var streamOperationEvents = (parameters, options) => {
21783
22001
  ...params
21784
22002
  });
21785
22003
  };
22004
+ var deleteManagedMailDomain = (parameters, options) => {
22005
+ const params = buildClientParams([parameters], [
22006
+ {
22007
+ args: [
22008
+ { in: "headers", key: "X-Request-Id" },
22009
+ { in: "headers", key: "Idempotency-Key" },
22010
+ { in: "path", key: "project_id" },
22011
+ { in: "path", key: "environment_id" }
22012
+ ]
22013
+ }
22014
+ ]);
22015
+ return (options?.client ?? client).delete({
22016
+ responseStyle: "data",
22017
+ security: [{ scheme: "bearer", type: "http" }],
22018
+ url: "/v1/projects/{project_id}/environments/{environment_id}/mail-domain",
22019
+ ...options,
22020
+ ...params
22021
+ });
22022
+ };
21786
22023
  var getManagedMailDomain = (parameters, options) => {
21787
22024
  const params = buildClientParams([parameters], [
21788
22025
  {
@@ -22009,6 +22246,14 @@ function assertManagedMailResponse(value, input) {
22009
22246
  invalid3();
22010
22247
  return;
22011
22248
  }
22249
+ if (input.action === "domain_delete") {
22250
+ exact3(r, ["status", "domain", "dns_records"]);
22251
+ if (r["status"] !== "deleted")
22252
+ invalid3();
22253
+ domain(r["domain"]);
22254
+ records(r["dns_records"]);
22255
+ return;
22256
+ }
22012
22257
  if (input.action === "messages_list") {
22013
22258
  exact3(r, ["items"]);
22014
22259
  if (!Array.isArray(r["items"]) || r["items"].length > 50)
@@ -22137,6 +22382,8 @@ function requestManagedMail(client2, input) {
22137
22382
  return verifyManagedMailWebhook({ ...scope, "Idempotency-Key": input.idempotencyKey }, { client: client2 });
22138
22383
  case "webhook_disable":
22139
22384
  return disableManagedMailReceiving({ ...scope, "Idempotency-Key": input.idempotencyKey }, { client: client2 });
22385
+ case "domain_delete":
22386
+ return deleteManagedMailDomain({ ...scope, "Idempotency-Key": input.idempotencyKey }, { client: client2 });
22140
22387
  case "messages_list":
22141
22388
  return listManagedMailMessages({ ...scope, ...input.after ? { after: input.after } : {} }, { client: client2 });
22142
22389
  case "message_get":
@@ -22376,6 +22623,22 @@ var GeneratedSdkProductApi = class {
22376
22623
  paidDomainRequest: { hostname: input.hostname }
22377
22624
  }, { client: this.#client });
22378
22625
  }
22626
+ async ensureDevShareLink(projectId) {
22627
+ return ensureProjectDevShareLink({ project_id: projectId }, { client: this.#client });
22628
+ }
22629
+ async rotateDevShareLink(projectId, idempotencyKey) {
22630
+ return rotateProjectDevShareLink({ project_id: projectId, "Idempotency-Key": idempotencyKey }, { client: this.#client });
22631
+ }
22632
+ async revokeDevShareLink(projectId, idempotencyKey) {
22633
+ return revokeProjectDevShareLink({ project_id: projectId, "Idempotency-Key": idempotencyKey }, { client: this.#client });
22634
+ }
22635
+ async setDevAccessMode(projectId, mode, idempotencyKey) {
22636
+ return setProjectDevAccessMode({
22637
+ project_id: projectId,
22638
+ "Idempotency-Key": idempotencyKey,
22639
+ setDevAccessModeRequest: { mode }
22640
+ }, { client: this.#client });
22641
+ }
22379
22642
  async createDevAccessTicket(projectId) {
22380
22643
  return createProjectDevAccessTicket({ project_id: projectId }, { client: this.#client });
22381
22644
  }
@@ -22389,6 +22652,7 @@ var GeneratedSdkProductApi = class {
22389
22652
  organization_id: input.organizationId,
22390
22653
  name: input.name,
22391
22654
  ...input.dataMode === void 0 ? {} : { data_mode: input.dataMode },
22655
+ ...input.devAccessMode === void 0 ? {} : { dev_access_mode: input.devAccessMode },
22392
22656
  ...input.region === void 0 ? {} : { region: input.region }
22393
22657
  }
22394
22658
  }, { client: this.#client });
@@ -22446,7 +22710,10 @@ var GeneratedSdkProductApi = class {
22446
22710
  return configureProjectDomains({ "Idempotency-Key": input.idempotencyKey, project_id: input.projectId }, { client: this.#client });
22447
22711
  }
22448
22712
  async planDeployment(input) {
22449
- return planDeployment({ project_id: input.projectId, planDeploymentRequest: { commit_sha: input.commitSha } }, { client: this.#client });
22713
+ return planDeployment({
22714
+ project_id: input.projectId,
22715
+ planDeploymentRequest: { commit_sha: input.commitSha, environment: input.environment }
22716
+ }, { client: this.#client });
22450
22717
  }
22451
22718
  async createDeployment(input) {
22452
22719
  return createDeployment({
@@ -22536,12 +22803,26 @@ var GeneratedSdkProductApi = class {
22536
22803
  };
22537
22804
 
22538
22805
  // apps/product-cli/dist/project-link-store.js
22539
- import { chmod, mkdir as mkdir2, rename, writeFile } from "node:fs/promises";
22806
+ import { appendFile, chmod, mkdir as mkdir2, readFile, rename, stat, writeFile } from "node:fs/promises";
22540
22807
  import { join } from "node:path";
22808
+ async function readLinkedProjectId(directory, apiOrigin) {
22809
+ try {
22810
+ const link = JSON.parse(await readFile(join(directory, "link.json"), "utf8"));
22811
+ if (typeof link !== "object" || link === null)
22812
+ return null;
22813
+ const { version: version2, api_origin, project_id } = link;
22814
+ return version2 === 1 && api_origin === apiOrigin && typeof project_id === "string" && /^[0-9A-HJKMNP-TV-Z]{26}$/u.test(project_id) ? project_id : null;
22815
+ } catch {
22816
+ return null;
22817
+ }
22818
+ }
22541
22819
  var OwnerOnlyProjectLinkStore = class {
22542
22820
  directory;
22543
- constructor(directory) {
22821
+ repositoryRoot;
22822
+ /** repositoryRoot: when it is a Git working tree, the link directory is kept out of Git. */
22823
+ constructor(directory, repositoryRoot) {
22544
22824
  this.directory = directory;
22825
+ this.repositoryRoot = repositoryRoot;
22545
22826
  }
22546
22827
  async save(metadata) {
22547
22828
  await mkdir2(this.directory, { mode: 448, recursive: true });
@@ -22553,12 +22834,33 @@ var OwnerOnlyProjectLinkStore = class {
22553
22834
  await chmod(temporary, 384);
22554
22835
  await rename(temporary, target);
22555
22836
  await chmod(target, 384);
22837
+ if (this.repositoryRoot !== void 0)
22838
+ await ignoreLinkDirectory(this.repositoryRoot);
22556
22839
  }
22557
22840
  };
22841
+ async function ignoreLinkDirectory(root) {
22842
+ try {
22843
+ await stat(join(root, ".git"));
22844
+ } catch {
22845
+ return;
22846
+ }
22847
+ const file = join(root, ".gitignore");
22848
+ let current = "";
22849
+ try {
22850
+ current = await readFile(file, "utf8");
22851
+ } catch {
22852
+ current = "";
22853
+ }
22854
+ const lines = current.split(/\r?\n/u).map((line) => line.trim());
22855
+ if (lines.some((line) => /^\/?\.ohmyhost\/?$/u.test(line)))
22856
+ return;
22857
+ await appendFile(file, `${current === "" || current.endsWith("\n") ? "" : "\n"}/.ohmyhost/
22858
+ `);
22859
+ }
22558
22860
 
22559
22861
  // apps/product-cli/dist/repository-init.js
22560
22862
  import { createHash } from "node:crypto";
22561
- import { lstat as lstat2, open as open3, readFile, readdir, stat } from "node:fs/promises";
22863
+ import { lstat as lstat2, open as open3, readFile as readFile2, readdir, stat as stat2 } from "node:fs/promises";
22562
22864
  import { dirname as dirname2, posix, resolve as resolve2 } from "node:path";
22563
22865
 
22564
22866
  // packages/contracts/dist/application-root.js
@@ -23440,7 +23742,7 @@ async function initializeRepository(input) {
23440
23742
  })
23441
23743
  });
23442
23744
  const targetBetterAuth = existingConfiguration?.auth?.provider === "better-auth";
23443
- const targetMail = targetBetterAuth || existingConfiguration?.mail?.enabled === true;
23745
+ const targetMail = existingConfiguration?.mail?.enabled === true;
23444
23746
  const targetStorage = r2 || supabaseStorage;
23445
23747
  const configuredCompanionRequired = existingConfiguration !== null && (existingConfiguration.database?.enabled === true || existingConfiguration.auth?.provider === "better-auth" || existingConfiguration.mail?.enabled === true || existingConfiguration.storage !== void 0 || (existingConfiguration.functions?.crons.length ?? 0) > 0);
23446
23748
  const companionRequired = framework === "vite" && (existingConfiguration === null ? databaseProvider !== "none" || targetBetterAuth || targetMail || targetStorage || edgeFunctionNames.size > 0 || applicationFiles.includes("src/ohmyhost/companion.ts") : configuredCompanionRequired);
@@ -23526,7 +23828,7 @@ async function cronBlockers(framework, config, applicationDirectory, files) {
23526
23828
  ];
23527
23829
  }
23528
23830
  const modulePath = framework === "vite" ? "src/ohmyhost/companion.ts" : WORKER_MODULE_PATH;
23529
- const source = files.includes(modulePath) ? await readFile(resolve2(applicationDirectory, modulePath), "utf8") : null;
23831
+ const source = files.includes(modulePath) ? await readFile2(resolve2(applicationDirectory, modulePath), "utf8") : null;
23530
23832
  if (framework !== "functions" && source !== null && !DEFAULT_EXPORT_PATTERN.test(source)) {
23531
23833
  return [defaultExportBlocker(modulePath)];
23532
23834
  }
@@ -23547,10 +23849,10 @@ async function storageClientBlockers(config, applicationDirectory, files) {
23547
23849
  if (!SOURCE_MODULE_PATTERN.test(path))
23548
23850
  continue;
23549
23851
  const absolute = resolve2(applicationDirectory, path);
23550
- const information = await stat(absolute);
23852
+ const information = await stat2(absolute);
23551
23853
  if (!information.isFile() || information.size > MAXIMUM_SOURCE_BYTES)
23552
23854
  continue;
23553
- if (callsStorageClient(await readFile(absolute, "utf8")))
23855
+ if (callsStorageClient(await readFile2(absolute, "utf8")))
23554
23856
  return [];
23555
23857
  }
23556
23858
  return [
@@ -23568,10 +23870,10 @@ async function databaseContractBlockers(config, applicationDirectory, files) {
23568
23870
  if (!SOURCE_MODULE_PATTERN.test(path))
23569
23871
  continue;
23570
23872
  const absolute = resolve2(applicationDirectory, path);
23571
- const information = await stat(absolute);
23873
+ const information = await stat2(absolute);
23572
23874
  if (!information.isFile() || information.size > MAXIMUM_SOURCE_BYTES)
23573
23875
  continue;
23574
- const source = (await readFile(absolute, "utf8")).replaceAll(INERT_SOURCE_PATTERN, " ");
23876
+ const source = (await readFile2(absolute, "utf8")).replaceAll(INERT_SOURCE_PATTERN, " ");
23575
23877
  if (DATABASE_PRIVATE_BINDING_PATTERN.test(source)) {
23576
23878
  blockers.push({
23577
23879
  code: "database_binding_private",
@@ -23590,7 +23892,7 @@ async function databaseContractBlockers(config, applicationDirectory, files) {
23590
23892
  async function workerModuleBlockers(framework, applicationDirectory, files) {
23591
23893
  if (framework !== "functions" || !files.includes(WORKER_MODULE_PATH))
23592
23894
  return [];
23593
- const source = await readFile(resolve2(applicationDirectory, WORKER_MODULE_PATH), "utf8");
23895
+ const source = await readFile2(resolve2(applicationDirectory, WORKER_MODULE_PATH), "utf8");
23594
23896
  return DEFAULT_EXPORT_PATTERN.test(source) ? [] : [defaultExportBlocker(WORKER_MODULE_PATH)];
23595
23897
  }
23596
23898
  function migrationFilenameBlockers(files, configuredPath, provider) {
@@ -23617,7 +23919,7 @@ async function migrationSqlBlockers(applicationDirectory, files, configuredPath,
23617
23919
  }
23618
23920
  const migrations = await Promise.all(migrationPaths.map(async (path) => Object.freeze({
23619
23921
  path,
23620
- body: new Uint8Array(await readFile(resolve2(applicationDirectory, root, path)))
23922
+ body: new Uint8Array(await readFile2(resolve2(applicationDirectory, root, path)))
23621
23923
  })));
23622
23924
  const blockers = [];
23623
23925
  for (const migration of migrations) {
@@ -23652,11 +23954,11 @@ async function readExistingConfiguration(repositoryRoot, repositoryFiles, applic
23652
23954
  if (!repositoryFiles.includes("ohmyhost.yaml"))
23653
23955
  return null;
23654
23956
  const configurationPath = resolve2(repositoryRoot, "ohmyhost.yaml");
23655
- const information = await stat(configurationPath);
23957
+ const information = await stat2(configurationPath);
23656
23958
  if (!information.isFile() || information.size > MAXIMUM_CONFIGURATION_BYTES) {
23657
23959
  throw new RepositoryInitError("repository_configuration_invalid", "Existing ohmyhost.yaml must be one bounded regular file.");
23658
23960
  }
23659
- const configuration = await readFile(configurationPath, "utf8");
23961
+ const configuration = await readFile2(configurationPath, "utf8");
23660
23962
  let parsed;
23661
23963
  try {
23662
23964
  parsed = parseOhmyhostConfigYaml(configuration);
@@ -23857,7 +24159,7 @@ async function readPackageJson(root) {
23857
24159
  const path = resolve2(root, "package.json");
23858
24160
  let information;
23859
24161
  try {
23860
- information = await stat(path);
24162
+ information = await stat2(path);
23861
24163
  } catch {
23862
24164
  throw new RepositoryInitError("package_manifest_missing", "package.json is required");
23863
24165
  }
@@ -23865,7 +24167,7 @@ async function readPackageJson(root) {
23865
24167
  throw new RepositoryInitError("package_manifest_invalid", "package.json is invalid");
23866
24168
  }
23867
24169
  try {
23868
- const value = JSON.parse(await readFile(path, "utf8"));
24170
+ const value = JSON.parse(await readFile2(path, "utf8"));
23869
24171
  if (!isRecord2(value))
23870
24172
  throw new TypeError();
23871
24173
  return value;
@@ -24127,10 +24429,10 @@ async function detectNextStandaloneOutput(root, framework, nextConfigPath) {
24127
24429
  if (framework !== "nextjs" || nextConfigPath === null)
24128
24430
  return false;
24129
24431
  const path = resolve2(root, nextConfigPath);
24130
- const information = await stat(path);
24432
+ const information = await stat2(path);
24131
24433
  if (!information.isFile() || information.size > MAXIMUM_CONFIGURATION_BYTES)
24132
24434
  return false;
24133
- return declaresStandaloneOutput(await readFile(path, "utf8"));
24435
+ return declaresStandaloneOutput(await readFile2(path, "utf8"));
24134
24436
  }
24135
24437
  function declaresStandaloneOutput(source) {
24136
24438
  const tokens = sourceTokens(source);
@@ -24196,10 +24498,10 @@ async function detectTanStackRuntime(root, files, framework, packageJson, viteCo
24196
24498
  if (viteConfigPath === null)
24197
24499
  return "ambiguous";
24198
24500
  const path = resolve2(root, viteConfigPath);
24199
- const information = await stat(path);
24501
+ const information = await stat2(path);
24200
24502
  if (!information.isFile() || information.size > MAXIMUM_PACKAGE_BYTES)
24201
24503
  return "ambiguous";
24202
- const source = await readFile(path, "utf8");
24504
+ const source = await readFile2(path, "utf8");
24203
24505
  const tokens = sourceTokens(source);
24204
24506
  if (isCompleteTanStackStatic(tokens))
24205
24507
  return "static";
@@ -24305,10 +24607,10 @@ async function detectR2Storage(root, files) {
24305
24607
  const configs = files.filter((path) => /(?:^|\/)wrangler\.(?:jsonc?|toml)$/u.test(path));
24306
24608
  for (const config of configs) {
24307
24609
  const path = resolve2(root, config);
24308
- const information = await stat(path);
24610
+ const information = await stat2(path);
24309
24611
  if (!information.isFile() || information.size > MAXIMUM_CONFIGURATION_BYTES)
24310
24612
  continue;
24311
- const source = await readFile(path, "utf8");
24613
+ const source = await readFile2(path, "utf8");
24312
24614
  if (/\br2_buckets\b/u.test(source))
24313
24615
  return true;
24314
24616
  }
@@ -24661,7 +24963,14 @@ var runProductionCli = async (argv, environment, io, signal, overrides = {}) =>
24661
24963
  const diagnostics = new StderrDiagnosticSink(io);
24662
24964
  let command;
24663
24965
  try {
24664
- command = parseProductCliCommand(argv);
24966
+ const parsed = await parseWithLinkedProject(argv, async () => {
24967
+ const profile2 = resolveProductCliEnvironment(environment);
24968
+ return readLinkedProjectId(join2(overrides.workingDirectory ?? process.cwd(), profile2.linkDirectory), profile2.apiOrigin);
24969
+ });
24970
+ command = parsed.command;
24971
+ if (parsed.linkedProjectId !== null)
24972
+ io.writeStderr(`ohmyhost: using linked project ${parsed.linkedProjectId}
24973
+ `);
24665
24974
  } catch (error) {
24666
24975
  const result2 = error instanceof InvalidCommandError ? invalidCommandFailure(recognizedCommandLabel(argv)) : errorDocument("unknown", 1, "internal_error", false, "Retry the command.");
24667
24976
  if (!(error instanceof InvalidCommandError)) {
@@ -24739,7 +25048,7 @@ var runProductionCli = async (argv, environment, io, signal, overrides = {}) =>
24739
25048
  }),
24740
25049
  signal
24741
25050
  }),
24742
- projectLinkStore: new OwnerOnlyProjectLinkStore(join2(process.cwd(), profile.linkDirectory)),
25051
+ projectLinkStore: new OwnerOnlyProjectLinkStore(join2(process.cwd(), profile.linkDirectory), process.cwd()),
24743
25052
  productApiOrigin: profile.apiOrigin,
24744
25053
  tokenRefresher: new PublicWorkosTokenRefresher(environment),
24745
25054
  tokenRevoker: lifecycle,
@@ -24925,6 +25234,30 @@ var GeneratedSdkSessionRevoker = class {
24925
25234
  }
24926
25235
  }
24927
25236
  };
25237
+ async function parseWithLinkedProject(argv, linkedProjectId) {
25238
+ try {
25239
+ return { command: parseProductCliCommand(argv), linkedProjectId: null };
25240
+ } catch (error) {
25241
+ if (!(error instanceof InvalidCommandError) || argv.includes("--project"))
25242
+ throw error;
25243
+ let projectId;
25244
+ try {
25245
+ projectId = await linkedProjectId();
25246
+ } catch {
25247
+ projectId = null;
25248
+ }
25249
+ if (projectId === null)
25250
+ throw error;
25251
+ try {
25252
+ return {
25253
+ command: parseProductCliCommand([...argv, "--project", projectId]),
25254
+ linkedProjectId: projectId
25255
+ };
25256
+ } catch {
25257
+ throw error;
25258
+ }
25259
+ }
25260
+ }
24928
25261
  var StderrDiagnosticSink = class {
24929
25262
  io;
24930
25263
  constructor(io) {
@@ -25133,6 +25466,7 @@ export {
25133
25466
  parsePaidDomain,
25134
25467
  parseCloudflareDnsAuthorization,
25135
25468
  parseCloudflareDnsAuthorizationStatus,
25469
+ parseDevAccessState,
25136
25470
  parseDevAccessTicket,
25137
25471
  parseCurrentIdentity,
25138
25472
  parseAccountProfile,
@@ -25149,6 +25483,7 @@ export {
25149
25483
  cliMetadataResult,
25150
25484
  ProductCli,
25151
25485
  GeneratedSdkProductApi,
25486
+ readLinkedProjectId,
25152
25487
  OwnerOnlyProjectLinkStore,
25153
25488
  RepositoryInitError,
25154
25489
  RepositoryInitBlockedError,
@@ -25162,6 +25497,7 @@ export {
25162
25497
  StderrDeviceAuthorizationPresenter,
25163
25498
  PublicWorkosTokenRefresher,
25164
25499
  GeneratedSdkSessionRevoker,
25500
+ parseWithLinkedProject,
25165
25501
  readBoundedResponseBody,
25166
25502
  createBoundedFetch,
25167
25503
  readSecretValueFromStandardInput