gigadrive 2.6.2 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command15 } from "@effect/cli";
4
+ import { Command as Command16 } from "@effect/cli";
5
5
  import { NodeContext, NodeRuntime } from "@effect/platform-node";
6
6
  import { NetworkConfigLive as NetworkConfigLive2 } from "@gigadrive/network-config";
7
- import { Effect as Effect27, Layer, LogLevel, Logger } from "effect";
7
+ import { Effect as Effect28, Layer, LogLevel, Logger } from "effect";
8
8
 
9
9
  // package.json
10
10
  var package_default = {
11
11
  name: "gigadrive",
12
- version: "2.6.2",
12
+ version: "2.7.1",
13
13
  repository: {
14
14
  type: "git",
15
15
  url: "https://github.com/Gigadrive/sdk.git",
@@ -126,7 +126,9 @@ var UserInfoFetchError = class extends Schema.TaggedError()("UserInfoFetchError"
126
126
  var ApiRequestError = class extends Schema.TaggedError()("ApiRequestError", {
127
127
  message: Schema.String,
128
128
  statusCode: Schema.optional(Schema.Number),
129
- code: Schema.optional(Schema.String)
129
+ code: Schema.optional(Schema.String),
130
+ /** Finer-grained reason next to `code`, for example `daily_add_limit`. */
131
+ reason: Schema.optional(Schema.String)
130
132
  }) {
131
133
  };
132
134
  var InvalidEnvVarFormatError = class extends Schema.TaggedError()(
@@ -140,6 +142,30 @@ var EnvVarNotFoundError = class extends Schema.TaggedError()("EnvVarNotFoundErro
140
142
  message: Schema.String
141
143
  }) {
142
144
  };
145
+ var DomainNotFoundError = class extends Schema.TaggedError()("DomainNotFoundError", {
146
+ message: Schema.String
147
+ }) {
148
+ };
149
+ var DomainWaitError = class extends Schema.TaggedError()("DomainWaitError", {
150
+ message: Schema.String,
151
+ state: Schema.String
152
+ }) {
153
+ };
154
+ var InvalidDomainOptionsError = class extends Schema.TaggedError()(
155
+ "InvalidDomainOptionsError",
156
+ { message: Schema.String }
157
+ ) {
158
+ };
159
+ var ConfirmationRequiredError = class extends Schema.TaggedError()(
160
+ "ConfirmationRequiredError",
161
+ { message: Schema.String }
162
+ ) {
163
+ };
164
+ var OrganizationRequiredError = class extends Schema.TaggedError()(
165
+ "OrganizationRequiredError",
166
+ { message: Schema.String }
167
+ ) {
168
+ };
143
169
  var NoApplicationsFoundError = class extends Schema.TaggedError()(
144
170
  "NoApplicationsFoundError",
145
171
  {
@@ -941,7 +967,12 @@ var ServiceCredentials = Config2.all({
941
967
  });
942
968
  var toApiRequestError = (error) => {
943
969
  if (error instanceof ApiError) {
944
- return new ApiRequestError({ message: error.message, statusCode: error.status, code: error.code });
970
+ return new ApiRequestError({
971
+ message: error.message,
972
+ statusCode: error.status,
973
+ code: error.code,
974
+ reason: error.reason
975
+ });
945
976
  }
946
977
  return new ApiRequestError({ message: error instanceof Error ? error.message : String(error) });
947
978
  };
@@ -1575,6 +1606,7 @@ import { Console as Console5, Effect as Effect11 } from "effect";
1575
1606
 
1576
1607
  // src/services/project-config.ts
1577
1608
  import {
1609
+ detectContainerProject,
1578
1610
  detectFramework,
1579
1611
  mergeWithFrameworkDefaults,
1580
1612
  NetworkConfigLive,
@@ -1592,7 +1624,8 @@ var wrapParseErrors = (effect) => effect.pipe(
1592
1624
  ConfigModuleLoadError: (e) => Effect10.fail(new ConfigParseError({ message: e.message, cause: e.cause ?? e.filePath })),
1593
1625
  ConfigVersionError: (e) => Effect10.fail(new ConfigParseError({ message: e.message, cause: e.filePath })),
1594
1626
  ConfigSchemaValidationError: (e) => Effect10.fail(new ConfigParseError({ message: e.message, cause: e.validationErrors.join(", ") })),
1595
- FunctionConfigError: (e) => Effect10.fail(new ConfigParseError({ message: e.message, cause: e.functionPath }))
1627
+ FunctionConfigError: (e) => Effect10.fail(new ConfigParseError({ message: e.message, cause: e.functionPath })),
1628
+ ContainerConfigError: (e) => Effect10.fail(new ConfigParseError({ message: e.message, cause: e.filePath ?? e.containerName }))
1596
1629
  })
1597
1630
  );
1598
1631
  var ProjectConfigService = class extends Effect10.Service()("ProjectConfigService", {
@@ -1639,12 +1672,18 @@ var ProjectConfigService = class extends Effect10.Service()("ProjectConfigServic
1639
1672
  config = yield* wrapParseErrors(postProcessConfig(detection.config, cwd));
1640
1673
  framework = { name: detection.framework.name, slug: detection.framework.slug };
1641
1674
  } else {
1642
- return yield* Effect10.fail(
1643
- new ConfigNotFoundError({
1644
- message: "No config file found and no framework detected.",
1645
- directory: cwd
1646
- })
1675
+ const containerProject = yield* wrapParseErrors(
1676
+ detectContainerProject(cwd).pipe(Effect10.map((result) => result?.config ?? null))
1647
1677
  );
1678
+ if (containerProject === null) {
1679
+ return yield* Effect10.fail(
1680
+ new ConfigNotFoundError({
1681
+ message: "No config file, framework, Compose file or Dockerfile found.",
1682
+ directory: cwd
1683
+ })
1684
+ );
1685
+ }
1686
+ config = yield* wrapParseErrors(postProcessConfig(containerProject, cwd));
1648
1687
  }
1649
1688
  for (const warning of config.warnings) {
1650
1689
  yield* Effect10.logWarning(warning);
@@ -1784,13 +1823,553 @@ var deploymentsCommand = deploymentsBase.pipe(
1784
1823
  Command6.withSubcommands([deploymentsListCommand, deploymentsInspectCommand])
1785
1824
  );
1786
1825
 
1787
- // src/commands/env/index.ts
1826
+ // src/commands/domains/index.ts
1788
1827
  import { Args as Args3, Command as Command7, Options as Options4, Prompt } from "@effect/cli";
1789
- import { Console as Console7, Effect as Effect17, Option as Option11 } from "effect";
1828
+ import { Clock, Console as Console7, Duration as Duration2, Effect as Effect14, Either, Option as Option8 } from "effect";
1829
+
1830
+ // src/lib/domain-output.ts
1831
+ var DOMAIN_STATE_LABELS = {
1832
+ pending_ownership: "verifying ownership",
1833
+ pending_dns: "waiting for DNS",
1834
+ issuing_certificate: "issuing certificate",
1835
+ active: "active",
1836
+ degraded: "needs attention",
1837
+ failed: "failed",
1838
+ suspended: "suspended",
1839
+ removing: "removing"
1840
+ };
1841
+ var RECORD_STATUS_LABELS = {
1842
+ ok: "found",
1843
+ pending: "waiting",
1844
+ mismatch: "different value"
1845
+ };
1846
+ var IN_PROGRESS_STATES = /* @__PURE__ */ new Set([
1847
+ "pending_ownership",
1848
+ "pending_dns",
1849
+ "issuing_certificate"
1850
+ ]);
1851
+ var formatDnsRecords = (records) => {
1852
+ if (records.length === 0) return [];
1853
+ const rows = [
1854
+ ["Type", "Name", "Value", "Status"],
1855
+ ...records.map((record) => [record.type, record.host, record.value, RECORD_STATUS_LABELS[record.status]])
1856
+ ];
1857
+ const widths = [0, 1, 2].map((column) => Math.max(...rows.map((row) => row[column].length)));
1858
+ return rows.map(
1859
+ (row) => row.map((cell, column) => column < widths.length ? cell.padEnd(widths[column]) : cell).join(" ").trimEnd()
1860
+ );
1861
+ };
1862
+ var describeDomain = (domain) => {
1863
+ const lines = [
1864
+ `${domain.unicodeHostname} ${DOMAIN_STATE_LABELS[domain.state]}${domain.primary ? " (primary)" : ""}`
1865
+ ];
1866
+ if (domain.target.type === "redirect" && domain.target.redirectTo !== null) {
1867
+ lines.push(`Redirects to ${domain.target.redirectTo} (${domain.target.redirectStatusCode ?? 308})`);
1868
+ } else if (domain.target.type === "branch") {
1869
+ lines.push(`Serves branch ${domain.target.branchId ?? "unknown"}`);
1870
+ }
1871
+ if (domain.error !== null) lines.push(`Problem (${domain.error.code}): ${domain.error.message}`);
1872
+ if (domain.certificate.expiresAt !== null) lines.push(`Certificate expires ${domain.certificate.expiresAt}`);
1873
+ return lines;
1874
+ };
1875
+
1876
+ // src/commands/domains/index.ts
1877
+ var REDIRECT_STATUS_CODES = ["301", "302", "307", "308"];
1878
+ var CONSOLE_URL = "https://console.gigadrive.de";
1879
+ var POLL_INTERVAL = Duration2.seconds(5);
1880
+ var appOption3 = Options4.text("app").pipe(
1881
+ Options4.withAlias("a"),
1882
+ Options4.withDescription("Operate on this application (overrides the linked application)"),
1883
+ Options4.optional
1884
+ );
1885
+ var orgOption3 = Options4.text("org").pipe(
1886
+ Options4.withAlias("o"),
1887
+ Options4.withDescription("Operate on this organization (defaults to the linked project\u2019s organization)"),
1888
+ Options4.optional
1889
+ );
1890
+ var jsonOption = Options4.boolean("json").pipe(
1891
+ Options4.withDescription("Print only the result as JSON on stdout; progress goes to stderr")
1892
+ );
1893
+ var waitOption = Options4.boolean("wait").pipe(
1894
+ Options4.withAlias("w"),
1895
+ Options4.withDescription("Wait until the domain serves traffic, printing each state change")
1896
+ );
1897
+ var timeoutOption = Options4.integer("timeout").pipe(
1898
+ Options4.withDescription("Minutes to wait with --wait, at least 1 (default: 10)"),
1899
+ Options4.withDefault(10)
1900
+ );
1901
+ var branchOption = Options4.text("branch").pipe(
1902
+ Options4.withDescription("Serve the latest deployment of this branch ID instead of production"),
1903
+ Options4.optional
1904
+ );
1905
+ var productionOption = Options4.boolean("production").pipe(
1906
+ Options4.withDescription("Serve the production deployment (the default for new domains)")
1907
+ );
1908
+ var redirectToOption = Options4.text("redirect-to").pipe(
1909
+ Options4.withDescription("Redirect every request to this hostname instead of serving the application"),
1910
+ Options4.optional
1911
+ );
1912
+ var statusOption2 = Options4.choice("status", REDIRECT_STATUS_CODES).pipe(
1913
+ Options4.withDescription("Redirect status code with --redirect-to (default: 308)"),
1914
+ Options4.optional
1915
+ );
1916
+ var dropPathOption = Options4.boolean("drop-path").pipe(
1917
+ Options4.withDescription("With --redirect-to, redirect to the root instead of keeping the path and query")
1918
+ );
1919
+ var primaryOption = Options4.boolean("primary").pipe(
1920
+ Options4.withDescription("Make this domain the application\u2019s primary URL")
1921
+ );
1922
+ var yesOption = Options4.boolean("yes").pipe(
1923
+ Options4.withAlias("y"),
1924
+ Options4.withDescription("Skip the confirmation prompt (required when not running in a terminal)")
1925
+ );
1926
+ var hostnameArg = Args3.text({ name: "hostname" }).pipe(
1927
+ Args3.withDescription("Hostname to attach, e.g. shop.example.com or example.com")
1928
+ );
1929
+ var domainArg = Args3.text({ name: "hostname-or-id" }).pipe(Args3.withDescription("Domain hostname or ID"));
1930
+ var targetFromFlags = (flags) => Effect14.gen(function* () {
1931
+ const chosen = [flags.production, Option8.isSome(flags.branch), Option8.isSome(flags.redirectTo)].filter(Boolean);
1932
+ if (chosen.length > 1) {
1933
+ return yield* new InvalidDomainOptionsError({
1934
+ message: "Choose one target: --production, --branch or --redirect-to."
1935
+ });
1936
+ }
1937
+ if (Option8.isNone(flags.redirectTo) && (Option8.isSome(flags.status) || flags.dropPath)) {
1938
+ return yield* new InvalidDomainOptionsError({
1939
+ message: "--status and --drop-path only apply together with --redirect-to."
1940
+ });
1941
+ }
1942
+ if (Option8.isSome(flags.redirectTo)) {
1943
+ const target = {
1944
+ type: "redirect",
1945
+ to: flags.redirectTo.value,
1946
+ statusCode: Option8.match(flags.status, {
1947
+ onNone: () => void 0,
1948
+ onSome: (code) => code === "301" ? 301 : code === "302" ? 302 : code === "307" ? 307 : 308
1949
+ }),
1950
+ preservePath: !flags.dropPath
1951
+ };
1952
+ return target;
1953
+ }
1954
+ if (Option8.isSome(flags.branch)) {
1955
+ const target = { type: "branch", branchId: flags.branch.value };
1956
+ return target;
1957
+ }
1958
+ if (flags.production) {
1959
+ const target = { type: "production" };
1960
+ return target;
1961
+ }
1962
+ return void 0;
1963
+ });
1964
+ var requirePositiveTimeout = (minutes) => minutes >= 1 ? Effect14.succeed(minutes) : new InvalidDomainOptionsError({ message: "--timeout must be at least 1 minute." });
1965
+ var confirm = (message, yes) => Effect14.gen(function* () {
1966
+ if (yes) return true;
1967
+ if (process.stdin.isTTY !== true) {
1968
+ return yield* new ConfirmationRequiredError({
1969
+ message: "Not running in a terminal, so there is no way to confirm. Pass --yes to proceed."
1970
+ });
1971
+ }
1972
+ return yield* Prompt.run(Prompt.confirm({ message, initial: false }));
1973
+ });
1974
+ var resolveApplication = (app) => Option8.match(app, {
1975
+ onSome: (value) => Effect14.succeed(value),
1976
+ onNone: () => Effect14.gen(function* () {
1977
+ const projectLink = yield* ProjectLinkService;
1978
+ const link = yield* projectLink.resolve(process.cwd());
1979
+ return link.applicationId;
1980
+ })
1981
+ });
1982
+ var resolveOrganization = (org) => Option8.match(org, {
1983
+ onSome: (value) => Effect14.succeed(value),
1984
+ onNone: () => Effect14.gen(function* () {
1985
+ const projectLink = yield* ProjectLinkService;
1986
+ const link = yield* projectLink.load(process.cwd());
1987
+ const organizationId = Option8.flatMap(link, (value) => Option8.fromNullable(value.organizationId));
1988
+ if (Option8.isNone(organizationId)) {
1989
+ return yield* new OrganizationRequiredError({
1990
+ message: "Pass --org, or run the command in a linked project."
1991
+ });
1992
+ }
1993
+ return organizationId.value;
1994
+ })
1995
+ });
1996
+ var normalizeHostname = (value) => value.trim().toLowerCase().replace(/\.$/, "");
1997
+ var findDomain = (applicationId, hostnameOrId) => Effect14.gen(function* () {
1998
+ const apiClient = yield* ApiClientService;
1999
+ const { items } = yield* apiClient.request((client) => client.applications.domains.list(applicationId));
2000
+ const wanted = normalizeHostname(hostnameOrId);
2001
+ const domain = items.find(
2002
+ (item) => item.id === hostnameOrId || item.hostname === wanted || item.unicodeHostname === wanted
2003
+ );
2004
+ if (!domain) {
2005
+ return yield* new DomainNotFoundError({ message: `No custom domain ${hostnameOrId} on this application.` });
2006
+ }
2007
+ return domain;
2008
+ });
2009
+ var printDomain = (domain) => Effect14.gen(function* () {
2010
+ for (const line of describeDomain(domain)) yield* Console7.log(line);
2011
+ const pending = domain.requiredRecords.filter((record) => record.status !== "ok");
2012
+ const records = formatDnsRecords(pending);
2013
+ if (records.length > 0 && domain.state !== "removing") {
2014
+ yield* Console7.log("\nAdd these records at your DNS provider:");
2015
+ for (const line of records) yield* Console7.log(` ${line}`);
2016
+ if (pending.some((record) => record.type === "ALIAS")) {
2017
+ yield* Console7.log(
2018
+ "\nApex domains need an ALIAS, ANAME or flattened CNAME record. Without one, attach www instead and redirect the apex to it."
2019
+ );
2020
+ }
2021
+ }
2022
+ });
2023
+ var isTransient = (error) => error._tag === "ApiRequestError" && (error.statusCode === void 0 || error.statusCode === 429 || error.statusCode >= 500);
2024
+ var waitUntilServing = (applicationId, initial, timeoutMinutes, json) => Effect14.gen(function* () {
2025
+ const apiClient = yield* ApiClientService;
2026
+ const progress = (line) => json ? Console7.error(line) : Console7.log(line);
2027
+ const fail = (domain2, message) => Effect14.gen(function* () {
2028
+ if (json) yield* Console7.log(JSON.stringify(domain2, null, 2));
2029
+ return yield* new DomainWaitError({ message, state: domain2.state });
2030
+ });
2031
+ const deadline = (yield* Clock.currentTimeMillis) + Duration2.toMillis(Duration2.minutes(timeoutMinutes));
2032
+ let domain = initial;
2033
+ yield* progress(`Waiting for ${domain.unicodeHostname} (${DOMAIN_STATE_LABELS[domain.state]})...`);
2034
+ while (IN_PROGRESS_STATES.has(domain.state)) {
2035
+ const remaining = deadline - (yield* Clock.currentTimeMillis);
2036
+ if (remaining <= 0) {
2037
+ return yield* fail(
2038
+ domain,
2039
+ `${domain.unicodeHostname} is not serving yet (${DOMAIN_STATE_LABELS[domain.state]}). Check again later with "gigadrive domains inspect ${domain.hostname}".`
2040
+ );
2041
+ }
2042
+ yield* Effect14.sleep(Duration2.min(POLL_INTERVAL, Duration2.millis(remaining)));
2043
+ const polled = yield* Effect14.either(
2044
+ apiClient.request((client) => client.applications.domains.get(applicationId, domain.id))
2045
+ );
2046
+ if (Either.isLeft(polled)) {
2047
+ if (isTransient(polled.left)) continue;
2048
+ return yield* polled.left;
2049
+ }
2050
+ if (polled.right.state !== domain.state) {
2051
+ yield* progress(` ${DOMAIN_STATE_LABELS[polled.right.state]}`);
2052
+ }
2053
+ domain = polled.right;
2054
+ }
2055
+ if (domain.state !== "active" && domain.state !== "degraded") {
2056
+ return yield* fail(
2057
+ domain,
2058
+ `${domain.unicodeHostname} is ${DOMAIN_STATE_LABELS[domain.state]}${domain.error ? `: ${domain.error.message}` : ""}`
2059
+ );
2060
+ }
2061
+ yield* progress(`
2062
+ ${domain.unicodeHostname} is live: https://${domain.hostname}`);
2063
+ if (json) yield* Console7.log(JSON.stringify(domain, null, 2));
2064
+ return domain;
2065
+ });
2066
+ var errorMessage = (action, error) => {
2067
+ switch (error._tag) {
2068
+ case "NotAuthenticatedError":
2069
+ return 'You are not logged in. Run "gigadrive login" to authenticate.';
2070
+ case "ApiRequestError":
2071
+ if (error.code === "quota_exceeded" && error.reason === "daily_add_limit") {
2072
+ return `${error.message}
2073
+ The daily limit resets within 24 hours; upgrading your plan raises it.`;
2074
+ }
2075
+ if (error.code === "quota_exceeded") {
2076
+ return `${error.message}
2077
+ See your plan's limits and upgrade at ${CONSOLE_URL} (organization settings > Limits).`;
2078
+ }
2079
+ if (error.code === "invalid_target" && error.reason === "redirects_not_available") {
2080
+ return `${error.message}
2081
+ Redirect domains are available on paid plans. Upgrade at ${CONSOLE_URL}.`;
2082
+ }
2083
+ if (error.code === "domain_in_use" && error.reason === "other_organization") {
2084
+ return `${error.message}
2085
+ If you control the domain, verify it with "gigadrive domains owners add <domain>", then move it with "gigadrive domains claim <hostname>".`;
2086
+ }
2087
+ if (error.reason === "ownership_not_live") {
2088
+ return `${error.message}
2089
+ Publish the TXT record shown by "gigadrive domains owners list" again, wait for DNS to update, then retry the claim.`;
2090
+ }
2091
+ return `Failed to ${action}: ${error.message}`;
2092
+ default:
2093
+ return error.message;
2094
+ }
2095
+ };
2096
+ var reportErrors = (action) => (self) => Effect14.tapError(self, (error) => Console7.error(errorMessage(action, error)));
2097
+ var listCommand = Command7.make(
2098
+ "list",
2099
+ { app: appOption3, json: jsonOption },
2100
+ ({ app, json }) => Effect14.gen(function* () {
2101
+ const apiClient = yield* ApiClientService;
2102
+ const applicationId = yield* resolveApplication(app);
2103
+ const { items } = yield* apiClient.request((client) => client.applications.domains.list(applicationId));
2104
+ if (json) return yield* Console7.log(JSON.stringify(items, null, 2));
2105
+ if (items.length === 0) {
2106
+ return yield* Console7.log('No custom domains. Add one with "gigadrive domains add <hostname>".');
2107
+ }
2108
+ const width = Math.max(...items.map((item) => item.unicodeHostname.length));
2109
+ for (const item of items) {
2110
+ const problem = item.error ? ` ${item.error.code}` : "";
2111
+ yield* Console7.log(
2112
+ `${item.unicodeHostname.padEnd(width)} ${DOMAIN_STATE_LABELS[item.state]}${item.primary ? " (primary)" : ""}${problem}`
2113
+ );
2114
+ }
2115
+ }).pipe(reportErrors("list custom domains"))
2116
+ );
2117
+ var addDomain = (input) => Effect14.gen(function* () {
2118
+ const apiClient = yield* ApiClientService;
2119
+ const target = yield* targetFromFlags(input);
2120
+ const timeout = yield* requirePositiveTimeout(input.timeout);
2121
+ const domain = yield* apiClient.request(
2122
+ (client) => client.applications.domains.add(input.applicationId, { hostname: input.hostname, target })
2123
+ );
2124
+ if (input.wait) return yield* waitUntilServing(input.applicationId, domain, timeout, input.json);
2125
+ if (input.json) {
2126
+ yield* Console7.log(JSON.stringify(domain, null, 2));
2127
+ return domain;
2128
+ }
2129
+ yield* printDomain(domain);
2130
+ if (IN_PROGRESS_STATES.has(domain.state)) {
2131
+ yield* Console7.log(
2132
+ `
2133
+ Gigadrive checks the records automatically. Follow progress with "gigadrive domains inspect ${domain.hostname}".`
2134
+ );
2135
+ }
2136
+ return domain;
2137
+ });
2138
+ var addCommand = Command7.make(
2139
+ "add",
2140
+ {
2141
+ hostname: hostnameArg,
2142
+ app: appOption3,
2143
+ production: productionOption,
2144
+ branch: branchOption,
2145
+ redirectTo: redirectToOption,
2146
+ status: statusOption2,
2147
+ dropPath: dropPathOption,
2148
+ wait: waitOption,
2149
+ timeout: timeoutOption,
2150
+ json: jsonOption
2151
+ },
2152
+ ({ app, ...options }) => Effect14.gen(function* () {
2153
+ const applicationId = yield* resolveApplication(app);
2154
+ yield* addDomain({ ...options, applicationId });
2155
+ }).pipe(reportErrors("add the domain"))
2156
+ );
2157
+ var updateCommand = Command7.make(
2158
+ "update",
2159
+ {
2160
+ domain: domainArg,
2161
+ app: appOption3,
2162
+ production: productionOption,
2163
+ branch: branchOption,
2164
+ redirectTo: redirectToOption,
2165
+ status: statusOption2,
2166
+ dropPath: dropPathOption,
2167
+ primary: primaryOption,
2168
+ json: jsonOption
2169
+ },
2170
+ ({ domain: hostnameOrId, app, primary, json, ...flags }) => Effect14.gen(function* () {
2171
+ const apiClient = yield* ApiClientService;
2172
+ const target = yield* targetFromFlags(flags);
2173
+ if (target === void 0 && !primary) {
2174
+ return yield* new InvalidDomainOptionsError({
2175
+ message: "Nothing to change. Pass --production, --branch, --redirect-to or --primary."
2176
+ });
2177
+ }
2178
+ const applicationId = yield* resolveApplication(app);
2179
+ const found = yield* findDomain(applicationId, hostnameOrId);
2180
+ const domain = yield* apiClient.request(
2181
+ (client) => client.applications.domains.update(applicationId, found.id, {
2182
+ ...target === void 0 ? {} : { target },
2183
+ ...primary ? { primary: true } : {}
2184
+ })
2185
+ );
2186
+ if (json) return yield* Console7.log(JSON.stringify(domain, null, 2));
2187
+ yield* printDomain(domain);
2188
+ }).pipe(reportErrors("update the domain"))
2189
+ );
2190
+ var claimCommand = Command7.make(
2191
+ "claim",
2192
+ {
2193
+ hostname: hostnameArg.pipe(Args3.withDescription("Hostname another organization attached")),
2194
+ app: appOption3,
2195
+ json: jsonOption
2196
+ },
2197
+ ({ hostname: hostname2, app, json }) => Effect14.gen(function* () {
2198
+ const apiClient = yield* ApiClientService;
2199
+ const applicationId = yield* resolveApplication(app);
2200
+ const domain = yield* apiClient.request((client) => client.applications.domains.claim(applicationId, hostname2));
2201
+ if (json) return yield* Console7.log(JSON.stringify(domain, null, 2));
2202
+ yield* Console7.log(`Moved ${domain.unicodeHostname} to this application.`);
2203
+ yield* printDomain(domain);
2204
+ }).pipe(reportErrors("claim the domain"))
2205
+ );
2206
+ var inspectCommand = Command7.make(
2207
+ "inspect",
2208
+ { domain: domainArg, app: appOption3, json: jsonOption },
2209
+ ({ domain: hostnameOrId, app, json }) => Effect14.gen(function* () {
2210
+ const applicationId = yield* resolveApplication(app);
2211
+ const domain = yield* findDomain(applicationId, hostnameOrId);
2212
+ if (json) return yield* Console7.log(JSON.stringify(domain, null, 2));
2213
+ yield* printDomain(domain);
2214
+ if (domain.nextCheckAt !== null) yield* Console7.log(`
2215
+ Next automatic check: ${domain.nextCheckAt}`);
2216
+ }).pipe(reportErrors("inspect the domain"))
2217
+ );
2218
+ var checkCommand = Command7.make(
2219
+ "check",
2220
+ { domain: domainArg, app: appOption3, wait: waitOption, timeout: timeoutOption, json: jsonOption },
2221
+ ({ domain: hostnameOrId, app, wait, timeout, json }) => Effect14.gen(function* () {
2222
+ const apiClient = yield* ApiClientService;
2223
+ const minutes = yield* requirePositiveTimeout(timeout);
2224
+ const applicationId = yield* resolveApplication(app);
2225
+ const found = yield* findDomain(applicationId, hostnameOrId);
2226
+ const domain = yield* apiClient.request((client) => client.applications.domains.refresh(applicationId, found.id));
2227
+ if (wait) return yield* waitUntilServing(applicationId, domain, minutes, json);
2228
+ if (json) return yield* Console7.log(JSON.stringify(domain, null, 2));
2229
+ yield* Console7.log(`Checking ${domain.unicodeHostname}.`);
2230
+ yield* printDomain(domain);
2231
+ }).pipe(reportErrors("check the domain"))
2232
+ );
2233
+ var removeDomain = (applicationId, hostnameOrId, yes) => Effect14.gen(function* () {
2234
+ const apiClient = yield* ApiClientService;
2235
+ const domain = yield* findDomain(applicationId, hostnameOrId);
2236
+ const confirmed = yield* confirm(
2237
+ `Remove ${domain.unicodeHostname}? It stops serving this application immediately.`,
2238
+ yes
2239
+ );
2240
+ if (!confirmed) return yield* Console7.log("Cancelled.");
2241
+ yield* apiClient.request((client) => client.applications.domains.remove(applicationId, domain.id));
2242
+ yield* Console7.log(`Removed ${domain.unicodeHostname}.`);
2243
+ });
2244
+ var removeCommand = Command7.make(
2245
+ "rm",
2246
+ { domain: domainArg, app: appOption3, yes: yesOption },
2247
+ ({ domain: hostnameOrId, app, yes }) => Effect14.gen(function* () {
2248
+ const applicationId = yield* resolveApplication(app);
2249
+ yield* removeDomain(applicationId, hostnameOrId, yes);
2250
+ }).pipe(
2251
+ // Ctrl+C at the confirmation is a deliberate cancel, not a failure.
2252
+ Effect14.catchTag("QuitException", () => Console7.log("Cancelled.")),
2253
+ reportErrors("remove the domain")
2254
+ )
2255
+ );
2256
+ var findOwnership = (organizationId, name) => Effect14.gen(function* () {
2257
+ const apiClient = yield* ApiClientService;
2258
+ const { items } = yield* apiClient.request((client) => client.organizations.domains.list(organizationId));
2259
+ const wanted = normalizeHostname(name);
2260
+ const claim = items.find((item) => item.id === name || item.name === wanted || item.unicodeName === wanted);
2261
+ if (!claim) {
2262
+ return yield* new DomainNotFoundError({
2263
+ message: `${name} is not claimed. Add it with "gigadrive domains owners add".`
2264
+ });
2265
+ }
2266
+ return claim;
2267
+ });
2268
+ var ownersListCommand = Command7.make(
2269
+ "list",
2270
+ { org: orgOption3, json: jsonOption },
2271
+ ({ org, json }) => Effect14.gen(function* () {
2272
+ const apiClient = yield* ApiClientService;
2273
+ const organizationId = yield* resolveOrganization(org);
2274
+ const { items } = yield* apiClient.request((client) => client.organizations.domains.list(organizationId));
2275
+ if (json) return yield* Console7.log(JSON.stringify(items, null, 2));
2276
+ if (items.length === 0) return yield* Console7.log("No verified domains.");
2277
+ const width = Math.max(...items.map((item) => item.unicodeName.length));
2278
+ for (const item of items) {
2279
+ yield* Console7.log(`${item.unicodeName.padEnd(width)} ${item.status}`);
2280
+ }
2281
+ }).pipe(reportErrors("list verified domains"))
2282
+ );
2283
+ var ownersAddCommand = Command7.make(
2284
+ "add",
2285
+ {
2286
+ name: Args3.text({ name: "domain" }).pipe(Args3.withDescription("Domain to verify, e.g. example.com")),
2287
+ org: orgOption3,
2288
+ json: jsonOption
2289
+ },
2290
+ ({ name, org, json }) => Effect14.gen(function* () {
2291
+ const apiClient = yield* ApiClientService;
2292
+ const organizationId = yield* resolveOrganization(org);
2293
+ const claim = yield* apiClient.request((client) => client.organizations.domains.add(organizationId, name));
2294
+ if (json) return yield* Console7.log(JSON.stringify(claim, null, 2));
2295
+ if (claim.status === "verified") {
2296
+ return yield* Console7.log(`${claim.unicodeName} is verified.`);
2297
+ }
2298
+ yield* Console7.log(`Publish this TXT record for ${claim.unicodeName}:`);
2299
+ yield* Console7.log(` Name: ${claim.record.host}`);
2300
+ yield* Console7.log(` Value: ${claim.record.value}`);
2301
+ yield* Console7.log(`
2302
+ Then run "gigadrive domains owners verify ${claim.name}".`);
2303
+ }).pipe(reportErrors("add the domain"))
2304
+ );
2305
+ var ownersVerifyCommand = Command7.make(
2306
+ "verify",
2307
+ { name: Args3.text({ name: "domain" }).pipe(Args3.withDescription("Domain to verify")), org: orgOption3 },
2308
+ ({ name, org }) => Effect14.gen(function* () {
2309
+ const apiClient = yield* ApiClientService;
2310
+ const organizationId = yield* resolveOrganization(org);
2311
+ const claim = yield* findOwnership(organizationId, name);
2312
+ const checked = yield* apiClient.request(
2313
+ (client) => client.organizations.domains.verify(organizationId, claim.id)
2314
+ );
2315
+ if (checked.status === "verified") {
2316
+ return yield* Console7.log(`${checked.unicodeName} is verified.`);
2317
+ }
2318
+ yield* Console7.log(
2319
+ `${checked.unicodeName} is not verified yet${checked.error ? `: ${checked.error.message}` : "."} Gigadrive keeps checking automatically.`
2320
+ );
2321
+ }).pipe(reportErrors("verify the domain"))
2322
+ );
2323
+ var ownersRemoveCommand = Command7.make(
2324
+ "rm",
2325
+ {
2326
+ name: Args3.text({ name: "domain" }).pipe(Args3.withDescription("Domain to remove")),
2327
+ org: orgOption3,
2328
+ yes: yesOption
2329
+ },
2330
+ ({ name, org, yes }) => Effect14.gen(function* () {
2331
+ const apiClient = yield* ApiClientService;
2332
+ const organizationId = yield* resolveOrganization(org);
2333
+ const claim = yield* findOwnership(organizationId, name);
2334
+ const confirmed = yield* confirm(
2335
+ `Remove ${claim.unicodeName} from your organization's domains? Custom domains that rely on it must be removed first.`,
2336
+ yes
2337
+ );
2338
+ if (!confirmed) return yield* Console7.log("Cancelled.");
2339
+ yield* apiClient.request((client) => client.organizations.domains.remove(organizationId, claim.id));
2340
+ yield* Console7.log(`Removed ${claim.unicodeName}.`);
2341
+ }).pipe(
2342
+ Effect14.catchTag("QuitException", () => Console7.log("Cancelled.")),
2343
+ reportErrors("remove the domain")
2344
+ )
2345
+ );
2346
+ var ownersCommand = Command7.make("owners", {}, () => Effect14.void).pipe(
2347
+ Command7.withDescription("Domains your organization verified with a TXT record"),
2348
+ Command7.withSubcommands([ownersListCommand, ownersAddCommand, ownersVerifyCommand, ownersRemoveCommand])
2349
+ );
2350
+ var domainsBase = Command7.make("domains", {}, () => Effect14.void).pipe(
2351
+ Command7.withDescription("Custom domains of the linked application")
2352
+ );
2353
+ var domainsCommand = domainsBase.pipe(
2354
+ Command7.withSubcommands([
2355
+ listCommand,
2356
+ addCommand,
2357
+ updateCommand,
2358
+ claimCommand,
2359
+ inspectCommand,
2360
+ checkCommand,
2361
+ removeCommand,
2362
+ ownersCommand
2363
+ ])
2364
+ );
2365
+
2366
+ // src/commands/env/index.ts
2367
+ import { Args as Args4, Command as Command8, Options as Options5, Prompt as Prompt2 } from "@effect/cli";
2368
+ import { Console as Console8, Effect as Effect18, Option as Option12 } from "effect";
1790
2369
 
1791
2370
  // src/services/env-file.ts
1792
2371
  import { FileSystem as FileSystem6, Path as Path5 } from "@effect/platform";
1793
- import { Effect as Effect14, Option as Option8 } from "effect";
2372
+ import { Effect as Effect15, Option as Option9 } from "effect";
1794
2373
 
1795
2374
  // src/lib/dotenv.ts
1796
2375
  var DEFAULT_ENV_HEADER = "# Generated by `gigadrive env pull` \u2014 do not edit by hand.";
@@ -1848,42 +2427,42 @@ var parseEnv = (content) => {
1848
2427
  };
1849
2428
 
1850
2429
  // src/services/env-file.ts
1851
- var EnvFileService = class extends Effect14.Service()("EnvFileService", {
2430
+ var EnvFileService = class extends Effect15.Service()("EnvFileService", {
1852
2431
  accessors: true,
1853
- effect: Effect14.gen(function* () {
2432
+ effect: Effect15.gen(function* () {
1854
2433
  const fs = yield* FileSystem6.FileSystem;
1855
2434
  const pathService = yield* Path5.Path;
1856
- const exists = Effect14.fn("EnvFileService.exists")(function* (filePath) {
1857
- return yield* fs.exists(filePath).pipe(Effect14.mapError(() => new EnvFileReadError({ message: `Failed to check whether ${filePath} exists` })));
2435
+ const exists = Effect15.fn("EnvFileService.exists")(function* (filePath) {
2436
+ return yield* fs.exists(filePath).pipe(Effect15.mapError(() => new EnvFileReadError({ message: `Failed to check whether ${filePath} exists` })));
1858
2437
  });
1859
- const read = Effect14.fn("EnvFileService.read")(function* (filePath) {
2438
+ const read = Effect15.fn("EnvFileService.read")(function* (filePath) {
1860
2439
  const present = yield* exists(filePath);
1861
- if (!present) return Option8.none();
1862
- const contents = yield* fs.readFileString(filePath, "utf8").pipe(Effect14.mapError(() => new EnvFileReadError({ message: `Failed to read ${filePath}` })));
1863
- return Option8.some(contents);
2440
+ if (!present) return Option9.none();
2441
+ const contents = yield* fs.readFileString(filePath, "utf8").pipe(Effect15.mapError(() => new EnvFileReadError({ message: `Failed to read ${filePath}` })));
2442
+ return Option9.some(contents);
1864
2443
  });
1865
- const write = Effect14.fn("EnvFileService.write")(function* (filePath, entries, opts) {
2444
+ const write = Effect15.fn("EnvFileService.write")(function* (filePath, entries, opts) {
1866
2445
  const dir = pathService.dirname(filePath);
1867
2446
  yield* fs.makeDirectory(dir, { recursive: true }).pipe(
1868
- Effect14.mapError(
2447
+ Effect15.mapError(
1869
2448
  (error) => new EnvFileWriteError({ message: `Failed to create directory for ${filePath}`, cause: String(error) })
1870
2449
  )
1871
2450
  );
1872
2451
  yield* fs.writeFileString(filePath, serializeEnv(entries, opts), { mode: 384 }).pipe(
1873
- Effect14.mapError(
2452
+ Effect15.mapError(
1874
2453
  (error) => new EnvFileWriteError({ message: `Failed to write ${filePath}`, cause: String(error) })
1875
2454
  )
1876
2455
  );
1877
2456
  yield* fs.chmod(filePath, 384).pipe(
1878
- Effect14.mapError(
2457
+ Effect15.mapError(
1879
2458
  (error) => new EnvFileWriteError({ message: `Failed to secure ${filePath}`, cause: String(error) })
1880
2459
  )
1881
2460
  );
1882
2461
  });
1883
- const ensureGitignored = Effect14.fn("EnvFileService.ensureGitignored")(function* (dir, entry) {
2462
+ const ensureGitignored = Effect15.fn("EnvFileService.ensureGitignored")(function* (dir, entry) {
1884
2463
  const gitignorePath = pathService.join(dir, ".gitignore");
1885
2464
  const existing = yield* read(gitignorePath);
1886
- const current = Option8.getOrElse(existing, () => "");
2465
+ const current = Option9.getOrElse(existing, () => "");
1887
2466
  const alreadyIgnored = current.split("\n").some((line) => line.trim() === entry);
1888
2467
  if (alreadyIgnored) {
1889
2468
  return false;
@@ -1891,7 +2470,7 @@ var EnvFileService = class extends Effect14.Service()("EnvFileService", {
1891
2470
  const separator = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
1892
2471
  yield* fs.writeFileString(gitignorePath, `${current}${separator}${entry}
1893
2472
  `).pipe(
1894
- Effect14.mapError(
2473
+ Effect15.mapError(
1895
2474
  (error) => new EnvFileWriteError({ message: "Failed to update .gitignore", cause: String(error) })
1896
2475
  )
1897
2476
  );
@@ -1903,29 +2482,29 @@ var EnvFileService = class extends Effect14.Service()("EnvFileService", {
1903
2482
  };
1904
2483
 
1905
2484
  // src/services/local-credentials.ts
1906
- import { Config as Config3, Effect as Effect16, Option as Option10 } from "effect";
2485
+ import { Config as Config3, Effect as Effect17, Option as Option11 } from "effect";
1907
2486
  import * as os3 from "os";
1908
2487
 
1909
2488
  // src/services/dev-credentials-store.ts
1910
2489
  import { FileSystem as FileSystem7, Path as Path6 } from "@effect/platform";
1911
- import { Effect as Effect15, Option as Option9, Schema as Schema7 } from "effect";
2490
+ import { Effect as Effect16, Option as Option10, Schema as Schema7 } from "effect";
1912
2491
  import * as os2 from "os";
1913
- var DevCredentialsStore = class extends Effect15.Service()("DevCredentialsStore", {
2492
+ var DevCredentialsStore = class extends Effect16.Service()("DevCredentialsStore", {
1914
2493
  accessors: true,
1915
- effect: Effect15.gen(function* () {
2494
+ effect: Effect16.gen(function* () {
1916
2495
  const fs = yield* FileSystem7.FileSystem;
1917
2496
  const pathService = yield* Path6.Path;
1918
2497
  const homeDir = os2.homedir();
1919
2498
  const storeDir = pathService.join(homeDir, ".gigadrive");
1920
2499
  const storeFile = pathService.join(storeDir, "dev-keys.json");
1921
- const ensureDirectory = Effect15.gen(function* () {
2500
+ const ensureDirectory = Effect16.gen(function* () {
1922
2501
  yield* fs.makeDirectory(storeDir, { recursive: true }).pipe(
1923
- Effect15.mapError(
2502
+ Effect16.mapError(
1924
2503
  (error) => new DevCredentialsStoreWriteError({ message: "Failed to create ~/.gigadrive", cause: String(error) })
1925
2504
  )
1926
2505
  );
1927
2506
  yield* fs.chmod(storeDir, 448).pipe(
1928
- Effect15.mapError(
2507
+ Effect16.mapError(
1929
2508
  (error) => new DevCredentialsStoreWriteError({
1930
2509
  message: "Failed to set ~/.gigadrive permissions",
1931
2510
  cause: String(error)
@@ -1933,30 +2512,30 @@ var DevCredentialsStore = class extends Effect15.Service()("DevCredentialsStore"
1933
2512
  )
1934
2513
  );
1935
2514
  });
1936
- const load = Effect15.gen(function* () {
1937
- const present = yield* fs.exists(storeFile).pipe(Effect15.mapError(() => new DevCredentialsStoreReadError({ message: "Failed to check dev-keys.json" })));
2515
+ const load = Effect16.gen(function* () {
2516
+ const present = yield* fs.exists(storeFile).pipe(Effect16.mapError(() => new DevCredentialsStoreReadError({ message: "Failed to check dev-keys.json" })));
1938
2517
  if (!present) return {};
1939
- const data = yield* fs.readFileString(storeFile, "utf8").pipe(Effect15.mapError(() => new DevCredentialsStoreReadError({ message: "Failed to read dev-keys.json" })));
1940
- const json = yield* Effect15.try({
2518
+ const data = yield* fs.readFileString(storeFile, "utf8").pipe(Effect16.mapError(() => new DevCredentialsStoreReadError({ message: "Failed to read dev-keys.json" })));
2519
+ const json = yield* Effect16.try({
1941
2520
  try: () => JSON.parse(data),
1942
2521
  catch: () => new DevCredentialsStoreReadError({ message: "dev-keys.json contains invalid JSON" })
1943
2522
  });
1944
2523
  return yield* Schema7.decodeUnknown(DevKeyStore)(json).pipe(
1945
- Effect15.mapError(() => new DevCredentialsStoreReadError({ message: "dev-keys.json has an invalid schema" }))
2524
+ Effect16.mapError(() => new DevCredentialsStoreReadError({ message: "dev-keys.json has an invalid schema" }))
1946
2525
  );
1947
2526
  });
1948
- const get = Effect15.fn("DevCredentialsStore.get")(function* (applicationId) {
2527
+ const get = Effect16.fn("DevCredentialsStore.get")(function* (applicationId) {
1949
2528
  const store = yield* load;
1950
2529
  const entry = store[applicationId];
1951
- return entry ? Option9.some(entry) : Option9.none();
2530
+ return entry ? Option10.some(entry) : Option10.none();
1952
2531
  });
1953
- const set = Effect15.fn("DevCredentialsStore.set")(function* (applicationId, entry) {
2532
+ const set = Effect16.fn("DevCredentialsStore.set")(function* (applicationId, entry) {
1954
2533
  const store = yield* load;
1955
2534
  const next = { ...store, [applicationId]: entry };
1956
2535
  yield* ensureDirectory;
1957
2536
  yield* fs.writeFileString(storeFile, `${JSON.stringify(next, null, 2)}
1958
2537
  `, { mode: 384 }).pipe(
1959
- Effect15.mapError(
2538
+ Effect16.mapError(
1960
2539
  (error) => new DevCredentialsStoreWriteError({ message: "Failed to write dev-keys.json", cause: String(error) })
1961
2540
  )
1962
2541
  );
@@ -1974,25 +2553,25 @@ var credentialEntries = (clientId, clientSecret, baseUrl) => [
1974
2553
  { key: "GIGADRIVE_CLIENT_SECRET", value: clientSecret },
1975
2554
  { key: "GIGADRIVE_API_BASE_URL", value: baseUrl }
1976
2555
  ];
1977
- var LocalCredentialsService = class extends Effect16.Service()("LocalCredentialsService", {
2556
+ var LocalCredentialsService = class extends Effect17.Service()("LocalCredentialsService", {
1978
2557
  accessors: true,
1979
2558
  dependencies: [ApiClientService.Default, DevCredentialsStore.Default],
1980
- effect: Effect16.gen(function* () {
2559
+ effect: Effect17.gen(function* () {
1981
2560
  const apiClient = yield* ApiClientService;
1982
2561
  const store = yield* DevCredentialsStore;
1983
2562
  const baseUrl = yield* ApiBaseUrl2;
1984
2563
  const keyName = (applicationId) => `cli-dev:${os3.hostname()}:${applicationId}`;
1985
- const provision = Effect16.fn("LocalCredentialsService.provision")(function* (input) {
2564
+ const provision = Effect17.fn("LocalCredentialsService.provision")(function* (input) {
1986
2565
  const stored = yield* store.get(input.applicationId);
1987
2566
  const existing = input.existingContent ? parseEnv(input.existingContent) : {};
1988
2567
  const existingClientId = existing["GIGADRIVE_CLIENT_ID"];
1989
2568
  const existingClientSecret = existing["GIGADRIVE_CLIENT_SECRET"];
1990
- const canReuse = !input.rotate && existingClientId !== void 0 && existingClientSecret !== void 0 && Option10.isSome(stored) && stored.value.apiKeyId === existingClientId;
2569
+ const canReuse = !input.rotate && existingClientId !== void 0 && existingClientSecret !== void 0 && Option11.isSome(stored) && stored.value.apiKeyId === existingClientId;
1991
2570
  if (canReuse) {
1992
2571
  return credentialEntries(existingClientId, existingClientSecret, baseUrl);
1993
2572
  }
1994
- if (Option10.isSome(stored)) {
1995
- yield* apiClient.request((client) => client.apiKeys.delete(stored.value.apiKeyId)).pipe(Effect16.catchTag("ApiRequestError", () => Effect16.void));
2573
+ if (Option11.isSome(stored)) {
2574
+ yield* apiClient.request((client) => client.apiKeys.delete(stored.value.apiKeyId)).pipe(Effect17.catchTag("ApiRequestError", () => Effect17.void));
1996
2575
  }
1997
2576
  const created = yield* apiClient.request(
1998
2577
  (client) => client.apiKeys.create({
@@ -2010,92 +2589,92 @@ var LocalCredentialsService = class extends Effect16.Service()("LocalCredentials
2010
2589
  };
2011
2590
 
2012
2591
  // src/commands/env/index.ts
2013
- var appOption3 = Options4.text("app").pipe(
2014
- Options4.withAlias("a"),
2015
- Options4.withDescription("Operate on this application (overrides the linked application)"),
2016
- Options4.optional
2592
+ var appOption4 = Options5.text("app").pipe(
2593
+ Options5.withAlias("a"),
2594
+ Options5.withDescription("Operate on this application (overrides the linked application)"),
2595
+ Options5.optional
2017
2596
  );
2018
- var orgOption3 = Options4.text("org").pipe(
2019
- Options4.withAlias("o"),
2020
- Options4.withDescription("Operate on this organization instead of an application"),
2021
- Options4.optional
2597
+ var orgOption4 = Options5.text("org").pipe(
2598
+ Options5.withAlias("o"),
2599
+ Options5.withDescription("Operate on this organization instead of an application"),
2600
+ Options5.optional
2022
2601
  );
2023
- var sensitiveOption = Options4.boolean("sensitive").pipe(
2024
- Options4.withDescription("Store the value as sensitive (hidden in API responses)")
2602
+ var sensitiveOption = Options5.boolean("sensitive").pipe(
2603
+ Options5.withDescription("Store the value as sensitive (hidden in API responses)")
2025
2604
  );
2026
- var envIdOption = Options4.text("env").pipe(
2027
- Options4.withAlias("e"),
2028
- Options4.withDescription("Environment ID for an environment-scoped variable (application scope only)"),
2029
- Options4.optional
2605
+ var envIdOption = Options5.text("env").pipe(
2606
+ Options5.withAlias("e"),
2607
+ Options5.withDescription("Environment ID for an environment-scoped variable (application scope only)"),
2608
+ Options5.optional
2030
2609
  );
2031
- var keyValueArg = Args3.text({ name: "key=value" }).pipe(
2032
- Args3.withDescription("Variable assignment, e.g. DATABASE_URL=postgres://user:pass@host/db")
2610
+ var keyValueArg = Args4.text({ name: "key=value" }).pipe(
2611
+ Args4.withDescription("Variable assignment, e.g. DATABASE_URL=postgres://user:pass@host/db")
2033
2612
  );
2034
- var keyOrIdArg = Args3.text({ name: "key-or-id" }).pipe(Args3.withDescription("Variable key or ID to remove"));
2035
- var fileArg = Args3.text({ name: "file" }).pipe(
2036
- Args3.withDescription("Output file to write (default: .env.local)"),
2037
- Args3.optional
2613
+ var keyOrIdArg = Args4.text({ name: "key-or-id" }).pipe(Args4.withDescription("Variable key or ID to remove"));
2614
+ var fileArg = Args4.text({ name: "file" }).pipe(
2615
+ Args4.withDescription("Output file to write (default: .env.local)"),
2616
+ Args4.optional
2038
2617
  );
2039
- var environmentOption = Options4.text("environment").pipe(
2040
- Options4.withAlias("e"),
2041
- Options4.withDescription("Environment slug to resolve overrides for (e.g. preview). Omit for the local baseline"),
2042
- Options4.optional
2618
+ var environmentOption = Options5.text("environment").pipe(
2619
+ Options5.withAlias("e"),
2620
+ Options5.withDescription("Environment slug to resolve overrides for (e.g. preview). Omit for the local baseline"),
2621
+ Options5.optional
2043
2622
  );
2044
- var yesOption = Options4.boolean("yes").pipe(
2045
- Options4.withAlias("y"),
2046
- Options4.withDescription("Overwrite an existing file without confirmation")
2623
+ var yesOption2 = Options5.boolean("yes").pipe(
2624
+ Options5.withAlias("y"),
2625
+ Options5.withDescription("Overwrite an existing file without confirmation")
2047
2626
  );
2048
- var withCredentialsOption = Options4.boolean("with-credentials").pipe(
2049
- Options4.withDescription("Also provision API-key credentials so the local app can call the API as this application")
2627
+ var withCredentialsOption = Options5.boolean("with-credentials").pipe(
2628
+ Options5.withDescription("Also provision API-key credentials so the local app can call the API as this application")
2050
2629
  );
2051
- var rotateOption = Options4.boolean("rotate").pipe(
2052
- Options4.withDescription("Force a fresh API key when provisioning credentials, revoking the previous one")
2630
+ var rotateOption = Options5.boolean("rotate").pipe(
2631
+ Options5.withDescription("Force a fresh API key when provisioning credentials, revoking the previous one")
2053
2632
  );
2054
- var resolveScope = (app, org) => Effect17.gen(function* () {
2055
- if (Option11.isSome(org)) {
2633
+ var resolveScope = (app, org) => Effect18.gen(function* () {
2634
+ if (Option12.isSome(org)) {
2056
2635
  return { kind: "organization", id: org.value };
2057
2636
  }
2058
2637
  const projectLink = yield* ProjectLinkService;
2059
- const id = yield* Option11.match(app, {
2060
- onSome: (value) => Effect17.succeed(value),
2061
- onNone: () => projectLink.resolve(process.cwd()).pipe(Effect17.map((link) => link.applicationId))
2638
+ const id = yield* Option12.match(app, {
2639
+ onSome: (value) => Effect18.succeed(value),
2640
+ onNone: () => projectLink.resolve(process.cwd()).pipe(Effect18.map((link) => link.applicationId))
2062
2641
  });
2063
2642
  return { kind: "application", id };
2064
2643
  });
2065
- var envListCommand = Command7.make(
2644
+ var envListCommand = Command8.make(
2066
2645
  "list",
2067
- { app: appOption3, org: orgOption3 },
2068
- ({ app, org }) => Effect17.gen(function* () {
2646
+ { app: appOption4, org: orgOption4 },
2647
+ ({ app, org }) => Effect18.gen(function* () {
2069
2648
  const apiClient = yield* ApiClientService;
2070
2649
  const scope = yield* resolveScope(app, org);
2071
2650
  const { items } = yield* apiClient.request(
2072
2651
  (client) => scope.kind === "organization" ? client.organizations.envVars.list(scope.id) : client.applications.envVars.list(scope.id)
2073
2652
  );
2074
2653
  if (items.length === 0) {
2075
- yield* Console7.log("No environment variables set.");
2654
+ yield* Console8.log("No environment variables set.");
2076
2655
  return;
2077
2656
  }
2078
2657
  for (const v of items) {
2079
- yield* Console7.log(`${v.key}=${v.sensitive ? "***" : v.value ?? ""}`);
2658
+ yield* Console8.log(`${v.key}=${v.sensitive ? "***" : v.value ?? ""}`);
2080
2659
  }
2081
2660
  }).pipe(
2082
- Effect17.catchTags({
2083
- NotAuthenticatedError: (err) => Console7.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2084
- Effect17.andThen(Effect17.fail(err))
2661
+ Effect18.catchTags({
2662
+ NotAuthenticatedError: (err) => Console8.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2663
+ Effect18.andThen(Effect18.fail(err))
2085
2664
  ),
2086
- ApiRequestError: (err) => Console7.error(`Failed to list environment variables: ${err.message}`).pipe(Effect17.andThen(Effect17.fail(err))),
2087
- ProjectNotLinkedError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2088
- ProjectLinkReadError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err)))
2665
+ ApiRequestError: (err) => Console8.error(`Failed to list environment variables: ${err.message}`).pipe(Effect18.andThen(Effect18.fail(err))),
2666
+ ProjectNotLinkedError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2667
+ ProjectLinkReadError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err)))
2089
2668
  })
2090
2669
  )
2091
2670
  );
2092
- var envSetCommand = Command7.make(
2671
+ var envSetCommand = Command8.make(
2093
2672
  "set",
2094
- { keyValue: keyValueArg, app: appOption3, org: orgOption3, sensitive: sensitiveOption, env: envIdOption },
2095
- ({ keyValue, app, org, sensitive, env }) => Effect17.gen(function* () {
2673
+ { keyValue: keyValueArg, app: appOption4, org: orgOption4, sensitive: sensitiveOption, env: envIdOption },
2674
+ ({ keyValue, app, org, sensitive, env }) => Effect18.gen(function* () {
2096
2675
  const separator = keyValue.indexOf("=");
2097
2676
  if (separator <= 0) {
2098
- return yield* Effect17.fail(
2677
+ return yield* Effect18.fail(
2099
2678
  new InvalidEnvVarFormatError({
2100
2679
  message: 'Invalid format. Use KEY=VALUE, e.g. "gigadrive env set DATABASE_URL=postgres://...".'
2101
2680
  })
@@ -2105,27 +2684,27 @@ var envSetCommand = Command7.make(
2105
2684
  const value = keyValue.slice(separator + 1);
2106
2685
  const apiClient = yield* ApiClientService;
2107
2686
  const scope = yield* resolveScope(app, org);
2108
- const environmentId = Option11.getOrUndefined(env);
2687
+ const environmentId = Option12.getOrUndefined(env);
2109
2688
  const created = yield* apiClient.request(
2110
2689
  (client) => scope.kind === "organization" ? client.organizations.envVars.create(scope.id, { key, value, sensitive }) : client.applications.envVars.create(scope.id, { key, value, sensitive, environmentId })
2111
2690
  );
2112
- yield* Console7.log(`Set ${created.key}.`);
2691
+ yield* Console8.log(`Set ${created.key}.`);
2113
2692
  }).pipe(
2114
- Effect17.catchTags({
2115
- InvalidEnvVarFormatError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2116
- NotAuthenticatedError: (err) => Console7.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2117
- Effect17.andThen(Effect17.fail(err))
2693
+ Effect18.catchTags({
2694
+ InvalidEnvVarFormatError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2695
+ NotAuthenticatedError: (err) => Console8.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2696
+ Effect18.andThen(Effect18.fail(err))
2118
2697
  ),
2119
- ApiRequestError: (err) => Console7.error(`Failed to set environment variable: ${err.message}`).pipe(Effect17.andThen(Effect17.fail(err))),
2120
- ProjectNotLinkedError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2121
- ProjectLinkReadError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err)))
2698
+ ApiRequestError: (err) => Console8.error(`Failed to set environment variable: ${err.message}`).pipe(Effect18.andThen(Effect18.fail(err))),
2699
+ ProjectNotLinkedError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2700
+ ProjectLinkReadError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err)))
2122
2701
  })
2123
2702
  )
2124
2703
  );
2125
- var envRmCommand = Command7.make(
2704
+ var envRmCommand = Command8.make(
2126
2705
  "rm",
2127
- { keyOrId: keyOrIdArg, app: appOption3, org: orgOption3 },
2128
- ({ keyOrId, app, org }) => Effect17.gen(function* () {
2706
+ { keyOrId: keyOrIdArg, app: appOption4, org: orgOption4 },
2707
+ ({ keyOrId, app, org }) => Effect18.gen(function* () {
2129
2708
  const apiClient = yield* ApiClientService;
2130
2709
  const scope = yield* resolveScope(app, org);
2131
2710
  const { items } = yield* apiClient.request(
@@ -2133,56 +2712,56 @@ var envRmCommand = Command7.make(
2133
2712
  );
2134
2713
  const target = items.find((v) => v.id === keyOrId || v.key === keyOrId);
2135
2714
  if (target === void 0) {
2136
- return yield* Effect17.fail(
2715
+ return yield* Effect18.fail(
2137
2716
  new EnvVarNotFoundError({ message: `No environment variable matching "${keyOrId}".` })
2138
2717
  );
2139
2718
  }
2140
2719
  yield* apiClient.request(
2141
2720
  (client) => scope.kind === "organization" ? client.organizations.envVars.delete(scope.id, target.id) : client.applications.envVars.delete(scope.id, target.id)
2142
2721
  );
2143
- yield* Console7.log(`Removed ${target.key}.`);
2722
+ yield* Console8.log(`Removed ${target.key}.`);
2144
2723
  }).pipe(
2145
- Effect17.catchTags({
2146
- EnvVarNotFoundError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2147
- NotAuthenticatedError: (err) => Console7.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2148
- Effect17.andThen(Effect17.fail(err))
2724
+ Effect18.catchTags({
2725
+ EnvVarNotFoundError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2726
+ NotAuthenticatedError: (err) => Console8.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2727
+ Effect18.andThen(Effect18.fail(err))
2149
2728
  ),
2150
- ApiRequestError: (err) => Console7.error(`Failed to remove environment variable: ${err.message}`).pipe(Effect17.andThen(Effect17.fail(err))),
2151
- ProjectNotLinkedError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2152
- ProjectLinkReadError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err)))
2729
+ ApiRequestError: (err) => Console8.error(`Failed to remove environment variable: ${err.message}`).pipe(Effect18.andThen(Effect18.fail(err))),
2730
+ ProjectNotLinkedError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2731
+ ProjectLinkReadError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err)))
2153
2732
  })
2154
2733
  )
2155
2734
  );
2156
- var envPullCommand = Command7.make(
2735
+ var envPullCommand = Command8.make(
2157
2736
  "pull",
2158
2737
  {
2159
2738
  file: fileArg,
2160
- app: appOption3,
2739
+ app: appOption4,
2161
2740
  environment: environmentOption,
2162
- yes: yesOption,
2741
+ yes: yesOption2,
2163
2742
  withCredentials: withCredentialsOption,
2164
2743
  rotate: rotateOption
2165
2744
  },
2166
- ({ file, app, environment, yes, withCredentials, rotate }) => Effect17.gen(function* () {
2745
+ ({ file, app, environment, yes, withCredentials, rotate }) => Effect18.gen(function* () {
2167
2746
  const apiClient = yield* ApiClientService;
2168
2747
  const projectLink = yield* ProjectLinkService;
2169
2748
  const envFile = yield* EnvFileService;
2170
- const applicationId = yield* Option11.match(app, {
2171
- onSome: (value) => Effect17.succeed(value),
2172
- onNone: () => projectLink.resolve(process.cwd()).pipe(Effect17.map((link) => link.applicationId))
2749
+ const applicationId = yield* Option12.match(app, {
2750
+ onSome: (value) => Effect18.succeed(value),
2751
+ onNone: () => projectLink.resolve(process.cwd()).pipe(Effect18.map((link) => link.applicationId))
2173
2752
  });
2174
- const target = Option11.getOrElse(file, () => ".env.local");
2175
- const environmentSlug = Option11.getOrUndefined(environment);
2753
+ const target = Option12.getOrElse(file, () => ".env.local");
2754
+ const environmentSlug = Option12.getOrUndefined(environment);
2176
2755
  const { items, omittedSensitive } = yield* apiClient.request(
2177
2756
  (client) => client.applications.envVars.pull(applicationId, environmentSlug ? { environment: environmentSlug } : void 0)
2178
2757
  );
2179
2758
  const existing = yield* envFile.read(target);
2180
- if (Option11.isSome(existing) && !yes) {
2181
- const overwrite = yield* Prompt.run(
2182
- Prompt.confirm({ message: `${target} already exists. Overwrite?`, initial: false })
2759
+ if (Option12.isSome(existing) && !yes) {
2760
+ const overwrite = yield* Prompt2.run(
2761
+ Prompt2.confirm({ message: `${target} already exists. Overwrite?`, initial: false })
2183
2762
  );
2184
2763
  if (!overwrite) {
2185
- return yield* Console7.log("Cancelled.");
2764
+ return yield* Console8.log("Cancelled.");
2186
2765
  }
2187
2766
  }
2188
2767
  let credentialEntries2 = [];
@@ -2191,81 +2770,81 @@ var envPullCommand = Command7.make(
2191
2770
  credentialEntries2 = yield* localCredentials.provision({
2192
2771
  applicationId,
2193
2772
  rotate,
2194
- existingContent: Option11.getOrUndefined(existing)
2773
+ existingContent: Option12.getOrUndefined(existing)
2195
2774
  });
2196
2775
  }
2197
2776
  const entries = [...items.map((v) => ({ key: v.key, value: v.value })), ...credentialEntries2];
2198
2777
  yield* envFile.write(target, entries);
2199
2778
  const gitignored = yield* envFile.ensureGitignored(process.cwd(), target);
2200
- yield* Console7.log(
2779
+ yield* Console8.log(
2201
2780
  `Pulled ${items.length} environment variable(s)${withCredentials ? " and API credentials" : ""} to ${target}.`
2202
2781
  );
2203
2782
  if (omittedSensitive > 0) {
2204
- yield* Console7.log(
2783
+ yield* Console8.log(
2205
2784
  `Skipped ${omittedSensitive} sensitive variable(s); secrets live only in production/preview environments.`
2206
2785
  );
2207
2786
  }
2208
2787
  if (gitignored) {
2209
- yield* Console7.log(`Added ${target} to .gitignore.`);
2788
+ yield* Console8.log(`Added ${target} to .gitignore.`);
2210
2789
  }
2211
2790
  }).pipe(
2212
- Effect17.catchTags({
2791
+ Effect18.catchTags({
2213
2792
  // Ctrl+C during the overwrite prompt is a deliberate cancel — exit 0.
2214
- QuitException: () => Console7.log("Cancelled."),
2215
- NotAuthenticatedError: (err) => Console7.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2216
- Effect17.andThen(Effect17.fail(err))
2793
+ QuitException: () => Console8.log("Cancelled."),
2794
+ NotAuthenticatedError: (err) => Console8.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2795
+ Effect18.andThen(Effect18.fail(err))
2217
2796
  ),
2218
- ApiRequestError: (err) => Console7.error(`Failed to pull environment variables: ${err.message}`).pipe(Effect17.andThen(Effect17.fail(err))),
2219
- ProjectNotLinkedError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2220
- ProjectLinkReadError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2221
- EnvFileReadError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2222
- EnvFileWriteError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2223
- DevCredentialsStoreReadError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err))),
2224
- DevCredentialsStoreWriteError: (err) => Console7.error(err.message).pipe(Effect17.andThen(Effect17.fail(err)))
2797
+ ApiRequestError: (err) => Console8.error(`Failed to pull environment variables: ${err.message}`).pipe(Effect18.andThen(Effect18.fail(err))),
2798
+ ProjectNotLinkedError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2799
+ ProjectLinkReadError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2800
+ EnvFileReadError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2801
+ EnvFileWriteError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2802
+ DevCredentialsStoreReadError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2803
+ DevCredentialsStoreWriteError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err)))
2225
2804
  })
2226
2805
  )
2227
2806
  );
2228
- var envBase = Command7.make("env", {}, () => Effect17.void);
2807
+ var envBase = Command8.make("env", {}, () => Effect18.void);
2229
2808
  var envCommand = envBase.pipe(
2230
- Command7.withSubcommands([envListCommand, envSetCommand, envRmCommand, envPullCommand])
2809
+ Command8.withSubcommands([envListCommand, envSetCommand, envRmCommand, envPullCommand])
2231
2810
  );
2232
2811
 
2233
2812
  // src/commands/link/index.ts
2234
- import { Command as Command8, Options as Options5, Prompt as Prompt2 } from "@effect/cli";
2235
- import { Console as Console8, Effect as Effect18, Option as Option12 } from "effect";
2236
- var appOption4 = Options5.text("app").pipe(
2237
- Options5.withAlias("a"),
2238
- Options5.withDescription("Application ID to link (skips the interactive picker)"),
2239
- Options5.optional
2813
+ import { Command as Command9, Options as Options6, Prompt as Prompt3 } from "@effect/cli";
2814
+ import { Console as Console9, Effect as Effect19, Option as Option13 } from "effect";
2815
+ var appOption5 = Options6.text("app").pipe(
2816
+ Options6.withAlias("a"),
2817
+ Options6.withDescription("Application ID to link (skips the interactive picker)"),
2818
+ Options6.optional
2240
2819
  );
2241
- var orgOption4 = Options5.text("org").pipe(
2242
- Options5.withAlias("o"),
2243
- Options5.withDescription("Only list applications belonging to this organization ID"),
2244
- Options5.optional
2820
+ var orgOption5 = Options6.text("org").pipe(
2821
+ Options6.withAlias("o"),
2822
+ Options6.withDescription("Only list applications belonging to this organization ID"),
2823
+ Options6.optional
2245
2824
  );
2246
- var linkCommand = Command8.make(
2825
+ var linkCommand = Command9.make(
2247
2826
  "link",
2248
- { app: appOption4, org: orgOption4 },
2249
- ({ app, org }) => Effect18.gen(function* () {
2827
+ { app: appOption5, org: orgOption5 },
2828
+ ({ app, org }) => Effect19.gen(function* () {
2250
2829
  const apiClient = yield* ApiClientService;
2251
2830
  const projectLink = yield* ProjectLinkService;
2252
2831
  const cwd = process.cwd();
2253
- const organizationId = Option12.getOrUndefined(org);
2832
+ const organizationId = Option13.getOrUndefined(org);
2254
2833
  const { items: apps } = yield* apiClient.request((client) => client.applications.list({ organizationId }));
2255
2834
  if (apps.length === 0) {
2256
- return yield* Effect18.fail(
2835
+ return yield* Effect19.fail(
2257
2836
  new NoApplicationsFoundError({
2258
2837
  message: 'No applications found. Create one in the Gigadrive console, then run "gigadrive link" again.'
2259
2838
  })
2260
2839
  );
2261
2840
  }
2262
- const explicitAppId = Option12.getOrUndefined(app);
2841
+ const explicitAppId = Option13.getOrUndefined(app);
2263
2842
  let applicationId;
2264
2843
  let linkedOrganizationId;
2265
2844
  if (explicitAppId !== void 0) {
2266
2845
  const match = apps.find((a) => a.id === explicitAppId);
2267
2846
  if (match === void 0) {
2268
- return yield* Effect18.fail(
2847
+ return yield* Effect19.fail(
2269
2848
  new ApplicationNotFoundError({
2270
2849
  message: `Application "${explicitAppId}" was not found among your applications.`
2271
2850
  })
@@ -2277,8 +2856,8 @@ var linkCommand = Command8.make(
2277
2856
  applicationId = apps[0].id;
2278
2857
  linkedOrganizationId = apps[0].organization.id;
2279
2858
  } else {
2280
- const chosen = yield* Prompt2.run(
2281
- Prompt2.select({
2859
+ const chosen = yield* Prompt3.run(
2860
+ Prompt3.select({
2282
2861
  message: "Select an application to link",
2283
2862
  choices: apps.map((a) => ({ title: `${a.name} (${a.organization.name})`, value: a }))
2284
2863
  })
@@ -2287,88 +2866,88 @@ var linkCommand = Command8.make(
2287
2866
  linkedOrganizationId = chosen.organization.id;
2288
2867
  }
2289
2868
  yield* projectLink.save(cwd, { applicationId, organizationId: linkedOrganizationId });
2290
- yield* Console8.log(`Linked this directory to application ${applicationId}.`);
2291
- yield* Console8.log('Tip: add ".gigadrive/" to your .gitignore.');
2869
+ yield* Console9.log(`Linked this directory to application ${applicationId}.`);
2870
+ yield* Console9.log('Tip: add ".gigadrive/" to your .gitignore.');
2292
2871
  }).pipe(
2293
- Effect18.catchTags({
2872
+ Effect19.catchTags({
2294
2873
  // Ctrl+C during the picker is a deliberate cancel — exit 0.
2295
- QuitException: () => Console8.log("Cancelled."),
2296
- NotAuthenticatedError: (err) => Console8.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2297
- Effect18.andThen(Effect18.fail(err))
2874
+ QuitException: () => Console9.log("Cancelled."),
2875
+ NotAuthenticatedError: (err) => Console9.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2876
+ Effect19.andThen(Effect19.fail(err))
2298
2877
  ),
2299
- ApiRequestError: (err) => Console8.error(`Failed to list applications: ${err.message}`).pipe(Effect18.andThen(Effect18.fail(err))),
2300
- NoApplicationsFoundError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2301
- ApplicationNotFoundError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err))),
2302
- ProjectLinkWriteError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err)))
2878
+ ApiRequestError: (err) => Console9.error(`Failed to list applications: ${err.message}`).pipe(Effect19.andThen(Effect19.fail(err))),
2879
+ NoApplicationsFoundError: (err) => Console9.error(err.message).pipe(Effect19.andThen(Effect19.fail(err))),
2880
+ ApplicationNotFoundError: (err) => Console9.error(err.message).pipe(Effect19.andThen(Effect19.fail(err))),
2881
+ ProjectLinkWriteError: (err) => Console9.error(err.message).pipe(Effect19.andThen(Effect19.fail(err)))
2303
2882
  })
2304
2883
  )
2305
2884
  );
2306
- var unlinkCommand = Command8.make(
2885
+ var unlinkCommand = Command9.make(
2307
2886
  "unlink",
2308
2887
  {},
2309
- () => Effect18.gen(function* () {
2888
+ () => Effect19.gen(function* () {
2310
2889
  const projectLink = yield* ProjectLinkService;
2311
2890
  yield* projectLink.remove(process.cwd());
2312
- yield* Console8.log("Unlinked this directory.");
2891
+ yield* Console9.log("Unlinked this directory.");
2313
2892
  }).pipe(
2314
- Effect18.catchTags({
2315
- ProjectLinkWriteError: (err) => Console8.error(err.message).pipe(Effect18.andThen(Effect18.fail(err)))
2893
+ Effect19.catchTags({
2894
+ ProjectLinkWriteError: (err) => Console9.error(err.message).pipe(Effect19.andThen(Effect19.fail(err)))
2316
2895
  })
2317
2896
  )
2318
2897
  );
2319
2898
 
2320
2899
  // src/commands/login/index.ts
2321
- import { Command as Command9 } from "@effect/cli";
2322
- import { Console as Console9, Effect as Effect19 } from "effect";
2323
- var loginCommand = Command9.make(
2900
+ import { Command as Command10 } from "@effect/cli";
2901
+ import { Console as Console10, Effect as Effect20 } from "effect";
2902
+ var loginCommand = Command10.make(
2324
2903
  "login",
2325
2904
  {},
2326
- () => Effect19.gen(function* () {
2327
- yield* Console9.log("Initiating login...");
2905
+ () => Effect20.gen(function* () {
2906
+ yield* Console10.log("Initiating login...");
2328
2907
  const auth = yield* AuthService;
2329
2908
  yield* auth.login;
2330
- const info = yield* auth.getUserInfo.pipe(Effect19.catchAll(() => Effect19.succeed({})));
2909
+ const info = yield* auth.getUserInfo.pipe(Effect20.catchAll(() => Effect20.succeed({})));
2331
2910
  const name = auth.inferUserName(info);
2332
- yield* Console9.log(`You are now logged in as ${name}.`);
2911
+ yield* Console10.log(`You are now logged in as ${name}.`);
2333
2912
  }).pipe(
2334
- Effect19.catchTags({
2335
- LoginFlowError: (err) => Console9.error(err.message),
2336
- DeviceAuthorizationError: (err) => Console9.error(`Login failed: ${err.message}`),
2337
- AuthorizationDeniedError: (err) => Console9.error(err.message),
2338
- DeviceCodeExpiredError: (err) => Console9.error(err.message),
2339
- TokenExchangeError: (err) => Console9.error(`Login failed: ${err.message}`),
2340
- OAuthDiscoveryError: (err) => Console9.error(`Login failed: ${err.message}`),
2341
- AuthStorageWriteError: (err) => Console9.error(`Failed to save credentials: ${err.message}`)
2913
+ Effect20.catchTags({
2914
+ LoginFlowError: (err) => Console10.error(err.message),
2915
+ DeviceAuthorizationError: (err) => Console10.error(`Login failed: ${err.message}`),
2916
+ AuthorizationDeniedError: (err) => Console10.error(err.message),
2917
+ DeviceCodeExpiredError: (err) => Console10.error(err.message),
2918
+ TokenExchangeError: (err) => Console10.error(`Login failed: ${err.message}`),
2919
+ OAuthDiscoveryError: (err) => Console10.error(`Login failed: ${err.message}`),
2920
+ AuthStorageWriteError: (err) => Console10.error(`Failed to save credentials: ${err.message}`)
2342
2921
  })
2343
2922
  )
2344
2923
  );
2345
2924
 
2346
2925
  // src/commands/logout/index.ts
2347
- import { Command as Command10 } from "@effect/cli";
2348
- import { Console as Console10, Effect as Effect20 } from "effect";
2349
- var logoutCommand = Command10.make(
2926
+ import { Command as Command11 } from "@effect/cli";
2927
+ import { Console as Console11, Effect as Effect21 } from "effect";
2928
+ var logoutCommand = Command11.make(
2350
2929
  "logout",
2351
2930
  {},
2352
- () => Effect20.gen(function* () {
2931
+ () => Effect21.gen(function* () {
2353
2932
  const auth = yield* AuthService;
2354
2933
  yield* auth.logout;
2355
- yield* Console10.log("Logged out.");
2934
+ yield* Console11.log("Logged out.");
2356
2935
  }).pipe(
2357
- Effect20.catchTags({
2358
- AuthStorageWriteError: (err) => Console10.error(`Failed to log out: ${err.message}`).pipe(Effect20.andThen(Effect20.fail(err)))
2936
+ Effect21.catchTags({
2937
+ AuthStorageWriteError: (err) => Console11.error(`Failed to log out: ${err.message}`).pipe(Effect21.andThen(Effect21.fail(err)))
2359
2938
  })
2360
2939
  )
2361
2940
  );
2362
2941
 
2363
2942
  // src/commands/platform/index.ts
2364
- import { Command as Command12 } from "@effect/cli";
2365
- import { Effect as Effect24 } from "effect";
2943
+ import { Command as Command13 } from "@effect/cli";
2944
+ import { Effect as Effect25 } from "effect";
2366
2945
 
2367
2946
  // src/commands/platform/deploy/index.ts
2368
- import { Command as Command11, Options as Options6, Prompt as Prompt3 } from "@effect/cli";
2947
+ import { Command as Command12, Options as Options7, Prompt as Prompt4 } from "@effect/cli";
2369
2948
  import { FileSystem as FileSystem9, Path as Path8 } from "@effect/platform";
2370
2949
  import { formatFileSize } from "@gigadrive/commons";
2371
- import { Console as Console11, Duration as Duration2, Effect as Effect23, Option as Option13, Schedule, Stream } from "effect";
2950
+ import { Console as Console12, Duration as Duration3, Effect as Effect24, Option as Option14, Schedule, Stream } from "effect";
2372
2951
  import * as os4 from "os";
2373
2952
  import * as path from "path";
2374
2953
 
@@ -2376,7 +2955,7 @@ import * as path from "path";
2376
2955
  import { FileSystem as FileSystem8, Path as Path7 } from "@effect/platform";
2377
2956
  import { getFilesForPattern } from "@gigadrive/build-utils";
2378
2957
  import archiver from "archiver";
2379
- import { Effect as Effect21 } from "effect";
2958
+ import { Effect as Effect22 } from "effect";
2380
2959
  import ignore from "ignore";
2381
2960
  import * as nodeFs from "fs";
2382
2961
  import * as nodeFsPromises from "fs/promises";
@@ -2389,22 +2968,33 @@ var MANAGED_IGNORE_PATTERNS = [
2389
2968
  "**/.DS_Store",
2390
2969
  "**/Thumbs.db"
2391
2970
  ];
2971
+ var CONTAINER_BUILD_FILE_PATTERNS = [
2972
+ "!Dockerfile",
2973
+ "!**/Dockerfile",
2974
+ "!**/*.Dockerfile",
2975
+ "!**/Dockerfile.*",
2976
+ "!compose.yaml",
2977
+ "!compose.yml",
2978
+ "!docker-compose.yaml",
2979
+ "!docker-compose.yml"
2980
+ ];
2981
+ var DOCKER_BUILD_IGNORE_FILE = ".dockerignore";
2392
2982
  var readIgnoreFile = (fs, ignorePath) => fs.readFileString(ignorePath, "utf8").pipe(
2393
- Effect21.map((content) => content.split("\n").filter((line) => line.trim() !== "")),
2394
- Effect21.catchAll(() => Effect21.succeed([]))
2983
+ Effect22.map((content) => content.split("\n").filter((line) => line.trim() !== "")),
2984
+ Effect22.catchAll(() => Effect22.succeed([]))
2395
2985
  );
2396
- var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) => Effect21.gen(function* () {
2397
- const items = yield* fs.readDirectory(dir).pipe(Effect21.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${dir}` })));
2986
+ var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules, ignoreFileNames) => Effect22.gen(function* () {
2987
+ const items = yield* fs.readDirectory(dir).pipe(Effect22.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${dir}` })));
2398
2988
  for (const item of items) {
2399
2989
  const fullPath = pathService.join(dir, item);
2400
2990
  const relativePath = pathService.relative(baseDir, fullPath);
2401
- const stat = yield* Effect21.tryPromise({
2991
+ const stat = yield* Effect22.tryPromise({
2402
2992
  try: () => nodeFsPromises.lstat(fullPath),
2403
2993
  catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
2404
2994
  });
2405
2995
  if (stat.isDirectory()) {
2406
2996
  if (ignoreRules.ignores(`${relativePath}/`)) continue;
2407
- for (const ignoreFileName of IGNORE_FILE_NAMES) {
2997
+ for (const ignoreFileName of ignoreFileNames) {
2408
2998
  const ignoreFilePath = pathService.join(fullPath, ignoreFileName);
2409
2999
  const patterns = yield* readIgnoreFile(fs, ignoreFilePath);
2410
3000
  if (patterns.length > 0) {
@@ -2415,17 +3005,18 @@ var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) => Effe
2415
3005
  );
2416
3006
  }
2417
3007
  }
2418
- yield* collectIgnorePatterns(fs, pathService, fullPath, baseDir, ignoreRules);
3008
+ yield* collectIgnorePatterns(fs, pathService, fullPath, baseDir, ignoreRules, ignoreFileNames);
2419
3009
  }
2420
3010
  }
2421
- }).pipe(Effect21.catchAll(() => Effect21.void));
2422
- var initializeIgnoreRules = (fs, pathService, baseDir, useIgnoreFiles, useManagedIgnore) => Effect21.gen(function* () {
3011
+ }).pipe(Effect22.catchAll(() => Effect22.void));
3012
+ var initializeIgnoreRules = (fs, pathService, baseDir, useIgnoreFiles, useManagedIgnore, buildsContainerImages) => Effect22.gen(function* () {
2423
3013
  const ignoreRules = ignore();
3014
+ const ignoreFileNames = buildsContainerImages ? IGNORE_FILE_NAMES.filter((name) => name !== DOCKER_BUILD_IGNORE_FILE) : IGNORE_FILE_NAMES;
2424
3015
  if (useManagedIgnore) {
2425
3016
  ignoreRules.add(MANAGED_IGNORE_PATTERNS);
2426
3017
  }
2427
3018
  if (useIgnoreFiles) {
2428
- for (const ignoreFileName of IGNORE_FILE_NAMES) {
3019
+ for (const ignoreFileName of ignoreFileNames) {
2429
3020
  const ignoreFilePath = pathService.join(baseDir, ignoreFileName);
2430
3021
  const patterns = yield* readIgnoreFile(fs, ignoreFilePath);
2431
3022
  if (patterns.length > 0) {
@@ -2434,18 +3025,19 @@ var initializeIgnoreRules = (fs, pathService, baseDir, useIgnoreFiles, useManage
2434
3025
  );
2435
3026
  }
2436
3027
  }
2437
- yield* collectIgnorePatterns(fs, pathService, baseDir, baseDir, ignoreRules);
3028
+ yield* collectIgnorePatterns(fs, pathService, baseDir, baseDir, ignoreRules, ignoreFileNames);
3029
+ ignoreRules.add(CONTAINER_BUILD_FILE_PATTERNS);
2438
3030
  }
2439
3031
  return ignoreRules;
2440
3032
  });
2441
- var getFilesToInclude = (fs, pathService, dir, ignoreRules) => Effect21.gen(function* () {
3033
+ var getFilesToInclude = (fs, pathService, dir, ignoreRules) => Effect22.gen(function* () {
2442
3034
  const filesToInclude = [];
2443
- const walkDir = (currentDir) => Effect21.gen(function* () {
2444
- const items = yield* fs.readDirectory(currentDir).pipe(Effect21.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${currentDir}` })));
3035
+ const walkDir = (currentDir) => Effect22.gen(function* () {
3036
+ const items = yield* fs.readDirectory(currentDir).pipe(Effect22.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${currentDir}` })));
2445
3037
  for (const item of items) {
2446
3038
  const fullPath = pathService.join(currentDir, item);
2447
3039
  const relativePath = pathService.relative(dir, fullPath);
2448
- const stat = yield* Effect21.tryPromise({
3040
+ const stat = yield* Effect22.tryPromise({
2449
3041
  try: () => nodeFsPromises.lstat(fullPath),
2450
3042
  catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
2451
3043
  });
@@ -2459,27 +3051,28 @@ var getFilesToInclude = (fs, pathService, dir, ignoreRules) => Effect21.gen(func
2459
3051
  }
2460
3052
  }
2461
3053
  }
2462
- }).pipe(Effect21.catchAll(() => Effect21.void));
3054
+ }).pipe(Effect22.catchAll(() => Effect22.void));
2463
3055
  yield* walkDir(dir);
2464
3056
  return filesToInclude;
2465
3057
  });
2466
- var ArchiveService = class extends Effect21.Service()("ArchiveService", {
3058
+ var ArchiveService = class extends Effect22.Service()("ArchiveService", {
2467
3059
  accessors: true,
2468
- effect: Effect21.gen(function* () {
3060
+ effect: Effect22.gen(function* () {
2469
3061
  const fs = yield* FileSystem8.FileSystem;
2470
3062
  const pathService = yield* Path7.Path;
2471
- const createZipArchive = Effect21.fn("ArchiveService.createZipArchive")(function* (inputDir, outputFile, options = {}) {
2472
- yield* Effect21.annotateCurrentSpan("inputDir", inputDir);
2473
- yield* Effect21.annotateCurrentSpan("outputFile", outputFile);
2474
- yield* Effect21.log("Creating zip archive", { inputDir, outputFile });
3063
+ const createZipArchive = Effect22.fn("ArchiveService.createZipArchive")(function* (inputDir, outputFile, options = {}) {
3064
+ yield* Effect22.annotateCurrentSpan("inputDir", inputDir);
3065
+ yield* Effect22.annotateCurrentSpan("outputFile", outputFile);
3066
+ yield* Effect22.log("Creating zip archive", { inputDir, outputFile });
2475
3067
  const ignoreRules = yield* initializeIgnoreRules(
2476
3068
  fs,
2477
3069
  pathService,
2478
3070
  inputDir,
2479
3071
  options.useIgnoreFiles !== false,
2480
- options.useManagedIgnore !== false
3072
+ options.useManagedIgnore !== false,
3073
+ options.buildsContainerImages === true
2481
3074
  );
2482
- const filesToInclude = options.whitelist ? yield* Effect21.tryPromise({
3075
+ const filesToInclude = options.whitelist ? yield* Effect22.tryPromise({
2483
3076
  try: () => Promise.all(
2484
3077
  options.whitelist.map((file) => getFilesForPattern(file, inputDir, options.excludeFiles ?? []))
2485
3078
  ),
@@ -2487,25 +3080,25 @@ var ArchiveService = class extends Effect21.Service()("ArchiveService", {
2487
3080
  message: "Failed to resolve whitelist patterns",
2488
3081
  cause: error instanceof Error ? error.message : String(error)
2489
3082
  })
2490
- }) : yield* Effect21.gen(function* () {
3083
+ }) : yield* Effect22.gen(function* () {
2491
3084
  if (options.excludeFiles && options.excludeFiles.length > 0) {
2492
3085
  ignoreRules.add(options.excludeFiles);
2493
3086
  }
2494
3087
  return yield* getFilesToInclude(fs, pathService, inputDir, ignoreRules).pipe(
2495
- Effect21.map((files) => [files])
3088
+ Effect22.map((files) => [files])
2496
3089
  );
2497
3090
  });
2498
- const archiveExists = yield* fs.exists(outputFile).pipe(Effect21.catchAll(() => Effect21.succeed(false)));
3091
+ const archiveExists = yield* fs.exists(outputFile).pipe(Effect22.catchAll(() => Effect22.succeed(false)));
2499
3092
  if (archiveExists) {
2500
3093
  yield* fs.remove(outputFile).pipe(
2501
- Effect21.mapError(
3094
+ Effect22.mapError(
2502
3095
  (error) => new ArchiveCreateError({
2503
3096
  message: `Failed to remove existing archive: ${String(error)}`
2504
3097
  })
2505
3098
  )
2506
3099
  );
2507
3100
  }
2508
- yield* Effect21.tryPromise({
3101
+ yield* Effect22.tryPromise({
2509
3102
  try: () => new Promise((resolve, reject) => {
2510
3103
  const output = nodeFs.createWriteStream(outputFile);
2511
3104
  const archive = archiver("zip", { zlib: { level: 9 } });
@@ -2524,14 +3117,14 @@ var ArchiveService = class extends Effect21.Service()("ArchiveService", {
2524
3117
  })
2525
3118
  });
2526
3119
  const fileInfo = yield* fs.stat(outputFile).pipe(
2527
- Effect21.mapError(
3120
+ Effect22.mapError(
2528
3121
  (error) => new ArchiveCreateError({
2529
3122
  message: `Failed to stat archive: ${String(error)}`
2530
3123
  })
2531
3124
  )
2532
3125
  );
2533
3126
  const size = Number(fileInfo.size);
2534
- yield* Effect21.log("Archive created", { size });
3127
+ yield* Effect22.log("Archive created", { size });
2535
3128
  return { path: outputFile, size };
2536
3129
  });
2537
3130
  return { createZipArchive };
@@ -2540,32 +3133,32 @@ var ArchiveService = class extends Effect21.Service()("ArchiveService", {
2540
3133
  };
2541
3134
 
2542
3135
  // src/services/deployment-api.ts
2543
- import { Effect as Effect22 } from "effect";
2544
- var DeploymentApiService = class extends Effect22.Service()("DeploymentApiService", {
3136
+ import { Effect as Effect23 } from "effect";
3137
+ var DeploymentApiService = class extends Effect23.Service()("DeploymentApiService", {
2545
3138
  accessors: true,
2546
3139
  dependencies: [ApiClientService.Default],
2547
- effect: Effect22.gen(function* () {
3140
+ effect: Effect23.gen(function* () {
2548
3141
  const apiClient = yield* ApiClientService;
2549
3142
  const getClient = apiClient.getClient.pipe(
2550
- Effect22.mapError((err) => new DeploymentAuthError({ message: `Authentication failed: ${err.message}` }))
3143
+ Effect23.mapError((err) => new DeploymentAuthError({ message: `Authentication failed: ${err.message}` }))
2551
3144
  );
2552
- const createDeployment = Effect22.fn("DeploymentApiService.createDeployment")(function* (applicationId) {
2553
- yield* Effect22.annotateCurrentSpan("applicationId", applicationId);
2554
- yield* Effect22.log("Creating deployment", { applicationId });
3145
+ const createDeployment = Effect23.fn("DeploymentApiService.createDeployment")(function* (applicationId) {
3146
+ yield* Effect23.annotateCurrentSpan("applicationId", applicationId);
3147
+ yield* Effect23.log("Creating deployment", { applicationId });
2555
3148
  const client = yield* getClient;
2556
- const deployment = yield* Effect22.tryPromise({
3149
+ const deployment = yield* Effect23.tryPromise({
2557
3150
  try: () => client.deployments.create({ applicationId }),
2558
3151
  catch: (error) => new DeploymentCreateError({
2559
3152
  message: `Failed to create deployment: ${error instanceof Error ? error.message : String(error)}`
2560
3153
  })
2561
3154
  });
2562
- yield* Effect22.log("Deployment created", { deploymentId: deployment.id });
3155
+ yield* Effect23.log("Deployment created", { deploymentId: deployment.id });
2563
3156
  return deployment.id;
2564
3157
  });
2565
- const startMultipartUpload = Effect22.fn("DeploymentApiService.startMultipartUpload")(function* (deploymentId) {
2566
- yield* Effect22.annotateCurrentSpan("deploymentId", deploymentId);
3158
+ const startMultipartUpload = Effect23.fn("DeploymentApiService.startMultipartUpload")(function* (deploymentId) {
3159
+ yield* Effect23.annotateCurrentSpan("deploymentId", deploymentId);
2567
3160
  const client = yield* getClient;
2568
- const result = yield* Effect22.tryPromise({
3161
+ const result = yield* Effect23.tryPromise({
2569
3162
  try: () => client.deployments.startUpload(deploymentId),
2570
3163
  catch: (error) => new UploadStartError({
2571
3164
  message: `Failed to start multipart upload: ${error instanceof Error ? error.message : String(error)}`
@@ -2573,9 +3166,9 @@ var DeploymentApiService = class extends Effect22.Service()("DeploymentApiServic
2573
3166
  });
2574
3167
  return result.uploadId;
2575
3168
  });
2576
- const getPresignedUrl = Effect22.fn("DeploymentApiService.getPresignedUrl")(function* (deploymentId, uploadId, partNumber) {
3169
+ const getPresignedUrl = Effect23.fn("DeploymentApiService.getPresignedUrl")(function* (deploymentId, uploadId, partNumber) {
2577
3170
  const client = yield* getClient;
2578
- const result = yield* Effect22.tryPromise({
3171
+ const result = yield* Effect23.tryPromise({
2579
3172
  try: () => client.deployments.getPresignedUrl(deploymentId, uploadId, partNumber),
2580
3173
  catch: (error) => new PresignedUrlError({
2581
3174
  message: `Failed to get presigned URL: ${error instanceof Error ? error.message : String(error)}`,
@@ -2584,11 +3177,11 @@ var DeploymentApiService = class extends Effect22.Service()("DeploymentApiServic
2584
3177
  });
2585
3178
  return result.url;
2586
3179
  });
2587
- const uploadPart = Effect22.fn("DeploymentApiService.uploadPart")(function* (presignedUrl, data, partNumber) {
2588
- yield* Effect22.annotateCurrentSpan("partNumber", partNumber);
2589
- yield* Effect22.annotateCurrentSpan("size", data.length);
3180
+ const uploadPart = Effect23.fn("DeploymentApiService.uploadPart")(function* (presignedUrl, data, partNumber) {
3181
+ yield* Effect23.annotateCurrentSpan("partNumber", partNumber);
3182
+ yield* Effect23.annotateCurrentSpan("size", data.length);
2590
3183
  const client = yield* getClient;
2591
- const result = yield* Effect22.tryPromise({
3184
+ const result = yield* Effect23.tryPromise({
2592
3185
  try: () => client.deployments.uploadPart(presignedUrl, data, partNumber),
2593
3186
  catch: (error) => new UploadPartError({
2594
3187
  message: `Failed to upload part ${partNumber}: ${error instanceof Error ? error.message : String(error)}`,
@@ -2597,21 +3190,21 @@ var DeploymentApiService = class extends Effect22.Service()("DeploymentApiServic
2597
3190
  });
2598
3191
  return result;
2599
3192
  });
2600
- const completeUpload = Effect22.fn("DeploymentApiService.completeUpload")(function* (deploymentId, uploadId, parts) {
2601
- yield* Effect22.annotateCurrentSpan("deploymentId", deploymentId);
2602
- yield* Effect22.annotateCurrentSpan("partsCount", parts.length);
3193
+ const completeUpload = Effect23.fn("DeploymentApiService.completeUpload")(function* (deploymentId, uploadId, parts) {
3194
+ yield* Effect23.annotateCurrentSpan("deploymentId", deploymentId);
3195
+ yield* Effect23.annotateCurrentSpan("partsCount", parts.length);
2603
3196
  const client = yield* getClient;
2604
- yield* Effect22.tryPromise({
3197
+ yield* Effect23.tryPromise({
2605
3198
  try: () => client.deployments.completeUpload(deploymentId, uploadId, parts),
2606
3199
  catch: (error) => new UploadCompleteError({
2607
3200
  message: `Failed to complete upload: ${error instanceof Error ? error.message : String(error)}`
2608
3201
  })
2609
3202
  });
2610
- yield* Effect22.log("Upload completed successfully");
3203
+ yield* Effect23.log("Upload completed successfully");
2611
3204
  });
2612
- const getDeploymentStatus = Effect22.fn("DeploymentApiService.getDeploymentStatus")(function* (deploymentId) {
3205
+ const getDeploymentStatus = Effect23.fn("DeploymentApiService.getDeploymentStatus")(function* (deploymentId) {
2613
3206
  const client = yield* getClient;
2614
- const deployment = yield* Effect22.tryPromise({
3207
+ const deployment = yield* Effect23.tryPromise({
2615
3208
  try: () => client.deployments.get(deploymentId),
2616
3209
  catch: (error) => new DeploymentStatusError({
2617
3210
  message: `Failed to get deployment status: ${error instanceof Error ? error.message : String(error)}`
@@ -2619,9 +3212,9 @@ var DeploymentApiService = class extends Effect22.Service()("DeploymentApiServic
2619
3212
  });
2620
3213
  return deployment.status;
2621
3214
  });
2622
- const getLogs = Effect22.fn("DeploymentApiService.getLogs")(function* (deploymentId, options) {
3215
+ const getLogs = Effect23.fn("DeploymentApiService.getLogs")(function* (deploymentId, options) {
2623
3216
  const client = yield* getClient;
2624
- const result = yield* Effect22.tryPromise({
3217
+ const result = yield* Effect23.tryPromise({
2625
3218
  try: () => client.deployments.getLogs(deploymentId, options),
2626
3219
  catch: (error) => new DeploymentLogsFetchError({
2627
3220
  message: `Failed to get logs: ${error instanceof Error ? error.message : String(error)}`
@@ -2629,9 +3222,9 @@ var DeploymentApiService = class extends Effect22.Service()("DeploymentApiServic
2629
3222
  });
2630
3223
  return result;
2631
3224
  });
2632
- const getHostnames = Effect22.fn("DeploymentApiService.getHostnames")(function* (deploymentId) {
3225
+ const getHostnames = Effect23.fn("DeploymentApiService.getHostnames")(function* (deploymentId) {
2633
3226
  const client = yield* getClient;
2634
- const result = yield* Effect22.tryPromise({
3227
+ const result = yield* Effect23.tryPromise({
2635
3228
  try: () => client.deployments.getHostnames(deploymentId),
2636
3229
  catch: (error) => new DeploymentHostnamesFetchError({
2637
3230
  message: `Failed to get hostnames: ${error instanceof Error ? error.message : String(error)}`
@@ -2654,39 +3247,39 @@ var DeploymentApiService = class extends Effect22.Service()("DeploymentApiServic
2654
3247
  };
2655
3248
 
2656
3249
  // src/commands/platform/deploy/index.ts
2657
- var appOption5 = Options6.text("app").pipe(
2658
- Options6.withAlias("a"),
2659
- Options6.withDescription("Application ID to deploy to (overrides the linked application)"),
2660
- Options6.optional
3250
+ var appOption6 = Options7.text("app").pipe(
3251
+ Options7.withAlias("a"),
3252
+ Options7.withDescription("Application ID to deploy to (overrides the linked application)"),
3253
+ Options7.optional
2661
3254
  );
2662
- var orgOption5 = Options6.text("org").pipe(
2663
- Options6.withAlias("o"),
2664
- Options6.withDescription("Organization ID to use when automatically creating an application"),
2665
- Options6.optional
3255
+ var orgOption6 = Options7.text("org").pipe(
3256
+ Options7.withAlias("o"),
3257
+ Options7.withDescription("Organization ID to use when automatically creating an application"),
3258
+ Options7.optional
2666
3259
  );
2667
- var nameOption2 = Options6.text("name").pipe(
2668
- Options6.withAlias("n"),
2669
- Options6.withDescription("Application name to use when automatically creating an application"),
2670
- Options6.optional
3260
+ var nameOption2 = Options7.text("name").pipe(
3261
+ Options7.withAlias("n"),
3262
+ Options7.withDescription("Application name to use when automatically creating an application"),
3263
+ Options7.optional
2671
3264
  );
2672
- var createAndLinkDeploymentApplication = (input) => Effect23.gen(function* () {
3265
+ var createAndLinkDeploymentApplication = (input) => Effect24.gen(function* () {
2673
3266
  const projectLink = yield* ProjectLinkService;
2674
3267
  const apiClient = yield* ApiClientService;
2675
3268
  const { items: organizations } = yield* apiClient.request((client) => client.organizations.list());
2676
- const availableOrganizations = Option13.match(input.org, {
3269
+ const availableOrganizations = Option14.match(input.org, {
2677
3270
  onNone: () => organizations,
2678
3271
  onSome: (organizationId) => organizations.filter((organization2) => organization2.id === organizationId)
2679
3272
  });
2680
3273
  if (availableOrganizations.length === 0) {
2681
3274
  return yield* new NoOrganizationsFoundError({
2682
- message: Option13.match(input.org, {
3275
+ message: Option14.match(input.org, {
2683
3276
  onNone: () => 'No organization is available for this deployment. Create an organization, then run "gigadrive deploy" again.',
2684
3277
  onSome: (organizationId) => `Organization "${organizationId}" was not found among your organizations.`
2685
3278
  })
2686
3279
  });
2687
3280
  }
2688
- const organization = availableOrganizations.length === 1 ? availableOrganizations[0] : yield* Prompt3.run(
2689
- Prompt3.select({
3281
+ const organization = availableOrganizations.length === 1 ? availableOrganizations[0] : yield* Prompt4.run(
3282
+ Prompt4.select({
2690
3283
  message: "Select an organization for this application",
2691
3284
  choices: availableOrganizations.map((candidate) => ({
2692
3285
  title: candidate.name,
@@ -2695,7 +3288,7 @@ var createAndLinkDeploymentApplication = (input) => Effect23.gen(function* () {
2695
3288
  })
2696
3289
  );
2697
3290
  const inferredName = path.basename(input.cwd) || "Application";
2698
- const applicationName = Option13.match(input.name, {
3291
+ const applicationName = Option14.match(input.name, {
2699
3292
  onNone: () => inferredName,
2700
3293
  onSome: (name) => name
2701
3294
  }).trim();
@@ -2709,104 +3302,108 @@ var createAndLinkDeploymentApplication = (input) => Effect23.gen(function* () {
2709
3302
  applicationId: application.id,
2710
3303
  organizationId: organization.id
2711
3304
  });
2712
- yield* Console11.log(`Created and linked application ${application.name} (${application.id}).`);
3305
+ yield* Console12.log(`Created and linked application ${application.name} (${application.id}).`);
2713
3306
  return application.id;
2714
3307
  });
2715
- var resolveLinkedDeploymentApplication = (input) => Effect23.gen(function* () {
3308
+ var resolveLinkedDeploymentApplication = (input) => Effect24.gen(function* () {
2716
3309
  const projectLink = yield* ProjectLinkService;
2717
3310
  const existingLink = yield* projectLink.load(input.cwd);
2718
- return yield* Option13.match(existingLink, {
3311
+ return yield* Option14.match(existingLink, {
2719
3312
  onNone: () => createAndLinkDeploymentApplication(input),
2720
- onSome: (link) => Effect23.succeed(link.applicationId)
3313
+ onSome: (link) => Effect24.succeed(link.applicationId)
2721
3314
  });
2722
3315
  });
2723
- var resolveDeploymentApplication = (input) => Option13.match(input.app, {
3316
+ var resolveDeploymentApplication = (input) => Option14.match(input.app, {
2724
3317
  onNone: () => resolveLinkedDeploymentApplication(input),
2725
- onSome: Effect23.succeed
3318
+ onSome: Effect24.succeed
2726
3319
  });
2727
- var deployCommand = Command11.make(
3320
+ var deployCommand = Command12.make(
2728
3321
  "deploy",
2729
- { app: appOption5, org: orgOption5, name: nameOption2 },
2730
- ({ app, org, name }) => Effect23.gen(function* () {
3322
+ { app: appOption6, org: orgOption6, name: nameOption2 },
3323
+ ({ app, org, name }) => Effect24.gen(function* () {
2731
3324
  const projectConfig = yield* ProjectConfigService;
2732
3325
  const deploymentApi = yield* DeploymentApiService;
2733
3326
  const archiveService = yield* ArchiveService;
2734
3327
  const pathService = yield* Path8.Path;
2735
3328
  const cwd = process.cwd();
2736
- yield* Effect23.log("Starting deploy command");
3329
+ yield* Effect24.log("Starting deploy command");
2737
3330
  const { config } = yield* projectConfig.resolve(cwd);
2738
3331
  const applicationId = yield* resolveDeploymentApplication({ app, org, name, cwd });
2739
- yield* Console11.log("Creating deployment...");
3332
+ yield* Console12.log("Creating deployment...");
2740
3333
  const deploymentId = yield* deploymentApi.createDeployment(applicationId);
2741
- yield* Console11.log(`Deployment ID: ${deploymentId}`);
2742
- yield* Console11.log("Creating archive...");
3334
+ yield* Console12.log(`Deployment ID: ${deploymentId}`);
3335
+ yield* Console12.log("Creating archive...");
2743
3336
  const archivePath = pathService.join(os4.tmpdir(), `project-${Date.now()}.zip`);
2744
3337
  const archive = yield* archiveService.createZipArchive(config.userArchive?.rootOverwrite || cwd, archivePath, {
2745
3338
  whitelist: config.userArchive?.fileWhitelist,
2746
- excludeFiles: config.excludeFiles
3339
+ excludeFiles: config.excludeFiles,
3340
+ buildsContainerImages: [
3341
+ ...config.entrypoints.flatMap((entrypoint) => entrypoint.container ? [entrypoint.container] : []),
3342
+ ...config.sidecars ?? []
3343
+ ].some((container) => container.source.type === "dockerfile")
2747
3344
  });
2748
- yield* Console11.log(`Archive created (${formatFileSize(archive.size)})`);
2749
- yield* Console11.log("Uploading archive...");
3345
+ yield* Console12.log(`Archive created (${formatFileSize(archive.size)})`);
3346
+ yield* Console12.log("Uploading archive...");
2750
3347
  yield* uploadArchive(deploymentId, archivePath, archive.size);
2751
- yield* Console11.log("Upload complete.");
2752
- yield* Console11.log("The deployment pipeline is now being provisioned. This may take a few seconds.");
3348
+ yield* Console12.log("Upload complete.");
3349
+ yield* Console12.log("The deployment pipeline is now being provisioned. This may take a few seconds.");
2753
3350
  yield* pollDeployment(deploymentId);
2754
3351
  }).pipe(
2755
- Effect23.catchTags({
2756
- QuitException: () => Console11.log("Cancelled."),
2757
- NotAuthenticatedError: (err) => Console11.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
2758
- Effect23.andThen(Effect23.fail(err))
3352
+ Effect24.catchTags({
3353
+ QuitException: () => Console12.log("Cancelled."),
3354
+ NotAuthenticatedError: (err) => Console12.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
3355
+ Effect24.andThen(Effect24.fail(err))
2759
3356
  ),
2760
- ApiRequestError: (err) => Console11.error(`Application setup failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2761
- NoOrganizationsFoundError: (err) => Console11.error(err.message).pipe(Effect23.andThen(Effect23.fail(err))),
2762
- ProjectLinkReadError: (err) => Console11.error(err.message).pipe(Effect23.andThen(Effect23.fail(err))),
2763
- ProjectLinkWriteError: (err) => Console11.error(err.message).pipe(Effect23.andThen(Effect23.fail(err))),
2764
- ConfigNotFoundError: (err) => Console11.error(err.message).pipe(Effect23.andThen(Effect23.fail(err))),
2765
- ConfigParseError: (err) => Console11.error(`Config parse error: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2766
- ConfigValidationError: (err) => Effect23.gen(function* () {
3357
+ ApiRequestError: (err) => Console12.error(`Application setup failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3358
+ NoOrganizationsFoundError: (err) => Console12.error(err.message).pipe(Effect24.andThen(Effect24.fail(err))),
3359
+ ProjectLinkReadError: (err) => Console12.error(err.message).pipe(Effect24.andThen(Effect24.fail(err))),
3360
+ ProjectLinkWriteError: (err) => Console12.error(err.message).pipe(Effect24.andThen(Effect24.fail(err))),
3361
+ ConfigNotFoundError: (err) => Console12.error(err.message).pipe(Effect24.andThen(Effect24.fail(err))),
3362
+ ConfigParseError: (err) => Console12.error(`Config parse error: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3363
+ ConfigValidationError: (err) => Effect24.gen(function* () {
2767
3364
  for (const e of err.errors) {
2768
- yield* Console11.error(e);
3365
+ yield* Console12.error(e);
2769
3366
  }
2770
- yield* Console11.error(err.message);
2771
- }).pipe(Effect23.andThen(Effect23.fail(err))),
2772
- DeploymentCreateError: (err) => Console11.error(`Deployment creation failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2773
- ArchiveCreateError: (err) => Console11.error(`Archive creation failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2774
- UploadStartError: (err) => Console11.error(`Upload failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2775
- UploadPartError: (err) => Console11.error(`Upload failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2776
- UploadCompleteError: (err) => Console11.error(`Upload failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2777
- PresignedUrlError: (err) => Console11.error(`Upload failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2778
- DeploymentAuthError: (err) => Console11.error(`Authentication failed: ${err.message}`).pipe(Effect23.andThen(Effect23.fail(err))),
2779
- DeploymentFailedError: (err) => Console11.error(err.message).pipe(Effect23.andThen(Effect23.fail(err)))
3367
+ yield* Console12.error(err.message);
3368
+ }).pipe(Effect24.andThen(Effect24.fail(err))),
3369
+ DeploymentCreateError: (err) => Console12.error(`Deployment creation failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3370
+ ArchiveCreateError: (err) => Console12.error(`Archive creation failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3371
+ UploadStartError: (err) => Console12.error(`Upload failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3372
+ UploadPartError: (err) => Console12.error(`Upload failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3373
+ UploadCompleteError: (err) => Console12.error(`Upload failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3374
+ PresignedUrlError: (err) => Console12.error(`Upload failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3375
+ DeploymentAuthError: (err) => Console12.error(`Authentication failed: ${err.message}`).pipe(Effect24.andThen(Effect24.fail(err))),
3376
+ DeploymentFailedError: (err) => Console12.error(err.message).pipe(Effect24.andThen(Effect24.fail(err)))
2780
3377
  })
2781
3378
  )
2782
3379
  );
2783
- var uploadArchive = (deploymentId, archivePath, fileSize) => Effect23.gen(function* () {
3380
+ var uploadArchive = (deploymentId, archivePath, fileSize) => Effect24.gen(function* () {
2784
3381
  const deploymentApi = yield* DeploymentApiService;
2785
3382
  const fs = yield* FileSystem9.FileSystem;
2786
3383
  const uploadId = yield* deploymentApi.startMultipartUpload(deploymentId);
2787
3384
  const FILE_CHUNK_SIZE = 10 * 1024 * 1024;
2788
3385
  const numChunks = Math.ceil(fileSize / FILE_CHUNK_SIZE);
2789
- yield* Effect23.log("Starting multipart upload", { uploadId, numChunks, fileSize });
2790
- const parts = yield* Effect23.all(
3386
+ yield* Effect24.log("Starting multipart upload", { uploadId, numChunks, fileSize });
3387
+ const parts = yield* Effect24.all(
2791
3388
  Array.from({ length: numChunks }, (_, i) => {
2792
3389
  const partNumber = i + 1;
2793
3390
  const start = i * FILE_CHUNK_SIZE;
2794
3391
  const bytesToRead = partNumber < numChunks ? FILE_CHUNK_SIZE : fileSize - start;
2795
- return Effect23.gen(function* () {
3392
+ return Effect24.gen(function* () {
2796
3393
  const presignedUrl = yield* deploymentApi.getPresignedUrl(deploymentId, uploadId, partNumber);
2797
3394
  const chunkData = yield* Stream.runCollect(fs.stream(archivePath, { offset: start, bytesToRead })).pipe(
2798
- Effect23.map((chunks) => {
3395
+ Effect24.map((chunks) => {
2799
3396
  const arrays = Array.from(chunks);
2800
3397
  return Buffer.concat(arrays);
2801
3398
  }),
2802
- Effect23.mapError(
3399
+ Effect24.mapError(
2803
3400
  (error) => new UploadPartError({
2804
3401
  message: `Failed to read chunk ${partNumber}: ${String(error)}`,
2805
3402
  partNumber
2806
3403
  })
2807
3404
  )
2808
3405
  );
2809
- yield* Effect23.log(`Uploading part ${partNumber}/${numChunks}`, { size: chunkData.length });
3406
+ yield* Effect24.log(`Uploading part ${partNumber}/${numChunks}`, { size: chunkData.length });
2810
3407
  return yield* deploymentApi.uploadPart(presignedUrl, chunkData, partNumber);
2811
3408
  });
2812
3409
  }),
@@ -2814,20 +3411,20 @@ var uploadArchive = (deploymentId, archivePath, fileSize) => Effect23.gen(functi
2814
3411
  );
2815
3412
  yield* deploymentApi.completeUpload(deploymentId, uploadId, parts);
2816
3413
  });
2817
- var pollDeployment = (deploymentId) => Effect23.gen(function* () {
3414
+ var pollDeployment = (deploymentId) => Effect24.gen(function* () {
2818
3415
  const deploymentApi = yield* DeploymentApiService;
2819
3416
  let lastStatus = "PENDING";
2820
3417
  let logOffset = 0;
2821
- yield* Console11.log("Status: Pending");
2822
- yield* Effect23.repeat(
2823
- Effect23.gen(function* () {
2824
- const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(Effect23.catchTag("DeploymentStatusError", () => Effect23.succeed(lastStatus)));
3418
+ yield* Console12.log("Status: Pending");
3419
+ yield* Effect24.repeat(
3420
+ Effect24.gen(function* () {
3421
+ const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(Effect24.catchTag("DeploymentStatusError", () => Effect24.succeed(lastStatus)));
2825
3422
  if (newStatus !== lastStatus) {
2826
3423
  lastStatus = newStatus;
2827
3424
  const label = newStatus.charAt(0) + newStatus.slice(1).toLowerCase();
2828
- yield* Console11.log(`Status: ${label}`);
3425
+ yield* Console12.log(`Status: ${label}`);
2829
3426
  }
2830
- const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(Effect23.catchTag("DeploymentLogsFetchError", () => Effect23.succeed(null)));
3427
+ const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(Effect24.catchTag("DeploymentLogsFetchError", () => Effect24.succeed(null)));
2831
3428
  if (logsPage) {
2832
3429
  for (const logEntry of logsPage.items) {
2833
3430
  logOffset++;
@@ -2835,86 +3432,86 @@ var pollDeployment = (deploymentId) => Effect23.gen(function* () {
2835
3432
  }
2836
3433
  }
2837
3434
  if (newStatus === "ACTIVE") {
2838
- const hostnames = yield* deploymentApi.getHostnames(deploymentId).pipe(Effect23.catchTag("DeploymentHostnamesFetchError", () => Effect23.succeed([])));
3435
+ const hostnames = yield* deploymentApi.getHostnames(deploymentId).pipe(Effect24.catchTag("DeploymentHostnamesFetchError", () => Effect24.succeed([])));
2839
3436
  const active = hostnames.find((h) => h.active) ?? hostnames.at(0);
2840
3437
  if (active) {
2841
- yield* Console11.log(`Deployed to https://${active.hostname}`);
3438
+ yield* Console12.log(`Deployed to https://${active.hostname}`);
2842
3439
  } else {
2843
- yield* Console11.log("Deployment is live.");
3440
+ yield* Console12.log("Deployment is live.");
2844
3441
  }
2845
- return yield* Effect23.fail("done");
3442
+ return yield* Effect24.fail("done");
2846
3443
  }
2847
3444
  if (newStatus === "FAILED") {
2848
- return yield* Effect23.fail(
3445
+ return yield* Effect24.fail(
2849
3446
  new DeploymentFailedError({
2850
3447
  message: "The deployment failed. Please check the logs for more information."
2851
3448
  })
2852
3449
  );
2853
3450
  }
2854
3451
  }),
2855
- Schedule.addDelay(Schedule.forever, () => Duration2.seconds(1))
3452
+ Schedule.addDelay(Schedule.forever, () => Duration3.seconds(1))
2856
3453
  ).pipe(
2857
- Effect23.catchAll((err) => {
2858
- if (err === "done") return Effect23.void;
2859
- return Effect23.fail(err);
3454
+ Effect24.catchAll((err) => {
3455
+ if (err === "done") return Effect24.void;
3456
+ return Effect24.fail(err);
2860
3457
  })
2861
3458
  );
2862
3459
  });
2863
3460
  var printLog = (logEntry) => {
2864
3461
  switch (logEntry.type) {
2865
3462
  case "ERROR":
2866
- return Console11.error(logEntry.message);
3463
+ return Console12.error(logEntry.message);
2867
3464
  case "WARN":
2868
- return Console11.warn(logEntry.message);
3465
+ return Console12.warn(logEntry.message);
2869
3466
  default:
2870
- return Console11.log(logEntry.message);
3467
+ return Console12.log(logEntry.message);
2871
3468
  }
2872
3469
  };
2873
3470
 
2874
3471
  // src/commands/platform/index.ts
2875
- var platformBase = Command12.make("platform", {}, () => Effect24.void);
2876
- var platformCommand = platformBase.pipe(Command12.withSubcommands([deployCommand]));
3472
+ var platformBase = Command13.make("platform", {}, () => Effect25.void);
3473
+ var platformCommand = platformBase.pipe(Command13.withSubcommands([deployCommand]));
2877
3474
 
2878
3475
  // src/commands/setup/index.ts
2879
- import { Args as Args4, Command as Command13, Options as Options7, Prompt as Prompt4 } from "@effect/cli";
2880
- import { Console as Console12, Effect as Effect25, Option as Option14 } from "effect";
2881
- var fileArg2 = Args4.text({ name: "file" }).pipe(
2882
- Args4.withDescription("Output file to write (default: .env.local)"),
2883
- Args4.optional
2884
- );
2885
- var appOption6 = Options7.text("app").pipe(
2886
- Options7.withAlias("a"),
2887
- Options7.withDescription("Application ID to set up (skips the interactive picker)"),
2888
- Options7.optional
2889
- );
2890
- var orgOption6 = Options7.text("org").pipe(
2891
- Options7.withAlias("o"),
2892
- Options7.withDescription("Only list applications belonging to this organization ID when picking"),
2893
- Options7.optional
2894
- );
2895
- var environmentOption2 = Options7.text("environment").pipe(
2896
- Options7.withAlias("e"),
2897
- Options7.withDescription("Environment slug to resolve overrides for (e.g. preview)"),
2898
- Options7.optional
2899
- );
2900
- var yesOption2 = Options7.boolean("yes").pipe(
2901
- Options7.withAlias("y"),
2902
- Options7.withDescription("Overwrite an existing file without confirmation")
2903
- );
2904
- var rotateOption2 = Options7.boolean("rotate").pipe(
2905
- Options7.withDescription("Force a fresh API key, revoking the previous one")
2906
- );
2907
- var setupCommand = Command13.make(
3476
+ import { Args as Args5, Command as Command14, Options as Options8, Prompt as Prompt5 } from "@effect/cli";
3477
+ import { Console as Console13, Effect as Effect26, Option as Option15 } from "effect";
3478
+ var fileArg2 = Args5.text({ name: "file" }).pipe(
3479
+ Args5.withDescription("Output file to write (default: .env.local)"),
3480
+ Args5.optional
3481
+ );
3482
+ var appOption7 = Options8.text("app").pipe(
3483
+ Options8.withAlias("a"),
3484
+ Options8.withDescription("Application ID to set up (skips the interactive picker)"),
3485
+ Options8.optional
3486
+ );
3487
+ var orgOption7 = Options8.text("org").pipe(
3488
+ Options8.withAlias("o"),
3489
+ Options8.withDescription("Only list applications belonging to this organization ID when picking"),
3490
+ Options8.optional
3491
+ );
3492
+ var environmentOption2 = Options8.text("environment").pipe(
3493
+ Options8.withAlias("e"),
3494
+ Options8.withDescription("Environment slug to resolve overrides for (e.g. preview)"),
3495
+ Options8.optional
3496
+ );
3497
+ var yesOption3 = Options8.boolean("yes").pipe(
3498
+ Options8.withAlias("y"),
3499
+ Options8.withDescription("Overwrite an existing file without confirmation")
3500
+ );
3501
+ var rotateOption2 = Options8.boolean("rotate").pipe(
3502
+ Options8.withDescription("Force a fresh API key, revoking the previous one")
3503
+ );
3504
+ var setupCommand = Command14.make(
2908
3505
  "setup",
2909
3506
  {
2910
3507
  file: fileArg2,
2911
- app: appOption6,
2912
- org: orgOption6,
3508
+ app: appOption7,
3509
+ org: orgOption7,
2913
3510
  environment: environmentOption2,
2914
- yes: yesOption2,
3511
+ yes: yesOption3,
2915
3512
  rotate: rotateOption2
2916
3513
  },
2917
- ({ file, app, org, environment, yes, rotate }) => Effect25.gen(function* () {
3514
+ ({ file, app, org, environment, yes, rotate }) => Effect26.gen(function* () {
2918
3515
  const apiClient = yield* ApiClientService;
2919
3516
  const projectLink = yield* ProjectLinkService;
2920
3517
  const envFile = yield* EnvFileService;
@@ -2922,29 +3519,29 @@ var setupCommand = Command13.make(
2922
3519
  const cwd = process.cwd();
2923
3520
  const existingLink = yield* projectLink.load(cwd);
2924
3521
  let applicationId;
2925
- if (Option14.isSome(existingLink)) {
3522
+ if (Option15.isSome(existingLink)) {
2926
3523
  applicationId = existingLink.value.applicationId;
2927
- if (Option14.isSome(app) || Option14.isSome(org)) {
2928
- yield* Console12.log(
3524
+ if (Option15.isSome(app) || Option15.isSome(org)) {
3525
+ yield* Console13.log(
2929
3526
  `Note: this directory is already linked to ${applicationId}; ignoring --app/--org. Run "gigadrive unlink" first to target a different application.`
2930
3527
  );
2931
3528
  }
2932
3529
  } else {
2933
- const organizationId = Option14.getOrUndefined(org);
3530
+ const organizationId = Option15.getOrUndefined(org);
2934
3531
  const { items: apps } = yield* apiClient.request((client) => client.applications.list({ organizationId }));
2935
3532
  if (apps.length === 0) {
2936
- return yield* Effect25.fail(
3533
+ return yield* Effect26.fail(
2937
3534
  new NoApplicationsFoundError({
2938
3535
  message: 'No applications found. Create one in the Gigadrive console, then run "gigadrive setup" again.'
2939
3536
  })
2940
3537
  );
2941
3538
  }
2942
- const explicitAppId = Option14.getOrUndefined(app);
3539
+ const explicitAppId = Option15.getOrUndefined(app);
2943
3540
  let chosen;
2944
3541
  if (explicitAppId !== void 0) {
2945
3542
  const match = apps.find((a) => a.id === explicitAppId);
2946
3543
  if (match === void 0) {
2947
- return yield* Effect25.fail(
3544
+ return yield* Effect26.fail(
2948
3545
  new ApplicationNotFoundError({
2949
3546
  message: `Application "${explicitAppId}" was not found among your applications.`
2950
3547
  })
@@ -2954,8 +3551,8 @@ var setupCommand = Command13.make(
2954
3551
  } else if (apps.length === 1) {
2955
3552
  chosen = apps[0];
2956
3553
  } else {
2957
- chosen = yield* Prompt4.run(
2958
- Prompt4.select({
3554
+ chosen = yield* Prompt5.run(
3555
+ Prompt5.select({
2959
3556
  message: "Select an application to set up",
2960
3557
  choices: apps.map((a) => ({ title: `${a.name} (${a.organization.name})`, value: a }))
2961
3558
  })
@@ -2963,83 +3560,83 @@ var setupCommand = Command13.make(
2963
3560
  }
2964
3561
  applicationId = chosen.id;
2965
3562
  yield* projectLink.save(cwd, { applicationId, organizationId: chosen.organization.id });
2966
- yield* Console12.log(`Linked this directory to application ${applicationId}.`);
3563
+ yield* Console13.log(`Linked this directory to application ${applicationId}.`);
2967
3564
  }
2968
- const target = Option14.getOrElse(file, () => ".env.local");
2969
- const environmentSlug = Option14.getOrUndefined(environment);
3565
+ const target = Option15.getOrElse(file, () => ".env.local");
3566
+ const environmentSlug = Option15.getOrUndefined(environment);
2970
3567
  const { items, omittedSensitive } = yield* apiClient.request(
2971
3568
  (client) => client.applications.envVars.pull(applicationId, environmentSlug ? { environment: environmentSlug } : void 0)
2972
3569
  );
2973
3570
  const existing = yield* envFile.read(target);
2974
- if (Option14.isSome(existing) && !yes) {
2975
- const overwrite = yield* Prompt4.run(
2976
- Prompt4.confirm({ message: `${target} already exists. Overwrite?`, initial: false })
3571
+ if (Option15.isSome(existing) && !yes) {
3572
+ const overwrite = yield* Prompt5.run(
3573
+ Prompt5.confirm({ message: `${target} already exists. Overwrite?`, initial: false })
2977
3574
  );
2978
3575
  if (!overwrite) {
2979
- return yield* Console12.log("Cancelled.");
3576
+ return yield* Console13.log("Cancelled.");
2980
3577
  }
2981
3578
  }
2982
3579
  const credentialEntries2 = yield* localCredentials.provision({
2983
3580
  applicationId,
2984
3581
  rotate,
2985
- existingContent: Option14.getOrUndefined(existing)
3582
+ existingContent: Option15.getOrUndefined(existing)
2986
3583
  });
2987
3584
  const entries = [...items.map((v) => ({ key: v.key, value: v.value })), ...credentialEntries2];
2988
3585
  yield* envFile.write(target, entries);
2989
3586
  const gitignored = yield* envFile.ensureGitignored(cwd, target);
2990
- yield* Console12.log("\nLocal dev environment ready.");
2991
- yield* Console12.log(` \u2022 Wrote ${items.length} variable(s) and API credentials to ${target}.`);
3587
+ yield* Console13.log("\nLocal dev environment ready.");
3588
+ yield* Console13.log(` \u2022 Wrote ${items.length} variable(s) and API credentials to ${target}.`);
2992
3589
  if (omittedSensitive > 0) {
2993
- yield* Console12.log(
3590
+ yield* Console13.log(
2994
3591
  ` \u2022 Skipped ${omittedSensitive} sensitive variable(s) (only production/preview hold secrets).`
2995
3592
  );
2996
3593
  }
2997
3594
  if (gitignored) {
2998
- yield* Console12.log(` \u2022 Added ${target} to .gitignore.`);
3595
+ yield* Console13.log(` \u2022 Added ${target} to .gitignore.`);
2999
3596
  }
3000
- yield* Console12.log(" \u2022 Your app can now call the Gigadrive API via the SDK (GIGADRIVE_CLIENT_ID/SECRET).");
3597
+ yield* Console13.log(" \u2022 Your app can now call the Gigadrive API via the SDK (GIGADRIVE_CLIENT_ID/SECRET).");
3001
3598
  }).pipe(
3002
- Effect25.catchTags({
3599
+ Effect26.catchTags({
3003
3600
  // Ctrl+C during a prompt is a deliberate cancel — exit 0.
3004
- QuitException: () => Console12.log("Cancelled."),
3005
- NotAuthenticatedError: (err) => Console12.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
3006
- Effect25.andThen(Effect25.fail(err))
3601
+ QuitException: () => Console13.log("Cancelled."),
3602
+ NotAuthenticatedError: (err) => Console13.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
3603
+ Effect26.andThen(Effect26.fail(err))
3007
3604
  ),
3008
- ApiRequestError: (err) => Console12.error(`Setup failed: ${err.message}`).pipe(Effect25.andThen(Effect25.fail(err))),
3009
- NoApplicationsFoundError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err))),
3010
- ApplicationNotFoundError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err))),
3011
- ProjectLinkReadError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err))),
3012
- ProjectLinkWriteError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err))),
3013
- EnvFileReadError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err))),
3014
- EnvFileWriteError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err))),
3015
- DevCredentialsStoreReadError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err))),
3016
- DevCredentialsStoreWriteError: (err) => Console12.error(err.message).pipe(Effect25.andThen(Effect25.fail(err)))
3605
+ ApiRequestError: (err) => Console13.error(`Setup failed: ${err.message}`).pipe(Effect26.andThen(Effect26.fail(err))),
3606
+ NoApplicationsFoundError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err))),
3607
+ ApplicationNotFoundError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err))),
3608
+ ProjectLinkReadError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err))),
3609
+ ProjectLinkWriteError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err))),
3610
+ EnvFileReadError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err))),
3611
+ EnvFileWriteError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err))),
3612
+ DevCredentialsStoreReadError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err))),
3613
+ DevCredentialsStoreWriteError: (err) => Console13.error(err.message).pipe(Effect26.andThen(Effect26.fail(err)))
3017
3614
  })
3018
3615
  )
3019
3616
  );
3020
3617
 
3021
3618
  // src/commands/whoami/index.ts
3022
- import { Command as Command14 } from "@effect/cli";
3023
- import { Console as Console13, Effect as Effect26 } from "effect";
3024
- var whoamiCommand = Command14.make(
3619
+ import { Command as Command15 } from "@effect/cli";
3620
+ import { Console as Console14, Effect as Effect27 } from "effect";
3621
+ var whoamiCommand = Command15.make(
3025
3622
  "whoami",
3026
3623
  {},
3027
- () => Effect26.gen(function* () {
3624
+ () => Effect27.gen(function* () {
3028
3625
  const auth = yield* AuthService;
3029
3626
  const info = yield* auth.getUserInfo;
3030
- yield* Console13.log(JSON.stringify(info, null, 2));
3627
+ yield* Console14.log(JSON.stringify(info, null, 2));
3031
3628
  }).pipe(
3032
- Effect26.catchTags({
3033
- NotAuthenticatedError: () => Console13.log('You are not logged in. Run "gigadrive login" to authenticate.'),
3034
- UserInfoFetchError: (err) => Console13.error(`Failed to retrieve user info: ${err.message}`),
3035
- OAuthDiscoveryError: (err) => Console13.error(`Failed to retrieve user info: ${err.message}`)
3629
+ Effect27.catchTags({
3630
+ NotAuthenticatedError: () => Console14.log('You are not logged in. Run "gigadrive login" to authenticate.'),
3631
+ UserInfoFetchError: (err) => Console14.error(`Failed to retrieve user info: ${err.message}`),
3632
+ OAuthDiscoveryError: (err) => Console14.error(`Failed to retrieve user info: ${err.message}`)
3036
3633
  })
3037
3634
  )
3038
3635
  );
3039
3636
 
3040
3637
  // src/index.ts
3041
- var gigadrive = Command15.make("gigadrive", {}, () => Effect27.void).pipe(
3042
- Command15.withSubcommands([
3638
+ var gigadrive = Command16.make("gigadrive", {}, () => Effect28.void).pipe(
3639
+ Command16.withSubcommands([
3043
3640
  loginCommand,
3044
3641
  logoutCommand,
3045
3642
  whoamiCommand,
@@ -3048,6 +3645,7 @@ var gigadrive = Command15.make("gigadrive", {}, () => Effect27.void).pipe(
3048
3645
  appsCommand,
3049
3646
  envCommand,
3050
3647
  deploymentsCommand,
3648
+ domainsCommand,
3051
3649
  aiCommand,
3052
3650
  buildCommand,
3053
3651
  debugCommand,
@@ -3056,7 +3654,7 @@ var gigadrive = Command15.make("gigadrive", {}, () => Effect27.void).pipe(
3056
3654
  setupCommand
3057
3655
  ])
3058
3656
  );
3059
- var cli = Command15.run(gigadrive, {
3657
+ var cli = Command16.run(gigadrive, {
3060
3658
  name: "Gigadrive CLI",
3061
3659
  version: package_default.version
3062
3660
  });
@@ -3078,5 +3676,5 @@ var ServicesLive = Layer.mergeAll(BaseServices, ApiClientLive, DeploymentApiLive
3078
3676
  var AppLive = Layer.mergeAll(ServicesLive, Logger.minimumLogLevel(LogLevel.Info)).pipe(
3079
3677
  Layer.provideMerge(NodeContext.layer)
3080
3678
  );
3081
- NodeRuntime.runMain(Effect27.provide(cli(process.argv), AppLive));
3679
+ NodeRuntime.runMain(Effect28.provide(cli(process.argv), AppLive));
3082
3680
  //# sourceMappingURL=index.mjs.map