gigadrive 2.6.1 → 2.7.0
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.cjs +1047 -450
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1039 -441
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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
|
|
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
|
|
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.
|
|
12
|
+
version: "2.7.0",
|
|
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({
|
|
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
|
-
|
|
1643
|
-
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
2430
|
+
var EnvFileService = class extends Effect15.Service()("EnvFileService", {
|
|
1852
2431
|
accessors: true,
|
|
1853
|
-
effect:
|
|
2432
|
+
effect: Effect15.gen(function* () {
|
|
1854
2433
|
const fs = yield* FileSystem6.FileSystem;
|
|
1855
2434
|
const pathService = yield* Path5.Path;
|
|
1856
|
-
const exists =
|
|
1857
|
-
return yield* fs.exists(filePath).pipe(
|
|
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 =
|
|
2438
|
+
const read = Effect15.fn("EnvFileService.read")(function* (filePath) {
|
|
1860
2439
|
const present = yield* exists(filePath);
|
|
1861
|
-
if (!present) return
|
|
1862
|
-
const contents = yield* fs.readFileString(filePath, "utf8").pipe(
|
|
1863
|
-
return
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
2492
|
+
var DevCredentialsStore = class extends Effect16.Service()("DevCredentialsStore", {
|
|
1914
2493
|
accessors: true,
|
|
1915
|
-
effect:
|
|
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 =
|
|
2500
|
+
const ensureDirectory = Effect16.gen(function* () {
|
|
1922
2501
|
yield* fs.makeDirectory(storeDir, { recursive: true }).pipe(
|
|
1923
|
-
|
|
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
|
-
|
|
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 =
|
|
1937
|
-
const present = yield* fs.exists(storeFile).pipe(
|
|
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(
|
|
1940
|
-
const json = yield*
|
|
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
|
-
|
|
2524
|
+
Effect16.mapError(() => new DevCredentialsStoreReadError({ message: "dev-keys.json has an invalid schema" }))
|
|
1946
2525
|
);
|
|
1947
2526
|
});
|
|
1948
|
-
const get =
|
|
2527
|
+
const get = Effect16.fn("DevCredentialsStore.get")(function* (applicationId) {
|
|
1949
2528
|
const store = yield* load;
|
|
1950
2529
|
const entry = store[applicationId];
|
|
1951
|
-
return entry ?
|
|
2530
|
+
return entry ? Option10.some(entry) : Option10.none();
|
|
1952
2531
|
});
|
|
1953
|
-
const set =
|
|
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
|
-
|
|
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
|
|
2556
|
+
var LocalCredentialsService = class extends Effect17.Service()("LocalCredentialsService", {
|
|
1978
2557
|
accessors: true,
|
|
1979
2558
|
dependencies: [ApiClientService.Default, DevCredentialsStore.Default],
|
|
1980
|
-
effect:
|
|
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 =
|
|
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 &&
|
|
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 (
|
|
1995
|
-
yield* apiClient.request((client) => client.apiKeys.delete(stored.value.apiKeyId)).pipe(
|
|
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
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
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
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
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 =
|
|
2024
|
-
|
|
2602
|
+
var sensitiveOption = Options5.boolean("sensitive").pipe(
|
|
2603
|
+
Options5.withDescription("Store the value as sensitive (hidden in API responses)")
|
|
2025
2604
|
);
|
|
2026
|
-
var envIdOption =
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
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 =
|
|
2032
|
-
|
|
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 =
|
|
2035
|
-
var fileArg =
|
|
2036
|
-
|
|
2037
|
-
|
|
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 =
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
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
|
|
2045
|
-
|
|
2046
|
-
|
|
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 =
|
|
2049
|
-
|
|
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 =
|
|
2052
|
-
|
|
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) =>
|
|
2055
|
-
if (
|
|
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*
|
|
2060
|
-
onSome: (value) =>
|
|
2061
|
-
onNone: () => projectLink.resolve(process.cwd()).pipe(
|
|
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 =
|
|
2644
|
+
var envListCommand = Command8.make(
|
|
2066
2645
|
"list",
|
|
2067
|
-
{ app:
|
|
2068
|
-
({ app, org }) =>
|
|
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*
|
|
2654
|
+
yield* Console8.log("No environment variables set.");
|
|
2076
2655
|
return;
|
|
2077
2656
|
}
|
|
2078
2657
|
for (const v of items) {
|
|
2079
|
-
yield*
|
|
2658
|
+
yield* Console8.log(`${v.key}=${v.sensitive ? "***" : v.value ?? ""}`);
|
|
2080
2659
|
}
|
|
2081
2660
|
}).pipe(
|
|
2082
|
-
|
|
2083
|
-
NotAuthenticatedError: (err) =>
|
|
2084
|
-
|
|
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) =>
|
|
2087
|
-
ProjectNotLinkedError: (err) =>
|
|
2088
|
-
ProjectLinkReadError: (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 =
|
|
2671
|
+
var envSetCommand = Command8.make(
|
|
2093
2672
|
"set",
|
|
2094
|
-
{ keyValue: keyValueArg, app:
|
|
2095
|
-
({ keyValue, app, org, sensitive, env }) =>
|
|
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*
|
|
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 =
|
|
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*
|
|
2691
|
+
yield* Console8.log(`Set ${created.key}.`);
|
|
2113
2692
|
}).pipe(
|
|
2114
|
-
|
|
2115
|
-
InvalidEnvVarFormatError: (err) =>
|
|
2116
|
-
NotAuthenticatedError: (err) =>
|
|
2117
|
-
|
|
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) =>
|
|
2120
|
-
ProjectNotLinkedError: (err) =>
|
|
2121
|
-
ProjectLinkReadError: (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 =
|
|
2704
|
+
var envRmCommand = Command8.make(
|
|
2126
2705
|
"rm",
|
|
2127
|
-
{ keyOrId: keyOrIdArg, app:
|
|
2128
|
-
({ keyOrId, app, org }) =>
|
|
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*
|
|
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*
|
|
2722
|
+
yield* Console8.log(`Removed ${target.key}.`);
|
|
2144
2723
|
}).pipe(
|
|
2145
|
-
|
|
2146
|
-
EnvVarNotFoundError: (err) =>
|
|
2147
|
-
NotAuthenticatedError: (err) =>
|
|
2148
|
-
|
|
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) =>
|
|
2151
|
-
ProjectNotLinkedError: (err) =>
|
|
2152
|
-
ProjectLinkReadError: (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 =
|
|
2735
|
+
var envPullCommand = Command8.make(
|
|
2157
2736
|
"pull",
|
|
2158
2737
|
{
|
|
2159
2738
|
file: fileArg,
|
|
2160
|
-
app:
|
|
2739
|
+
app: appOption4,
|
|
2161
2740
|
environment: environmentOption,
|
|
2162
|
-
yes:
|
|
2741
|
+
yes: yesOption2,
|
|
2163
2742
|
withCredentials: withCredentialsOption,
|
|
2164
2743
|
rotate: rotateOption
|
|
2165
2744
|
},
|
|
2166
|
-
({ file, app, environment, yes, withCredentials, rotate }) =>
|
|
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*
|
|
2171
|
-
onSome: (value) =>
|
|
2172
|
-
onNone: () => projectLink.resolve(process.cwd()).pipe(
|
|
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 =
|
|
2175
|
-
const environmentSlug =
|
|
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 (
|
|
2181
|
-
const overwrite = yield*
|
|
2182
|
-
|
|
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*
|
|
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:
|
|
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*
|
|
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*
|
|
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*
|
|
2788
|
+
yield* Console8.log(`Added ${target} to .gitignore.`);
|
|
2210
2789
|
}
|
|
2211
2790
|
}).pipe(
|
|
2212
|
-
|
|
2791
|
+
Effect18.catchTags({
|
|
2213
2792
|
// Ctrl+C during the overwrite prompt is a deliberate cancel — exit 0.
|
|
2214
|
-
QuitException: () =>
|
|
2215
|
-
NotAuthenticatedError: (err) =>
|
|
2216
|
-
|
|
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) =>
|
|
2219
|
-
ProjectNotLinkedError: (err) =>
|
|
2220
|
-
ProjectLinkReadError: (err) =>
|
|
2221
|
-
EnvFileReadError: (err) =>
|
|
2222
|
-
EnvFileWriteError: (err) =>
|
|
2223
|
-
DevCredentialsStoreReadError: (err) =>
|
|
2224
|
-
DevCredentialsStoreWriteError: (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 =
|
|
2807
|
+
var envBase = Command8.make("env", {}, () => Effect18.void);
|
|
2229
2808
|
var envCommand = envBase.pipe(
|
|
2230
|
-
|
|
2809
|
+
Command8.withSubcommands([envListCommand, envSetCommand, envRmCommand, envPullCommand])
|
|
2231
2810
|
);
|
|
2232
2811
|
|
|
2233
2812
|
// src/commands/link/index.ts
|
|
2234
|
-
import { Command as
|
|
2235
|
-
import { Console as
|
|
2236
|
-
var
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
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
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
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 =
|
|
2825
|
+
var linkCommand = Command9.make(
|
|
2247
2826
|
"link",
|
|
2248
|
-
{ app:
|
|
2249
|
-
({ app, org }) =>
|
|
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 =
|
|
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*
|
|
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 =
|
|
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*
|
|
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*
|
|
2281
|
-
|
|
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*
|
|
2291
|
-
yield*
|
|
2869
|
+
yield* Console9.log(`Linked this directory to application ${applicationId}.`);
|
|
2870
|
+
yield* Console9.log('Tip: add ".gigadrive/" to your .gitignore.');
|
|
2292
2871
|
}).pipe(
|
|
2293
|
-
|
|
2872
|
+
Effect19.catchTags({
|
|
2294
2873
|
// Ctrl+C during the picker is a deliberate cancel — exit 0.
|
|
2295
|
-
QuitException: () =>
|
|
2296
|
-
NotAuthenticatedError: (err) =>
|
|
2297
|
-
|
|
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) =>
|
|
2300
|
-
NoApplicationsFoundError: (err) =>
|
|
2301
|
-
ApplicationNotFoundError: (err) =>
|
|
2302
|
-
ProjectLinkWriteError: (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 =
|
|
2885
|
+
var unlinkCommand = Command9.make(
|
|
2307
2886
|
"unlink",
|
|
2308
2887
|
{},
|
|
2309
|
-
() =>
|
|
2888
|
+
() => Effect19.gen(function* () {
|
|
2310
2889
|
const projectLink = yield* ProjectLinkService;
|
|
2311
2890
|
yield* projectLink.remove(process.cwd());
|
|
2312
|
-
yield*
|
|
2891
|
+
yield* Console9.log("Unlinked this directory.");
|
|
2313
2892
|
}).pipe(
|
|
2314
|
-
|
|
2315
|
-
ProjectLinkWriteError: (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
|
|
2322
|
-
import { Console as
|
|
2323
|
-
var loginCommand =
|
|
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
|
-
() =>
|
|
2327
|
-
yield*
|
|
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(
|
|
2909
|
+
const info = yield* auth.getUserInfo.pipe(Effect20.catchAll(() => Effect20.succeed({})));
|
|
2331
2910
|
const name = auth.inferUserName(info);
|
|
2332
|
-
yield*
|
|
2911
|
+
yield* Console10.log(`You are now logged in as ${name}.`);
|
|
2333
2912
|
}).pipe(
|
|
2334
|
-
|
|
2335
|
-
LoginFlowError: (err) =>
|
|
2336
|
-
DeviceAuthorizationError: (err) =>
|
|
2337
|
-
AuthorizationDeniedError: (err) =>
|
|
2338
|
-
DeviceCodeExpiredError: (err) =>
|
|
2339
|
-
TokenExchangeError: (err) =>
|
|
2340
|
-
OAuthDiscoveryError: (err) =>
|
|
2341
|
-
AuthStorageWriteError: (err) =>
|
|
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
|
|
2348
|
-
import { Console as
|
|
2349
|
-
var logoutCommand =
|
|
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
|
-
() =>
|
|
2931
|
+
() => Effect21.gen(function* () {
|
|
2353
2932
|
const auth = yield* AuthService;
|
|
2354
2933
|
yield* auth.logout;
|
|
2355
|
-
yield*
|
|
2934
|
+
yield* Console11.log("Logged out.");
|
|
2356
2935
|
}).pipe(
|
|
2357
|
-
|
|
2358
|
-
AuthStorageWriteError: (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
|
|
2365
|
-
import { Effect as
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
2394
|
-
|
|
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) =>
|
|
2397
|
-
const items = yield* fs.readDirectory(dir).pipe(
|
|
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*
|
|
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
|
|
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(
|
|
2422
|
-
var initializeIgnoreRules = (fs, pathService, baseDir, useIgnoreFiles, useManagedIgnore) =>
|
|
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
|
|
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) =>
|
|
3033
|
+
var getFilesToInclude = (fs, pathService, dir, ignoreRules) => Effect22.gen(function* () {
|
|
2442
3034
|
const filesToInclude = [];
|
|
2443
|
-
const walkDir = (currentDir) =>
|
|
2444
|
-
const items = yield* fs.readDirectory(currentDir).pipe(
|
|
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*
|
|
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(
|
|
3054
|
+
}).pipe(Effect22.catchAll(() => Effect22.void));
|
|
2463
3055
|
yield* walkDir(dir);
|
|
2464
3056
|
return filesToInclude;
|
|
2465
3057
|
});
|
|
2466
|
-
var ArchiveService = class extends
|
|
3058
|
+
var ArchiveService = class extends Effect22.Service()("ArchiveService", {
|
|
2467
3059
|
accessors: true,
|
|
2468
|
-
effect:
|
|
3060
|
+
effect: Effect22.gen(function* () {
|
|
2469
3061
|
const fs = yield* FileSystem8.FileSystem;
|
|
2470
3062
|
const pathService = yield* Path7.Path;
|
|
2471
|
-
const createZipArchive =
|
|
2472
|
-
yield*
|
|
2473
|
-
yield*
|
|
2474
|
-
yield*
|
|
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*
|
|
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*
|
|
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
|
-
|
|
3088
|
+
Effect22.map((files) => [files])
|
|
2496
3089
|
);
|
|
2497
3090
|
});
|
|
2498
|
-
const archiveExists = yield* fs.exists(outputFile).pipe(
|
|
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
|
-
|
|
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*
|
|
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
|
-
|
|
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*
|
|
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
|
|
2544
|
-
var DeploymentApiService = class extends
|
|
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:
|
|
3140
|
+
effect: Effect23.gen(function* () {
|
|
2548
3141
|
const apiClient = yield* ApiClientService;
|
|
2549
3142
|
const getClient = apiClient.getClient.pipe(
|
|
2550
|
-
|
|
3143
|
+
Effect23.mapError((err) => new DeploymentAuthError({ message: `Authentication failed: ${err.message}` }))
|
|
2551
3144
|
);
|
|
2552
|
-
const createDeployment =
|
|
2553
|
-
yield*
|
|
2554
|
-
yield*
|
|
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*
|
|
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*
|
|
3155
|
+
yield* Effect23.log("Deployment created", { deploymentId: deployment.id });
|
|
2563
3156
|
return deployment.id;
|
|
2564
3157
|
});
|
|
2565
|
-
const startMultipartUpload =
|
|
2566
|
-
yield*
|
|
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*
|
|
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 =
|
|
3169
|
+
const getPresignedUrl = Effect23.fn("DeploymentApiService.getPresignedUrl")(function* (deploymentId, uploadId, partNumber) {
|
|
2577
3170
|
const client = yield* getClient;
|
|
2578
|
-
const result = yield*
|
|
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 =
|
|
2588
|
-
yield*
|
|
2589
|
-
yield*
|
|
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*
|
|
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 =
|
|
2601
|
-
yield*
|
|
2602
|
-
yield*
|
|
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*
|
|
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*
|
|
3203
|
+
yield* Effect23.log("Upload completed successfully");
|
|
2611
3204
|
});
|
|
2612
|
-
const getDeploymentStatus =
|
|
3205
|
+
const getDeploymentStatus = Effect23.fn("DeploymentApiService.getDeploymentStatus")(function* (deploymentId) {
|
|
2613
3206
|
const client = yield* getClient;
|
|
2614
|
-
const deployment = yield*
|
|
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 =
|
|
3215
|
+
const getLogs = Effect23.fn("DeploymentApiService.getLogs")(function* (deploymentId, options) {
|
|
2623
3216
|
const client = yield* getClient;
|
|
2624
|
-
const result = yield*
|
|
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 =
|
|
3225
|
+
const getHostnames = Effect23.fn("DeploymentApiService.getHostnames")(function* (deploymentId) {
|
|
2633
3226
|
const client = yield* getClient;
|
|
2634
|
-
const result = yield*
|
|
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
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
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
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
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 =
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
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) =>
|
|
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 =
|
|
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:
|
|
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*
|
|
2689
|
-
|
|
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 =
|
|
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*
|
|
3305
|
+
yield* Console12.log(`Created and linked application ${application.name} (${application.id}).`);
|
|
2713
3306
|
return application.id;
|
|
2714
3307
|
});
|
|
2715
|
-
var resolveLinkedDeploymentApplication = (input) =>
|
|
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*
|
|
3311
|
+
return yield* Option14.match(existingLink, {
|
|
2719
3312
|
onNone: () => createAndLinkDeploymentApplication(input),
|
|
2720
|
-
onSome: (link) =>
|
|
3313
|
+
onSome: (link) => Effect24.succeed(link.applicationId)
|
|
2721
3314
|
});
|
|
2722
3315
|
});
|
|
2723
|
-
var resolveDeploymentApplication = (input) =>
|
|
3316
|
+
var resolveDeploymentApplication = (input) => Option14.match(input.app, {
|
|
2724
3317
|
onNone: () => resolveLinkedDeploymentApplication(input),
|
|
2725
|
-
onSome:
|
|
3318
|
+
onSome: Effect24.succeed
|
|
2726
3319
|
});
|
|
2727
|
-
var deployCommand =
|
|
3320
|
+
var deployCommand = Command12.make(
|
|
2728
3321
|
"deploy",
|
|
2729
|
-
{ app:
|
|
2730
|
-
({ app, org, name }) =>
|
|
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*
|
|
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*
|
|
3332
|
+
yield* Console12.log("Creating deployment...");
|
|
2740
3333
|
const deploymentId = yield* deploymentApi.createDeployment(applicationId);
|
|
2741
|
-
yield*
|
|
2742
|
-
yield*
|
|
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*
|
|
2749
|
-
yield*
|
|
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*
|
|
2752
|
-
yield*
|
|
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
|
-
|
|
2756
|
-
QuitException: () =>
|
|
2757
|
-
NotAuthenticatedError: (err) =>
|
|
2758
|
-
|
|
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) =>
|
|
2761
|
-
NoOrganizationsFoundError: (err) =>
|
|
2762
|
-
ProjectLinkReadError: (err) =>
|
|
2763
|
-
ProjectLinkWriteError: (err) =>
|
|
2764
|
-
ConfigNotFoundError: (err) =>
|
|
2765
|
-
ConfigParseError: (err) =>
|
|
2766
|
-
ConfigValidationError: (err) =>
|
|
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*
|
|
3365
|
+
yield* Console12.error(e);
|
|
2769
3366
|
}
|
|
2770
|
-
yield*
|
|
2771
|
-
}).pipe(
|
|
2772
|
-
DeploymentCreateError: (err) =>
|
|
2773
|
-
ArchiveCreateError: (err) =>
|
|
2774
|
-
UploadStartError: (err) =>
|
|
2775
|
-
UploadPartError: (err) =>
|
|
2776
|
-
UploadCompleteError: (err) =>
|
|
2777
|
-
PresignedUrlError: (err) =>
|
|
2778
|
-
DeploymentAuthError: (err) =>
|
|
2779
|
-
DeploymentFailedError: (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) =>
|
|
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*
|
|
2790
|
-
const parts = yield*
|
|
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
|
|
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
|
-
|
|
3395
|
+
Effect24.map((chunks) => {
|
|
2799
3396
|
const arrays = Array.from(chunks);
|
|
2800
3397
|
return Buffer.concat(arrays);
|
|
2801
3398
|
}),
|
|
2802
|
-
|
|
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*
|
|
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) =>
|
|
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*
|
|
2822
|
-
yield*
|
|
2823
|
-
|
|
2824
|
-
const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(
|
|
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*
|
|
3425
|
+
yield* Console12.log(`Status: ${label}`);
|
|
2829
3426
|
}
|
|
2830
|
-
const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(
|
|
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(
|
|
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*
|
|
3438
|
+
yield* Console12.log(`Deployed to https://${active.hostname}`);
|
|
2842
3439
|
} else {
|
|
2843
|
-
yield*
|
|
3440
|
+
yield* Console12.log("Deployment is live.");
|
|
2844
3441
|
}
|
|
2845
|
-
return yield*
|
|
3442
|
+
return yield* Effect24.fail("done");
|
|
2846
3443
|
}
|
|
2847
3444
|
if (newStatus === "FAILED") {
|
|
2848
|
-
return yield*
|
|
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, () =>
|
|
3452
|
+
Schedule.addDelay(Schedule.forever, () => Duration3.seconds(1))
|
|
2856
3453
|
).pipe(
|
|
2857
|
-
|
|
2858
|
-
if (err === "done") return
|
|
2859
|
-
return
|
|
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
|
|
3463
|
+
return Console12.error(logEntry.message);
|
|
2867
3464
|
case "WARN":
|
|
2868
|
-
return
|
|
3465
|
+
return Console12.warn(logEntry.message);
|
|
2869
3466
|
default:
|
|
2870
|
-
return
|
|
3467
|
+
return Console12.log(logEntry.message);
|
|
2871
3468
|
}
|
|
2872
3469
|
};
|
|
2873
3470
|
|
|
2874
3471
|
// src/commands/platform/index.ts
|
|
2875
|
-
var platformBase =
|
|
2876
|
-
var platformCommand = platformBase.pipe(
|
|
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
|
|
2880
|
-
import { Console as
|
|
2881
|
-
var fileArg2 =
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
);
|
|
2885
|
-
var
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
);
|
|
2890
|
-
var
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
);
|
|
2895
|
-
var environmentOption2 =
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
);
|
|
2900
|
-
var
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
);
|
|
2904
|
-
var rotateOption2 =
|
|
2905
|
-
|
|
2906
|
-
);
|
|
2907
|
-
var setupCommand =
|
|
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:
|
|
2912
|
-
org:
|
|
3508
|
+
app: appOption7,
|
|
3509
|
+
org: orgOption7,
|
|
2913
3510
|
environment: environmentOption2,
|
|
2914
|
-
yes:
|
|
3511
|
+
yes: yesOption3,
|
|
2915
3512
|
rotate: rotateOption2
|
|
2916
3513
|
},
|
|
2917
|
-
({ file, app, org, environment, yes, rotate }) =>
|
|
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 (
|
|
3522
|
+
if (Option15.isSome(existingLink)) {
|
|
2926
3523
|
applicationId = existingLink.value.applicationId;
|
|
2927
|
-
if (
|
|
2928
|
-
yield*
|
|
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 =
|
|
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*
|
|
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 =
|
|
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*
|
|
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*
|
|
2958
|
-
|
|
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*
|
|
3563
|
+
yield* Console13.log(`Linked this directory to application ${applicationId}.`);
|
|
2967
3564
|
}
|
|
2968
|
-
const target =
|
|
2969
|
-
const environmentSlug =
|
|
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 (
|
|
2975
|
-
const overwrite = yield*
|
|
2976
|
-
|
|
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*
|
|
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:
|
|
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*
|
|
2991
|
-
yield*
|
|
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*
|
|
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*
|
|
3595
|
+
yield* Console13.log(` \u2022 Added ${target} to .gitignore.`);
|
|
2999
3596
|
}
|
|
3000
|
-
yield*
|
|
3597
|
+
yield* Console13.log(" \u2022 Your app can now call the Gigadrive API via the SDK (GIGADRIVE_CLIENT_ID/SECRET).");
|
|
3001
3598
|
}).pipe(
|
|
3002
|
-
|
|
3599
|
+
Effect26.catchTags({
|
|
3003
3600
|
// Ctrl+C during a prompt is a deliberate cancel — exit 0.
|
|
3004
|
-
QuitException: () =>
|
|
3005
|
-
NotAuthenticatedError: (err) =>
|
|
3006
|
-
|
|
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) =>
|
|
3009
|
-
NoApplicationsFoundError: (err) =>
|
|
3010
|
-
ApplicationNotFoundError: (err) =>
|
|
3011
|
-
ProjectLinkReadError: (err) =>
|
|
3012
|
-
ProjectLinkWriteError: (err) =>
|
|
3013
|
-
EnvFileReadError: (err) =>
|
|
3014
|
-
EnvFileWriteError: (err) =>
|
|
3015
|
-
DevCredentialsStoreReadError: (err) =>
|
|
3016
|
-
DevCredentialsStoreWriteError: (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
|
|
3023
|
-
import { Console as
|
|
3024
|
-
var whoamiCommand =
|
|
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
|
-
() =>
|
|
3624
|
+
() => Effect27.gen(function* () {
|
|
3028
3625
|
const auth = yield* AuthService;
|
|
3029
3626
|
const info = yield* auth.getUserInfo;
|
|
3030
|
-
yield*
|
|
3627
|
+
yield* Console14.log(JSON.stringify(info, null, 2));
|
|
3031
3628
|
}).pipe(
|
|
3032
|
-
|
|
3033
|
-
NotAuthenticatedError: () =>
|
|
3034
|
-
UserInfoFetchError: (err) =>
|
|
3035
|
-
OAuthDiscoveryError: (err) =>
|
|
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 =
|
|
3042
|
-
|
|
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 =
|
|
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(
|
|
3679
|
+
NodeRuntime.runMain(Effect28.provide(cli(process.argv), AppLive));
|
|
3082
3680
|
//# sourceMappingURL=index.mjs.map
|