gigadrive 2.2.0 → 2.4.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 +975 -328
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +941 -294
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -24,15 +24,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
|
-
var
|
|
27
|
+
var import_cli15 = require("@effect/cli");
|
|
28
28
|
var import_platform_node = require("@effect/platform-node");
|
|
29
29
|
var import_network_config2 = require("@gigadrive/network-config");
|
|
30
|
-
var
|
|
30
|
+
var import_effect29 = require("effect");
|
|
31
31
|
|
|
32
32
|
// package.json
|
|
33
33
|
var package_default = {
|
|
34
34
|
name: "gigadrive",
|
|
35
|
-
version: "2.
|
|
35
|
+
version: "2.4.0",
|
|
36
36
|
repository: {
|
|
37
37
|
type: "git",
|
|
38
38
|
url: "https://github.com/Gigadrive/sdk.git",
|
|
@@ -58,7 +58,7 @@ var package_default = {
|
|
|
58
58
|
dependencies: {
|
|
59
59
|
"@effect/cli": "^0.75.0",
|
|
60
60
|
"@effect/platform": "^0.96.0",
|
|
61
|
-
"@effect/platform-node": "^0.
|
|
61
|
+
"@effect/platform-node": "^0.107.0",
|
|
62
62
|
"@gigadrive/build-utils": "workspace:*",
|
|
63
63
|
"@gigadrive/commons": "workspace:*",
|
|
64
64
|
"@gigadrive/network-config": "workspace:*",
|
|
@@ -69,8 +69,8 @@ var package_default = {
|
|
|
69
69
|
open: "^10.2.0"
|
|
70
70
|
},
|
|
71
71
|
devDependencies: {
|
|
72
|
-
"@effect/language-service": "^0.
|
|
73
|
-
"@types/archiver": "^6.0.
|
|
72
|
+
"@effect/language-service": "^0.86.0",
|
|
73
|
+
"@types/archiver": "^6.0.4",
|
|
74
74
|
esbuild: "^0.28.0",
|
|
75
75
|
typescript: "catalog:"
|
|
76
76
|
},
|
|
@@ -113,6 +113,25 @@ var TokenExchangeError = class extends import_effect.Schema.TaggedError()("Token
|
|
|
113
113
|
statusCode: import_effect.Schema.optional(import_effect.Schema.Number)
|
|
114
114
|
}) {
|
|
115
115
|
};
|
|
116
|
+
var DeviceAuthorizationError = class extends import_effect.Schema.TaggedError()(
|
|
117
|
+
"DeviceAuthorizationError",
|
|
118
|
+
{
|
|
119
|
+
message: import_effect.Schema.String,
|
|
120
|
+
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
121
|
+
}
|
|
122
|
+
) {
|
|
123
|
+
};
|
|
124
|
+
var AuthorizationDeniedError = class extends import_effect.Schema.TaggedError()(
|
|
125
|
+
"AuthorizationDeniedError",
|
|
126
|
+
{
|
|
127
|
+
message: import_effect.Schema.String
|
|
128
|
+
}
|
|
129
|
+
) {
|
|
130
|
+
};
|
|
131
|
+
var DeviceCodeExpiredError = class extends import_effect.Schema.TaggedError()("DeviceCodeExpiredError", {
|
|
132
|
+
message: import_effect.Schema.String
|
|
133
|
+
}) {
|
|
134
|
+
};
|
|
116
135
|
var TokenRefreshError = class extends import_effect.Schema.TaggedError()("TokenRefreshError", {
|
|
117
136
|
message: import_effect.Schema.String,
|
|
118
137
|
statusCode: import_effect.Schema.optional(import_effect.Schema.Number)
|
|
@@ -158,6 +177,31 @@ var ApplicationNotFoundError = class extends import_effect.Schema.TaggedError()(
|
|
|
158
177
|
}
|
|
159
178
|
) {
|
|
160
179
|
};
|
|
180
|
+
var EnvFileReadError = class extends import_effect.Schema.TaggedError()("EnvFileReadError", {
|
|
181
|
+
message: import_effect.Schema.String,
|
|
182
|
+
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
183
|
+
}) {
|
|
184
|
+
};
|
|
185
|
+
var EnvFileWriteError = class extends import_effect.Schema.TaggedError()("EnvFileWriteError", {
|
|
186
|
+
message: import_effect.Schema.String,
|
|
187
|
+
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
188
|
+
}) {
|
|
189
|
+
};
|
|
190
|
+
var DevCredentialsStoreReadError = class extends import_effect.Schema.TaggedError()(
|
|
191
|
+
"DevCredentialsStoreReadError",
|
|
192
|
+
{
|
|
193
|
+
message: import_effect.Schema.String
|
|
194
|
+
}
|
|
195
|
+
) {
|
|
196
|
+
};
|
|
197
|
+
var DevCredentialsStoreWriteError = class extends import_effect.Schema.TaggedError()(
|
|
198
|
+
"DevCredentialsStoreWriteError",
|
|
199
|
+
{
|
|
200
|
+
message: import_effect.Schema.String,
|
|
201
|
+
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
202
|
+
}
|
|
203
|
+
) {
|
|
204
|
+
};
|
|
161
205
|
var ConfigNotFoundError = class extends import_effect.Schema.TaggedError()("ConfigNotFoundError", {
|
|
162
206
|
message: import_effect.Schema.String,
|
|
163
207
|
directory: import_effect.Schema.String
|
|
@@ -285,15 +329,9 @@ var import_effect6 = require("effect");
|
|
|
285
329
|
|
|
286
330
|
// src/services/auth.ts
|
|
287
331
|
var import_effect5 = require("effect");
|
|
288
|
-
var
|
|
289
|
-
var http = __toESM(require("http"), 1);
|
|
332
|
+
var import_node_process2 = __toESM(require("process"), 1);
|
|
290
333
|
var import_open = __toESM(require("open"), 1);
|
|
291
334
|
|
|
292
|
-
// src/services/auth-storage.ts
|
|
293
|
-
var import_platform = require("@effect/platform");
|
|
294
|
-
var import_effect3 = require("effect");
|
|
295
|
-
var os = __toESM(require("os"), 1);
|
|
296
|
-
|
|
297
335
|
// src/domain.ts
|
|
298
336
|
var import_effect2 = require("effect");
|
|
299
337
|
var DeploymentId = import_effect2.Schema.String.pipe(import_effect2.Schema.brand("@Gigadrive/DeploymentId"));
|
|
@@ -311,9 +349,18 @@ var OAuthClientConfig = import_effect2.Schema.Struct({
|
|
|
311
349
|
issuer: import_effect2.Schema.String,
|
|
312
350
|
authorizeUrl: import_effect2.Schema.String,
|
|
313
351
|
tokenUrl: import_effect2.Schema.String,
|
|
352
|
+
deviceAuthorizeUrl: import_effect2.Schema.String,
|
|
314
353
|
scope: import_effect2.Schema.String,
|
|
315
354
|
userinfoUrl: import_effect2.Schema.String
|
|
316
355
|
});
|
|
356
|
+
var DeviceAuthorizationResponse = import_effect2.Schema.Struct({
|
|
357
|
+
device_code: import_effect2.Schema.String,
|
|
358
|
+
user_code: import_effect2.Schema.String,
|
|
359
|
+
verification_uri: import_effect2.Schema.String,
|
|
360
|
+
verification_uri_complete: import_effect2.Schema.optional(import_effect2.Schema.String),
|
|
361
|
+
expires_in: import_effect2.Schema.Number,
|
|
362
|
+
interval: import_effect2.Schema.optional(import_effect2.Schema.Number)
|
|
363
|
+
});
|
|
317
364
|
var StoredAuthData = import_effect2.Schema.Struct({
|
|
318
365
|
refreshToken: import_effect2.Schema.String,
|
|
319
366
|
accessToken: import_effect2.Schema.optional(import_effect2.Schema.String),
|
|
@@ -323,8 +370,52 @@ var ProjectLink = import_effect2.Schema.Struct({
|
|
|
323
370
|
applicationId: import_effect2.Schema.String,
|
|
324
371
|
organizationId: import_effect2.Schema.optional(import_effect2.Schema.String)
|
|
325
372
|
});
|
|
373
|
+
var DevKeyEntry = import_effect2.Schema.Struct({
|
|
374
|
+
apiKeyId: import_effect2.Schema.String
|
|
375
|
+
});
|
|
376
|
+
var DevKeyStore = import_effect2.Schema.Record({ key: import_effect2.Schema.String, value: DevKeyEntry });
|
|
377
|
+
|
|
378
|
+
// src/lib/clipboard.ts
|
|
379
|
+
var import_node_child_process = require("child_process");
|
|
380
|
+
var import_node_process = __toESM(require("process"), 1);
|
|
381
|
+
var clipboardCandidates = () => {
|
|
382
|
+
switch (import_node_process.default.platform) {
|
|
383
|
+
case "darwin":
|
|
384
|
+
return [{ cmd: "pbcopy", args: [] }];
|
|
385
|
+
case "win32":
|
|
386
|
+
return [{ cmd: "clip", args: [] }];
|
|
387
|
+
default:
|
|
388
|
+
return [
|
|
389
|
+
{ cmd: "wl-copy", args: [] },
|
|
390
|
+
{ cmd: "xclip", args: ["-selection", "clipboard"] },
|
|
391
|
+
{ cmd: "xsel", args: ["--clipboard", "--input"] }
|
|
392
|
+
];
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
function writeClipboard(text) {
|
|
396
|
+
const candidates = clipboardCandidates();
|
|
397
|
+
const tryNext = (index) => {
|
|
398
|
+
if (index >= candidates.length) return;
|
|
399
|
+
const { cmd, args } = candidates[index];
|
|
400
|
+
let proc;
|
|
401
|
+
try {
|
|
402
|
+
proc = (0, import_node_child_process.spawn)(cmd, args, { stdio: ["pipe", "ignore", "ignore"] });
|
|
403
|
+
} catch {
|
|
404
|
+
tryNext(index + 1);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
proc.on("error", () => tryNext(index + 1));
|
|
408
|
+
proc.stdin?.on("error", () => {
|
|
409
|
+
});
|
|
410
|
+
proc.stdin?.end(text);
|
|
411
|
+
};
|
|
412
|
+
tryNext(0);
|
|
413
|
+
}
|
|
326
414
|
|
|
327
415
|
// src/services/auth-storage.ts
|
|
416
|
+
var import_platform = require("@effect/platform");
|
|
417
|
+
var import_effect3 = require("effect");
|
|
418
|
+
var os = __toESM(require("os"), 1);
|
|
328
419
|
var AuthStorageService = class extends import_effect3.Effect.Service()("AuthStorageService", {
|
|
329
420
|
accessors: true,
|
|
330
421
|
effect: import_effect3.Effect.gen(function* () {
|
|
@@ -403,15 +494,46 @@ var AuthStorageService = class extends import_effect3.Effect.Service()("AuthStor
|
|
|
403
494
|
var import_effect4 = require("effect");
|
|
404
495
|
var OAuthEnvConfig = import_effect4.Config.all({
|
|
405
496
|
issuerUrl: import_effect4.Config.string("GIGADRIVE_NETWORK_OAUTH_ISSUER_URL").pipe(import_effect4.Config.withDefault("https://idp.gigadrive.de")),
|
|
406
|
-
|
|
497
|
+
// Default is the first-party CLI's public OAuth client (seeded in the Network
|
|
498
|
+
// repo). Override with GIGADRIVE_NETWORK_OAUTH_CLIENT_ID per environment.
|
|
499
|
+
clientId: import_effect4.Config.string("GIGADRIVE_NETWORK_OAUTH_CLIENT_ID").pipe(
|
|
500
|
+
import_effect4.Config.withDefault("0195c11c-0000-7000-8000-000000000001")
|
|
501
|
+
)
|
|
407
502
|
});
|
|
408
503
|
var OpenIdDiscoveryDocument = import_effect4.Schema.Struct({
|
|
409
504
|
issuer: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
410
505
|
authorization_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
411
506
|
token_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
412
|
-
userinfo_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String)
|
|
507
|
+
userinfo_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
508
|
+
device_authorization_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String)
|
|
413
509
|
});
|
|
414
|
-
var
|
|
510
|
+
var CLI_SCOPES = [
|
|
511
|
+
// Identity / OIDC
|
|
512
|
+
"offline_access",
|
|
513
|
+
"openid",
|
|
514
|
+
"profile",
|
|
515
|
+
"email",
|
|
516
|
+
// Network API capabilities
|
|
517
|
+
"network:applications:read",
|
|
518
|
+
"network:env_vars:read",
|
|
519
|
+
"network:env_vars:write",
|
|
520
|
+
"network:env_vars:delete",
|
|
521
|
+
"network:deployments:read",
|
|
522
|
+
"network:deployments:write",
|
|
523
|
+
"network:deployments:trigger",
|
|
524
|
+
"network:ai_gateway:chat",
|
|
525
|
+
"network:ai_gateway:models",
|
|
526
|
+
"network:ai_gateway:usage:read",
|
|
527
|
+
"network:ai_gateway:budgets:read",
|
|
528
|
+
"network:ai_gateway:budgets:write",
|
|
529
|
+
"network:ai_gateway:policies:read",
|
|
530
|
+
"network:ai_gateway:policies:write",
|
|
531
|
+
// Provisioning local-dev API credentials
|
|
532
|
+
"platform:api_keys:read",
|
|
533
|
+
"platform:api_keys:write",
|
|
534
|
+
"platform:api_keys:delete"
|
|
535
|
+
];
|
|
536
|
+
var DEFAULT_SCOPE = CLI_SCOPES.join(" ");
|
|
415
537
|
var OAuthConfigService = class extends import_effect4.Effect.Service()("OAuthConfigService", {
|
|
416
538
|
accessors: true,
|
|
417
539
|
effect: import_effect4.Effect.gen(function* () {
|
|
@@ -449,7 +571,7 @@ var OAuthConfigService = class extends import_effect4.Effect.Service()("OAuthCon
|
|
|
449
571
|
})
|
|
450
572
|
)
|
|
451
573
|
);
|
|
452
|
-
if (!decoded.authorization_endpoint || !decoded.token_endpoint || !decoded.userinfo_endpoint) {
|
|
574
|
+
if (!decoded.authorization_endpoint || !decoded.token_endpoint || !decoded.userinfo_endpoint || !decoded.device_authorization_endpoint) {
|
|
453
575
|
return yield* import_effect4.Effect.fail(
|
|
454
576
|
new OAuthDiscoveryError({
|
|
455
577
|
message: "OIDC discovery returned incomplete endpoints"
|
|
@@ -461,6 +583,7 @@ var OAuthConfigService = class extends import_effect4.Effect.Service()("OAuthCon
|
|
|
461
583
|
issuer: decoded.issuer ?? issuerBase,
|
|
462
584
|
authorizeUrl: decoded.authorization_endpoint,
|
|
463
585
|
tokenUrl: decoded.token_endpoint,
|
|
586
|
+
deviceAuthorizeUrl: decoded.device_authorization_endpoint,
|
|
464
587
|
scope: DEFAULT_SCOPE,
|
|
465
588
|
userinfoUrl: decoded.userinfo_endpoint
|
|
466
589
|
};
|
|
@@ -474,14 +597,9 @@ var OAuthConfigService = class extends import_effect4.Effect.Service()("OAuthCon
|
|
|
474
597
|
};
|
|
475
598
|
|
|
476
599
|
// src/services/auth.ts
|
|
477
|
-
var
|
|
478
|
-
var
|
|
479
|
-
var
|
|
480
|
-
const codeVerifier = base64URLEncode(crypto.randomBytes(64));
|
|
481
|
-
const challengeBytes = crypto.createHash("sha256").update(codeVerifier, "utf8").digest();
|
|
482
|
-
const codeChallenge = base64URLEncode(challengeBytes);
|
|
483
|
-
return { codeVerifier, codeChallenge };
|
|
484
|
-
};
|
|
600
|
+
var DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
601
|
+
var DEFAULT_POLL_INTERVAL_SECONDS = 5;
|
|
602
|
+
var REQUEST_TIMEOUT_SECONDS = 30;
|
|
485
603
|
var AuthService = class extends import_effect5.Effect.Service()("AuthService", {
|
|
486
604
|
accessors: true,
|
|
487
605
|
dependencies: [OAuthConfigService.Default, AuthStorageService.Default],
|
|
@@ -496,115 +614,178 @@ var AuthService = class extends import_effect5.Effect.Service()("AuthService", {
|
|
|
496
614
|
yield* storage.remove;
|
|
497
615
|
yield* import_effect5.Effect.log("Logged out");
|
|
498
616
|
});
|
|
499
|
-
const
|
|
617
|
+
const requestDeviceAuthorization = (config) => import_effect5.Effect.gen(function* () {
|
|
500
618
|
const response = yield* import_effect5.Effect.tryPromise({
|
|
501
|
-
try: () => fetch(config.
|
|
619
|
+
try: (signal) => fetch(config.deviceAuthorizeUrl, {
|
|
502
620
|
method: "POST",
|
|
503
621
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
504
|
-
body: new URLSearchParams({
|
|
505
|
-
|
|
506
|
-
client_id: config.clientId,
|
|
507
|
-
code: authCode,
|
|
508
|
-
redirect_uri: redirectUri,
|
|
509
|
-
code_verifier: codeVerifier
|
|
510
|
-
}).toString()
|
|
622
|
+
body: new URLSearchParams({ client_id: config.clientId, scope: config.scope }).toString(),
|
|
623
|
+
signal
|
|
511
624
|
}),
|
|
512
|
-
catch: (error) => new
|
|
513
|
-
message: `
|
|
625
|
+
catch: (error) => new DeviceAuthorizationError({
|
|
626
|
+
message: `Device authorization request failed: ${error instanceof Error ? error.message : String(error)}`
|
|
514
627
|
})
|
|
515
628
|
});
|
|
516
629
|
if (!response.ok) {
|
|
517
630
|
const body = yield* import_effect5.Effect.tryPromise({
|
|
518
631
|
try: () => response.text(),
|
|
519
|
-
catch: () => new
|
|
632
|
+
catch: () => new DeviceAuthorizationError({ message: "Failed to read device authorization error response" })
|
|
520
633
|
});
|
|
521
634
|
return yield* import_effect5.Effect.fail(
|
|
522
|
-
new
|
|
523
|
-
message: `
|
|
524
|
-
statusCode: response.status
|
|
635
|
+
new DeviceAuthorizationError({
|
|
636
|
+
message: `Device authorization failed: ${response.status} ${response.statusText} - ${body}`
|
|
525
637
|
})
|
|
526
638
|
);
|
|
527
639
|
}
|
|
528
|
-
const
|
|
640
|
+
const json = yield* import_effect5.Effect.tryPromise({
|
|
641
|
+
try: () => response.json(),
|
|
642
|
+
catch: () => new DeviceAuthorizationError({ message: "Failed to parse device authorization response" })
|
|
643
|
+
});
|
|
644
|
+
return yield* import_effect5.Schema.decodeUnknown(DeviceAuthorizationResponse)(json).pipe(
|
|
645
|
+
import_effect5.Effect.mapError(
|
|
646
|
+
() => new DeviceAuthorizationError({ message: "Invalid device authorization response schema" })
|
|
647
|
+
)
|
|
648
|
+
);
|
|
649
|
+
}).pipe(
|
|
650
|
+
import_effect5.Effect.timeoutFail({
|
|
651
|
+
duration: import_effect5.Duration.seconds(REQUEST_TIMEOUT_SECONDS),
|
|
652
|
+
onTimeout: () => new DeviceAuthorizationError({ message: "Device authorization request timed out" })
|
|
653
|
+
})
|
|
654
|
+
);
|
|
655
|
+
const pollTokenOnce = (config, deviceCode) => import_effect5.Effect.gen(function* () {
|
|
656
|
+
const response = yield* import_effect5.Effect.tryPromise({
|
|
657
|
+
try: (signal) => fetch(config.tokenUrl, {
|
|
658
|
+
method: "POST",
|
|
659
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
660
|
+
body: new URLSearchParams({
|
|
661
|
+
grant_type: DEVICE_CODE_GRANT_TYPE,
|
|
662
|
+
client_id: config.clientId,
|
|
663
|
+
device_code: deviceCode
|
|
664
|
+
}).toString(),
|
|
665
|
+
signal
|
|
666
|
+
}),
|
|
667
|
+
catch: (error) => new TokenExchangeError({
|
|
668
|
+
message: `Token poll request failed: ${error instanceof Error ? error.message : String(error)}`
|
|
669
|
+
})
|
|
670
|
+
});
|
|
671
|
+
if (response.ok) {
|
|
672
|
+
const tokens = yield* import_effect5.Effect.tryPromise({
|
|
673
|
+
try: () => response.json(),
|
|
674
|
+
catch: () => new TokenExchangeError({ message: "Failed to parse token response" })
|
|
675
|
+
});
|
|
676
|
+
return { kind: "tokens", tokens };
|
|
677
|
+
}
|
|
678
|
+
const errorBody = yield* import_effect5.Effect.tryPromise({
|
|
529
679
|
try: () => response.json(),
|
|
530
|
-
catch: () => new TokenExchangeError({ message: "Failed to parse token
|
|
680
|
+
catch: () => new TokenExchangeError({ message: "Failed to parse token poll error response" })
|
|
531
681
|
});
|
|
532
|
-
|
|
682
|
+
switch (errorBody.error) {
|
|
683
|
+
case "authorization_pending":
|
|
684
|
+
return { kind: "pending" };
|
|
685
|
+
case "slow_down":
|
|
686
|
+
return { kind: "slow_down" };
|
|
687
|
+
case "access_denied":
|
|
688
|
+
return { kind: "denied" };
|
|
689
|
+
case "expired_token":
|
|
690
|
+
return { kind: "expired" };
|
|
691
|
+
default:
|
|
692
|
+
return yield* import_effect5.Effect.fail(
|
|
693
|
+
new TokenExchangeError({
|
|
694
|
+
message: `Token poll failed: ${response.status} ${response.statusText} - ${errorBody.error ?? "unknown_error"}`,
|
|
695
|
+
statusCode: response.status
|
|
696
|
+
})
|
|
697
|
+
);
|
|
698
|
+
}
|
|
533
699
|
});
|
|
534
|
-
const
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
700
|
+
const pollForToken = (config, device) => import_effect5.Effect.gen(function* () {
|
|
701
|
+
const deadline = Date.now() + device.expires_in * 1e3;
|
|
702
|
+
let interval = device.interval ?? DEFAULT_POLL_INTERVAL_SECONDS;
|
|
703
|
+
while (true) {
|
|
704
|
+
yield* import_effect5.Effect.sleep(import_effect5.Duration.seconds(interval));
|
|
705
|
+
if (Date.now() >= deadline) {
|
|
706
|
+
return yield* import_effect5.Effect.fail(
|
|
707
|
+
new DeviceCodeExpiredError({
|
|
708
|
+
message: "The login code expired before it was approved. Please run `gigadrive login` again."
|
|
709
|
+
})
|
|
710
|
+
);
|
|
544
711
|
}
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
res.writeHead(200, { "Content-Type": "text/html", Connection: "close" });
|
|
570
|
-
if (oauthError) {
|
|
571
|
-
const safeOauthError = escapeHtml(oauthError);
|
|
572
|
-
res.end(`<h1>Login Failed!</h1><p>Error: ${safeOauthError}</p><p>You can close this tab.</p>`);
|
|
573
|
-
server.close();
|
|
574
|
-
resume(import_effect5.Effect.fail(new LoginFlowError({ message: `OAuth error: ${oauthError}` })));
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
if (receivedState !== state) {
|
|
578
|
-
res.end(
|
|
579
|
-
"<h1>Login Failed!</h1><p>State mismatch. Possible CSRF attack.</p><p>You can close this tab.</p>"
|
|
712
|
+
const result = yield* pollTokenOnce(config, device.device_code).pipe(
|
|
713
|
+
// A hung poll must not stall the loop: on timeout treat it as pending so
|
|
714
|
+
// the next iteration re-checks the expiry deadline.
|
|
715
|
+
import_effect5.Effect.timeoutTo({
|
|
716
|
+
duration: import_effect5.Duration.seconds(REQUEST_TIMEOUT_SECONDS),
|
|
717
|
+
onSuccess: (value) => value,
|
|
718
|
+
onTimeout: () => ({ kind: "pending" })
|
|
719
|
+
})
|
|
720
|
+
);
|
|
721
|
+
switch (result.kind) {
|
|
722
|
+
case "tokens":
|
|
723
|
+
return result.tokens;
|
|
724
|
+
case "pending":
|
|
725
|
+
continue;
|
|
726
|
+
case "slow_down":
|
|
727
|
+
interval += 5;
|
|
728
|
+
continue;
|
|
729
|
+
case "denied":
|
|
730
|
+
return yield* import_effect5.Effect.fail(new AuthorizationDeniedError({ message: "The login request was denied." }));
|
|
731
|
+
case "expired":
|
|
732
|
+
return yield* import_effect5.Effect.fail(
|
|
733
|
+
new DeviceCodeExpiredError({
|
|
734
|
+
message: "The login code expired before it was approved. Please run `gigadrive login` again."
|
|
735
|
+
})
|
|
580
736
|
);
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
resume(import_effect5.Effect.fail(new LoginFlowError({ message:
|
|
598
|
-
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
const watchCopyKey = (url) => import_effect5.Effect.async((resume) => {
|
|
741
|
+
const stdin = import_node_process2.default.stdin;
|
|
742
|
+
if (!stdin.isTTY) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
stdin.setRawMode(true);
|
|
746
|
+
stdin.resume();
|
|
747
|
+
stdin.setEncoding("utf8");
|
|
748
|
+
const onData = (key) => {
|
|
749
|
+
if (key === "c" || key === "C") {
|
|
750
|
+
writeClipboard(url);
|
|
751
|
+
import_effect5.Console.log("Copied the login URL to your clipboard.").pipe(import_effect5.Effect.runSync);
|
|
752
|
+
} else if (key === "") {
|
|
753
|
+
resume(import_effect5.Effect.fail(new LoginFlowError({ message: "Login canceled." })));
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
stdin.on("data", onData);
|
|
757
|
+
return import_effect5.Effect.sync(() => {
|
|
758
|
+
stdin.off("data", onData);
|
|
759
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
760
|
+
stdin.pause();
|
|
599
761
|
});
|
|
600
762
|
});
|
|
601
763
|
const login = import_effect5.Effect.gen(function* () {
|
|
602
764
|
yield* logout;
|
|
603
|
-
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
604
|
-
const state = crypto.randomBytes(16).toString("hex");
|
|
605
765
|
const config = yield* oauthConfig.getConfig;
|
|
606
|
-
const
|
|
607
|
-
const
|
|
766
|
+
const device = yield* requestDeviceAuthorization(config);
|
|
767
|
+
const verificationUri = device.verification_uri;
|
|
768
|
+
const verificationUriComplete = device.verification_uri_complete ?? verificationUri;
|
|
769
|
+
const interactive = import_node_process2.default.stdin.isTTY === true;
|
|
770
|
+
yield* import_effect5.Console.log(
|
|
771
|
+
`
|
|
772
|
+
To sign in, visit:
|
|
773
|
+
|
|
774
|
+
${verificationUri}
|
|
775
|
+
|
|
776
|
+
and enter the code:
|
|
777
|
+
|
|
778
|
+
${device.user_code}
|
|
779
|
+
`
|
|
780
|
+
);
|
|
781
|
+
if (interactive) {
|
|
782
|
+
yield* import_effect5.Effect.tryPromise(() => (0, import_open.default)(verificationUriComplete)).pipe(import_effect5.Effect.catchAll(() => import_effect5.Effect.void));
|
|
783
|
+
yield* import_effect5.Console.log("We tried to open your browser automatically. If it did not open, use the URL above.");
|
|
784
|
+
yield* import_effect5.Console.log('Press "c" to copy the URL to your clipboard, or Ctrl+C to cancel.');
|
|
785
|
+
}
|
|
786
|
+
yield* import_effect5.Console.log("\nWaiting for you to approve the login\u2026");
|
|
787
|
+
const poll = pollForToken(config, device);
|
|
788
|
+
const tokens = yield* interactive ? poll.pipe(import_effect5.Effect.raceFirst(watchCopyKey(verificationUriComplete))) : poll;
|
|
608
789
|
if (!tokens.refresh_token) {
|
|
609
790
|
return yield* import_effect5.Effect.fail(
|
|
610
791
|
new TokenExchangeError({ message: "No refresh token received from identity provider" })
|
|
@@ -1555,7 +1736,230 @@ var deploymentsCommand = deploymentsBase.pipe(
|
|
|
1555
1736
|
|
|
1556
1737
|
// src/commands/env/index.ts
|
|
1557
1738
|
var import_cli7 = require("@effect/cli");
|
|
1739
|
+
var import_effect19 = require("effect");
|
|
1740
|
+
|
|
1741
|
+
// src/services/env-file.ts
|
|
1742
|
+
var import_platform6 = require("@effect/platform");
|
|
1558
1743
|
var import_effect16 = require("effect");
|
|
1744
|
+
|
|
1745
|
+
// src/lib/dotenv.ts
|
|
1746
|
+
var DEFAULT_ENV_HEADER = "# Generated by `gigadrive env pull` \u2014 do not edit by hand.";
|
|
1747
|
+
var UNQUOTED_SAFE = /^[A-Za-z0-9_.\-/@:+]*$/;
|
|
1748
|
+
var formatEnvValue = (value) => {
|
|
1749
|
+
if (UNQUOTED_SAFE.test(value)) {
|
|
1750
|
+
return value;
|
|
1751
|
+
}
|
|
1752
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1753
|
+
return `"${escaped}"`;
|
|
1754
|
+
};
|
|
1755
|
+
var serializeEnv = (entries, opts) => {
|
|
1756
|
+
const header = opts?.header ?? DEFAULT_ENV_HEADER;
|
|
1757
|
+
if (entries.length === 0) {
|
|
1758
|
+
return `${header}
|
|
1759
|
+
`;
|
|
1760
|
+
}
|
|
1761
|
+
const body = entries.map((e) => `${e.key}=${formatEnvValue(e.value)}`).join("\n");
|
|
1762
|
+
return `${header}
|
|
1763
|
+
${body}
|
|
1764
|
+
`;
|
|
1765
|
+
};
|
|
1766
|
+
var parseEnv = (content) => {
|
|
1767
|
+
const result = {};
|
|
1768
|
+
for (const rawLine of content.split("\n")) {
|
|
1769
|
+
const line = rawLine.trim();
|
|
1770
|
+
if (line.length === 0 || line.startsWith("#")) {
|
|
1771
|
+
continue;
|
|
1772
|
+
}
|
|
1773
|
+
const eq = line.indexOf("=");
|
|
1774
|
+
if (eq <= 0) {
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1777
|
+
const key = line.slice(0, eq).trim();
|
|
1778
|
+
let value = line.slice(eq + 1).trim();
|
|
1779
|
+
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
|
1780
|
+
value = value.slice(1, -1).replace(/\\(\\|"|n|r|t)/g, (_, ch) => {
|
|
1781
|
+
switch (ch) {
|
|
1782
|
+
case "n":
|
|
1783
|
+
return "\n";
|
|
1784
|
+
case "r":
|
|
1785
|
+
return "\r";
|
|
1786
|
+
case "t":
|
|
1787
|
+
return " ";
|
|
1788
|
+
case '"':
|
|
1789
|
+
return '"';
|
|
1790
|
+
default:
|
|
1791
|
+
return "\\";
|
|
1792
|
+
}
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
result[key] = value;
|
|
1796
|
+
}
|
|
1797
|
+
return result;
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
// src/services/env-file.ts
|
|
1801
|
+
var EnvFileService = class extends import_effect16.Effect.Service()("EnvFileService", {
|
|
1802
|
+
accessors: true,
|
|
1803
|
+
effect: import_effect16.Effect.gen(function* () {
|
|
1804
|
+
const fs = yield* import_platform6.FileSystem.FileSystem;
|
|
1805
|
+
const pathService = yield* import_platform6.Path.Path;
|
|
1806
|
+
const exists = import_effect16.Effect.fn("EnvFileService.exists")(function* (filePath) {
|
|
1807
|
+
return yield* fs.exists(filePath).pipe(import_effect16.Effect.mapError(() => new EnvFileReadError({ message: `Failed to check whether ${filePath} exists` })));
|
|
1808
|
+
});
|
|
1809
|
+
const read = import_effect16.Effect.fn("EnvFileService.read")(function* (filePath) {
|
|
1810
|
+
const present = yield* exists(filePath);
|
|
1811
|
+
if (!present) return import_effect16.Option.none();
|
|
1812
|
+
const contents = yield* fs.readFileString(filePath, "utf8").pipe(import_effect16.Effect.mapError(() => new EnvFileReadError({ message: `Failed to read ${filePath}` })));
|
|
1813
|
+
return import_effect16.Option.some(contents);
|
|
1814
|
+
});
|
|
1815
|
+
const write = import_effect16.Effect.fn("EnvFileService.write")(function* (filePath, entries, opts) {
|
|
1816
|
+
const dir = pathService.dirname(filePath);
|
|
1817
|
+
yield* fs.makeDirectory(dir, { recursive: true }).pipe(
|
|
1818
|
+
import_effect16.Effect.mapError(
|
|
1819
|
+
(error) => new EnvFileWriteError({ message: `Failed to create directory for ${filePath}`, cause: String(error) })
|
|
1820
|
+
)
|
|
1821
|
+
);
|
|
1822
|
+
yield* fs.writeFileString(filePath, serializeEnv(entries, opts), { mode: 384 }).pipe(
|
|
1823
|
+
import_effect16.Effect.mapError(
|
|
1824
|
+
(error) => new EnvFileWriteError({ message: `Failed to write ${filePath}`, cause: String(error) })
|
|
1825
|
+
)
|
|
1826
|
+
);
|
|
1827
|
+
yield* fs.chmod(filePath, 384).pipe(
|
|
1828
|
+
import_effect16.Effect.mapError(
|
|
1829
|
+
(error) => new EnvFileWriteError({ message: `Failed to secure ${filePath}`, cause: String(error) })
|
|
1830
|
+
)
|
|
1831
|
+
);
|
|
1832
|
+
});
|
|
1833
|
+
const ensureGitignored = import_effect16.Effect.fn("EnvFileService.ensureGitignored")(function* (dir, entry) {
|
|
1834
|
+
const gitignorePath = pathService.join(dir, ".gitignore");
|
|
1835
|
+
const existing = yield* read(gitignorePath);
|
|
1836
|
+
const current = import_effect16.Option.getOrElse(existing, () => "");
|
|
1837
|
+
const alreadyIgnored = current.split("\n").some((line) => line.trim() === entry);
|
|
1838
|
+
if (alreadyIgnored) {
|
|
1839
|
+
return false;
|
|
1840
|
+
}
|
|
1841
|
+
const separator = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
|
|
1842
|
+
yield* fs.writeFileString(gitignorePath, `${current}${separator}${entry}
|
|
1843
|
+
`).pipe(
|
|
1844
|
+
import_effect16.Effect.mapError(
|
|
1845
|
+
(error) => new EnvFileWriteError({ message: "Failed to update .gitignore", cause: String(error) })
|
|
1846
|
+
)
|
|
1847
|
+
);
|
|
1848
|
+
return true;
|
|
1849
|
+
});
|
|
1850
|
+
return { exists, read, write, ensureGitignored };
|
|
1851
|
+
})
|
|
1852
|
+
}) {
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1855
|
+
// src/services/local-credentials.ts
|
|
1856
|
+
var import_effect18 = require("effect");
|
|
1857
|
+
var os3 = __toESM(require("os"), 1);
|
|
1858
|
+
|
|
1859
|
+
// src/services/dev-credentials-store.ts
|
|
1860
|
+
var import_platform7 = require("@effect/platform");
|
|
1861
|
+
var import_effect17 = require("effect");
|
|
1862
|
+
var os2 = __toESM(require("os"), 1);
|
|
1863
|
+
var DevCredentialsStore = class extends import_effect17.Effect.Service()("DevCredentialsStore", {
|
|
1864
|
+
accessors: true,
|
|
1865
|
+
effect: import_effect17.Effect.gen(function* () {
|
|
1866
|
+
const fs = yield* import_platform7.FileSystem.FileSystem;
|
|
1867
|
+
const pathService = yield* import_platform7.Path.Path;
|
|
1868
|
+
const homeDir = os2.homedir();
|
|
1869
|
+
const storeDir = pathService.join(homeDir, ".gigadrive");
|
|
1870
|
+
const storeFile = pathService.join(storeDir, "dev-keys.json");
|
|
1871
|
+
const ensureDirectory = import_effect17.Effect.gen(function* () {
|
|
1872
|
+
yield* fs.makeDirectory(storeDir, { recursive: true }).pipe(
|
|
1873
|
+
import_effect17.Effect.mapError(
|
|
1874
|
+
(error) => new DevCredentialsStoreWriteError({ message: "Failed to create ~/.gigadrive", cause: String(error) })
|
|
1875
|
+
)
|
|
1876
|
+
);
|
|
1877
|
+
yield* fs.chmod(storeDir, 448).pipe(
|
|
1878
|
+
import_effect17.Effect.mapError(
|
|
1879
|
+
(error) => new DevCredentialsStoreWriteError({
|
|
1880
|
+
message: "Failed to set ~/.gigadrive permissions",
|
|
1881
|
+
cause: String(error)
|
|
1882
|
+
})
|
|
1883
|
+
)
|
|
1884
|
+
);
|
|
1885
|
+
});
|
|
1886
|
+
const load = import_effect17.Effect.gen(function* () {
|
|
1887
|
+
const present = yield* fs.exists(storeFile).pipe(import_effect17.Effect.mapError(() => new DevCredentialsStoreReadError({ message: "Failed to check dev-keys.json" })));
|
|
1888
|
+
if (!present) return {};
|
|
1889
|
+
const data = yield* fs.readFileString(storeFile, "utf8").pipe(import_effect17.Effect.mapError(() => new DevCredentialsStoreReadError({ message: "Failed to read dev-keys.json" })));
|
|
1890
|
+
const json = yield* import_effect17.Effect.try({
|
|
1891
|
+
try: () => JSON.parse(data),
|
|
1892
|
+
catch: () => new DevCredentialsStoreReadError({ message: "dev-keys.json contains invalid JSON" })
|
|
1893
|
+
});
|
|
1894
|
+
return yield* import_effect17.Schema.decodeUnknown(DevKeyStore)(json).pipe(
|
|
1895
|
+
import_effect17.Effect.mapError(() => new DevCredentialsStoreReadError({ message: "dev-keys.json has an invalid schema" }))
|
|
1896
|
+
);
|
|
1897
|
+
});
|
|
1898
|
+
const get = import_effect17.Effect.fn("DevCredentialsStore.get")(function* (applicationId) {
|
|
1899
|
+
const store = yield* load;
|
|
1900
|
+
const entry = store[applicationId];
|
|
1901
|
+
return entry ? import_effect17.Option.some(entry) : import_effect17.Option.none();
|
|
1902
|
+
});
|
|
1903
|
+
const set = import_effect17.Effect.fn("DevCredentialsStore.set")(function* (applicationId, entry) {
|
|
1904
|
+
const store = yield* load;
|
|
1905
|
+
const next = { ...store, [applicationId]: entry };
|
|
1906
|
+
yield* ensureDirectory;
|
|
1907
|
+
yield* fs.writeFileString(storeFile, `${JSON.stringify(next, null, 2)}
|
|
1908
|
+
`, { mode: 384 }).pipe(
|
|
1909
|
+
import_effect17.Effect.mapError(
|
|
1910
|
+
(error) => new DevCredentialsStoreWriteError({ message: "Failed to write dev-keys.json", cause: String(error) })
|
|
1911
|
+
)
|
|
1912
|
+
);
|
|
1913
|
+
});
|
|
1914
|
+
return { get, set };
|
|
1915
|
+
})
|
|
1916
|
+
}) {
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1919
|
+
// src/services/local-credentials.ts
|
|
1920
|
+
var DEV_KEY_SCOPES = ["network:env_vars:read"];
|
|
1921
|
+
var ApiBaseUrl2 = import_effect18.Config.string("GIGADRIVE_API_BASE_URL").pipe(import_effect18.Config.withDefault("https://api.gigadrive.network"));
|
|
1922
|
+
var credentialEntries = (clientId, clientSecret, baseUrl) => [
|
|
1923
|
+
{ key: "GIGADRIVE_CLIENT_ID", value: clientId },
|
|
1924
|
+
{ key: "GIGADRIVE_CLIENT_SECRET", value: clientSecret },
|
|
1925
|
+
{ key: "GIGADRIVE_API_BASE_URL", value: baseUrl }
|
|
1926
|
+
];
|
|
1927
|
+
var LocalCredentialsService = class extends import_effect18.Effect.Service()("LocalCredentialsService", {
|
|
1928
|
+
accessors: true,
|
|
1929
|
+
dependencies: [ApiClientService.Default, DevCredentialsStore.Default],
|
|
1930
|
+
effect: import_effect18.Effect.gen(function* () {
|
|
1931
|
+
const apiClient = yield* ApiClientService;
|
|
1932
|
+
const store = yield* DevCredentialsStore;
|
|
1933
|
+
const baseUrl = yield* ApiBaseUrl2;
|
|
1934
|
+
const keyName = (applicationId) => `cli-dev:${os3.hostname()}:${applicationId}`;
|
|
1935
|
+
const provision = import_effect18.Effect.fn("LocalCredentialsService.provision")(function* (input) {
|
|
1936
|
+
const stored = yield* store.get(input.applicationId);
|
|
1937
|
+
const existing = input.existingContent ? parseEnv(input.existingContent) : {};
|
|
1938
|
+
const existingClientId = existing["GIGADRIVE_CLIENT_ID"];
|
|
1939
|
+
const existingClientSecret = existing["GIGADRIVE_CLIENT_SECRET"];
|
|
1940
|
+
const canReuse = !input.rotate && existingClientId !== void 0 && existingClientSecret !== void 0 && import_effect18.Option.isSome(stored) && stored.value.apiKeyId === existingClientId;
|
|
1941
|
+
if (canReuse) {
|
|
1942
|
+
return credentialEntries(existingClientId, existingClientSecret, baseUrl);
|
|
1943
|
+
}
|
|
1944
|
+
if (import_effect18.Option.isSome(stored)) {
|
|
1945
|
+
yield* apiClient.request((client) => client.apiKeys.delete(stored.value.apiKeyId)).pipe(import_effect18.Effect.catchTag("ApiRequestError", () => import_effect18.Effect.void));
|
|
1946
|
+
}
|
|
1947
|
+
const created = yield* apiClient.request(
|
|
1948
|
+
(client) => client.apiKeys.create({
|
|
1949
|
+
name: keyName(input.applicationId),
|
|
1950
|
+
applicationId: input.applicationId,
|
|
1951
|
+
scopes: DEV_KEY_SCOPES
|
|
1952
|
+
})
|
|
1953
|
+
);
|
|
1954
|
+
yield* store.set(input.applicationId, { apiKeyId: created.id });
|
|
1955
|
+
return credentialEntries(created.id, created.secret, baseUrl);
|
|
1956
|
+
});
|
|
1957
|
+
return { provision };
|
|
1958
|
+
})
|
|
1959
|
+
}) {
|
|
1960
|
+
};
|
|
1961
|
+
|
|
1962
|
+
// src/commands/env/index.ts
|
|
1559
1963
|
var appOption3 = import_cli7.Options.text("app").pipe(
|
|
1560
1964
|
import_cli7.Options.withAlias("a"),
|
|
1561
1965
|
import_cli7.Options.withDescription("Operate on this application (overrides the linked application)"),
|
|
@@ -1578,51 +1982,70 @@ var keyValueArg = import_cli7.Args.text({ name: "key=value" }).pipe(
|
|
|
1578
1982
|
import_cli7.Args.withDescription("Variable assignment, e.g. DATABASE_URL=postgres://user:pass@host/db")
|
|
1579
1983
|
);
|
|
1580
1984
|
var keyOrIdArg = import_cli7.Args.text({ name: "key-or-id" }).pipe(import_cli7.Args.withDescription("Variable key or ID to remove"));
|
|
1581
|
-
var
|
|
1582
|
-
|
|
1985
|
+
var fileArg = import_cli7.Args.text({ name: "file" }).pipe(
|
|
1986
|
+
import_cli7.Args.withDescription("Output file to write (default: .env.local)"),
|
|
1987
|
+
import_cli7.Args.optional
|
|
1988
|
+
);
|
|
1989
|
+
var environmentOption = import_cli7.Options.text("environment").pipe(
|
|
1990
|
+
import_cli7.Options.withAlias("e"),
|
|
1991
|
+
import_cli7.Options.withDescription("Environment slug to resolve overrides for (e.g. preview). Omit for the local baseline"),
|
|
1992
|
+
import_cli7.Options.optional
|
|
1993
|
+
);
|
|
1994
|
+
var yesOption = import_cli7.Options.boolean("yes").pipe(
|
|
1995
|
+
import_cli7.Options.withAlias("y"),
|
|
1996
|
+
import_cli7.Options.withDescription("Overwrite an existing file without confirmation")
|
|
1997
|
+
);
|
|
1998
|
+
var withCredentialsOption = import_cli7.Options.boolean("with-credentials").pipe(
|
|
1999
|
+
import_cli7.Options.withDescription("Also provision API-key credentials so the local app can call the API as this application")
|
|
2000
|
+
);
|
|
2001
|
+
var rotateOption = import_cli7.Options.boolean("rotate").pipe(
|
|
2002
|
+
import_cli7.Options.withDescription("Force a fresh API key when provisioning credentials, revoking the previous one")
|
|
2003
|
+
);
|
|
2004
|
+
var resolveScope = (app, org) => import_effect19.Effect.gen(function* () {
|
|
2005
|
+
if (import_effect19.Option.isSome(org)) {
|
|
1583
2006
|
return { kind: "organization", id: org.value };
|
|
1584
2007
|
}
|
|
1585
2008
|
const projectLink = yield* ProjectLinkService;
|
|
1586
|
-
const id = yield*
|
|
1587
|
-
onSome: (value) =>
|
|
1588
|
-
onNone: () => projectLink.resolve(process.cwd()).pipe(
|
|
2009
|
+
const id = yield* import_effect19.Option.match(app, {
|
|
2010
|
+
onSome: (value) => import_effect19.Effect.succeed(value),
|
|
2011
|
+
onNone: () => projectLink.resolve(process.cwd()).pipe(import_effect19.Effect.map((link) => link.applicationId))
|
|
1589
2012
|
});
|
|
1590
2013
|
return { kind: "application", id };
|
|
1591
2014
|
});
|
|
1592
2015
|
var envListCommand = import_cli7.Command.make(
|
|
1593
2016
|
"list",
|
|
1594
2017
|
{ app: appOption3, org: orgOption4 },
|
|
1595
|
-
({ app, org }) =>
|
|
2018
|
+
({ app, org }) => import_effect19.Effect.gen(function* () {
|
|
1596
2019
|
const apiClient = yield* ApiClientService;
|
|
1597
2020
|
const scope = yield* resolveScope(app, org);
|
|
1598
2021
|
const { items } = yield* apiClient.request(
|
|
1599
2022
|
(client) => scope.kind === "organization" ? client.organizations.envVars.list(scope.id) : client.applications.envVars.list(scope.id)
|
|
1600
2023
|
);
|
|
1601
2024
|
if (items.length === 0) {
|
|
1602
|
-
yield*
|
|
2025
|
+
yield* import_effect19.Console.log("No environment variables set.");
|
|
1603
2026
|
return;
|
|
1604
2027
|
}
|
|
1605
2028
|
for (const v of items) {
|
|
1606
|
-
yield*
|
|
2029
|
+
yield* import_effect19.Console.log(`${v.key}=${v.sensitive ? "***" : v.value ?? ""}`);
|
|
1607
2030
|
}
|
|
1608
2031
|
}).pipe(
|
|
1609
|
-
|
|
1610
|
-
NotAuthenticatedError: (err) =>
|
|
1611
|
-
|
|
2032
|
+
import_effect19.Effect.catchTags({
|
|
2033
|
+
NotAuthenticatedError: (err) => import_effect19.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
2034
|
+
import_effect19.Effect.andThen(import_effect19.Effect.fail(err))
|
|
1612
2035
|
),
|
|
1613
|
-
ApiRequestError: (err) =>
|
|
1614
|
-
ProjectNotLinkedError: (err) =>
|
|
1615
|
-
ProjectLinkReadError: (err) =>
|
|
2036
|
+
ApiRequestError: (err) => import_effect19.Console.error(`Failed to list environment variables: ${err.message}`).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2037
|
+
ProjectNotLinkedError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2038
|
+
ProjectLinkReadError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err)))
|
|
1616
2039
|
})
|
|
1617
2040
|
)
|
|
1618
2041
|
);
|
|
1619
2042
|
var envSetCommand = import_cli7.Command.make(
|
|
1620
2043
|
"set",
|
|
1621
2044
|
{ keyValue: keyValueArg, app: appOption3, org: orgOption4, sensitive: sensitiveOption, env: envIdOption },
|
|
1622
|
-
({ keyValue, app, org, sensitive, env }) =>
|
|
2045
|
+
({ keyValue, app, org, sensitive, env }) => import_effect19.Effect.gen(function* () {
|
|
1623
2046
|
const separator = keyValue.indexOf("=");
|
|
1624
2047
|
if (separator <= 0) {
|
|
1625
|
-
return yield*
|
|
2048
|
+
return yield* import_effect19.Effect.fail(
|
|
1626
2049
|
new InvalidEnvVarFormatError({
|
|
1627
2050
|
message: 'Invalid format. Use KEY=VALUE, e.g. "gigadrive env set DATABASE_URL=postgres://...".'
|
|
1628
2051
|
})
|
|
@@ -1632,27 +2055,27 @@ var envSetCommand = import_cli7.Command.make(
|
|
|
1632
2055
|
const value = keyValue.slice(separator + 1);
|
|
1633
2056
|
const apiClient = yield* ApiClientService;
|
|
1634
2057
|
const scope = yield* resolveScope(app, org);
|
|
1635
|
-
const environmentId =
|
|
2058
|
+
const environmentId = import_effect19.Option.getOrUndefined(env);
|
|
1636
2059
|
const created = yield* apiClient.request(
|
|
1637
2060
|
(client) => scope.kind === "organization" ? client.organizations.envVars.create(scope.id, { key, value, sensitive }) : client.applications.envVars.create(scope.id, { key, value, sensitive, environmentId })
|
|
1638
2061
|
);
|
|
1639
|
-
yield*
|
|
2062
|
+
yield* import_effect19.Console.log(`Set ${created.key}.`);
|
|
1640
2063
|
}).pipe(
|
|
1641
|
-
|
|
1642
|
-
InvalidEnvVarFormatError: (err) =>
|
|
1643
|
-
NotAuthenticatedError: (err) =>
|
|
1644
|
-
|
|
2064
|
+
import_effect19.Effect.catchTags({
|
|
2065
|
+
InvalidEnvVarFormatError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2066
|
+
NotAuthenticatedError: (err) => import_effect19.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
2067
|
+
import_effect19.Effect.andThen(import_effect19.Effect.fail(err))
|
|
1645
2068
|
),
|
|
1646
|
-
ApiRequestError: (err) =>
|
|
1647
|
-
ProjectNotLinkedError: (err) =>
|
|
1648
|
-
ProjectLinkReadError: (err) =>
|
|
2069
|
+
ApiRequestError: (err) => import_effect19.Console.error(`Failed to set environment variable: ${err.message}`).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2070
|
+
ProjectNotLinkedError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2071
|
+
ProjectLinkReadError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err)))
|
|
1649
2072
|
})
|
|
1650
2073
|
)
|
|
1651
2074
|
);
|
|
1652
2075
|
var envRmCommand = import_cli7.Command.make(
|
|
1653
2076
|
"rm",
|
|
1654
2077
|
{ keyOrId: keyOrIdArg, app: appOption3, org: orgOption4 },
|
|
1655
|
-
({ keyOrId, app, org }) =>
|
|
2078
|
+
({ keyOrId, app, org }) => import_effect19.Effect.gen(function* () {
|
|
1656
2079
|
const apiClient = yield* ApiClientService;
|
|
1657
2080
|
const scope = yield* resolveScope(app, org);
|
|
1658
2081
|
const { items } = yield* apiClient.request(
|
|
@@ -1660,32 +2083,106 @@ var envRmCommand = import_cli7.Command.make(
|
|
|
1660
2083
|
);
|
|
1661
2084
|
const target = items.find((v) => v.id === keyOrId || v.key === keyOrId);
|
|
1662
2085
|
if (target === void 0) {
|
|
1663
|
-
return yield*
|
|
2086
|
+
return yield* import_effect19.Effect.fail(
|
|
1664
2087
|
new EnvVarNotFoundError({ message: `No environment variable matching "${keyOrId}".` })
|
|
1665
2088
|
);
|
|
1666
2089
|
}
|
|
1667
2090
|
yield* apiClient.request(
|
|
1668
2091
|
(client) => scope.kind === "organization" ? client.organizations.envVars.delete(scope.id, target.id) : client.applications.envVars.delete(scope.id, target.id)
|
|
1669
2092
|
);
|
|
1670
|
-
yield*
|
|
2093
|
+
yield* import_effect19.Console.log(`Removed ${target.key}.`);
|
|
1671
2094
|
}).pipe(
|
|
1672
|
-
|
|
1673
|
-
EnvVarNotFoundError: (err) =>
|
|
1674
|
-
NotAuthenticatedError: (err) =>
|
|
1675
|
-
|
|
2095
|
+
import_effect19.Effect.catchTags({
|
|
2096
|
+
EnvVarNotFoundError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2097
|
+
NotAuthenticatedError: (err) => import_effect19.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
2098
|
+
import_effect19.Effect.andThen(import_effect19.Effect.fail(err))
|
|
1676
2099
|
),
|
|
1677
|
-
ApiRequestError: (err) =>
|
|
1678
|
-
ProjectNotLinkedError: (err) =>
|
|
1679
|
-
ProjectLinkReadError: (err) =>
|
|
2100
|
+
ApiRequestError: (err) => import_effect19.Console.error(`Failed to remove environment variable: ${err.message}`).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2101
|
+
ProjectNotLinkedError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2102
|
+
ProjectLinkReadError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err)))
|
|
1680
2103
|
})
|
|
1681
2104
|
)
|
|
1682
2105
|
);
|
|
1683
|
-
var
|
|
1684
|
-
|
|
2106
|
+
var envPullCommand = import_cli7.Command.make(
|
|
2107
|
+
"pull",
|
|
2108
|
+
{
|
|
2109
|
+
file: fileArg,
|
|
2110
|
+
app: appOption3,
|
|
2111
|
+
environment: environmentOption,
|
|
2112
|
+
yes: yesOption,
|
|
2113
|
+
withCredentials: withCredentialsOption,
|
|
2114
|
+
rotate: rotateOption
|
|
2115
|
+
},
|
|
2116
|
+
({ file, app, environment, yes, withCredentials, rotate }) => import_effect19.Effect.gen(function* () {
|
|
2117
|
+
const apiClient = yield* ApiClientService;
|
|
2118
|
+
const projectLink = yield* ProjectLinkService;
|
|
2119
|
+
const envFile = yield* EnvFileService;
|
|
2120
|
+
const applicationId = yield* import_effect19.Option.match(app, {
|
|
2121
|
+
onSome: (value) => import_effect19.Effect.succeed(value),
|
|
2122
|
+
onNone: () => projectLink.resolve(process.cwd()).pipe(import_effect19.Effect.map((link) => link.applicationId))
|
|
2123
|
+
});
|
|
2124
|
+
const target = import_effect19.Option.getOrElse(file, () => ".env.local");
|
|
2125
|
+
const environmentSlug = import_effect19.Option.getOrUndefined(environment);
|
|
2126
|
+
const { items, omittedSensitive } = yield* apiClient.request(
|
|
2127
|
+
(client) => client.applications.envVars.pull(applicationId, environmentSlug ? { environment: environmentSlug } : void 0)
|
|
2128
|
+
);
|
|
2129
|
+
const existing = yield* envFile.read(target);
|
|
2130
|
+
if (import_effect19.Option.isSome(existing) && !yes) {
|
|
2131
|
+
const overwrite = yield* import_cli7.Prompt.run(
|
|
2132
|
+
import_cli7.Prompt.confirm({ message: `${target} already exists. Overwrite?`, initial: false })
|
|
2133
|
+
);
|
|
2134
|
+
if (!overwrite) {
|
|
2135
|
+
return yield* import_effect19.Console.log("Cancelled.");
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
let credentialEntries2 = [];
|
|
2139
|
+
if (withCredentials) {
|
|
2140
|
+
const localCredentials = yield* LocalCredentialsService;
|
|
2141
|
+
credentialEntries2 = yield* localCredentials.provision({
|
|
2142
|
+
applicationId,
|
|
2143
|
+
rotate,
|
|
2144
|
+
existingContent: import_effect19.Option.getOrUndefined(existing)
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
const entries = [...items.map((v) => ({ key: v.key, value: v.value })), ...credentialEntries2];
|
|
2148
|
+
yield* envFile.write(target, entries);
|
|
2149
|
+
const gitignored = yield* envFile.ensureGitignored(process.cwd(), target);
|
|
2150
|
+
yield* import_effect19.Console.log(
|
|
2151
|
+
`Pulled ${items.length} environment variable(s)${withCredentials ? " and API credentials" : ""} to ${target}.`
|
|
2152
|
+
);
|
|
2153
|
+
if (omittedSensitive > 0) {
|
|
2154
|
+
yield* import_effect19.Console.log(
|
|
2155
|
+
`Skipped ${omittedSensitive} sensitive variable(s); secrets live only in production/preview environments.`
|
|
2156
|
+
);
|
|
2157
|
+
}
|
|
2158
|
+
if (gitignored) {
|
|
2159
|
+
yield* import_effect19.Console.log(`Added ${target} to .gitignore.`);
|
|
2160
|
+
}
|
|
2161
|
+
}).pipe(
|
|
2162
|
+
import_effect19.Effect.catchTags({
|
|
2163
|
+
// Ctrl+C during the overwrite prompt is a deliberate cancel — exit 0.
|
|
2164
|
+
QuitException: () => import_effect19.Console.log("Cancelled."),
|
|
2165
|
+
NotAuthenticatedError: (err) => import_effect19.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
2166
|
+
import_effect19.Effect.andThen(import_effect19.Effect.fail(err))
|
|
2167
|
+
),
|
|
2168
|
+
ApiRequestError: (err) => import_effect19.Console.error(`Failed to pull environment variables: ${err.message}`).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2169
|
+
ProjectNotLinkedError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2170
|
+
ProjectLinkReadError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2171
|
+
EnvFileReadError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2172
|
+
EnvFileWriteError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2173
|
+
DevCredentialsStoreReadError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err))),
|
|
2174
|
+
DevCredentialsStoreWriteError: (err) => import_effect19.Console.error(err.message).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err)))
|
|
2175
|
+
})
|
|
2176
|
+
)
|
|
2177
|
+
);
|
|
2178
|
+
var envBase = import_cli7.Command.make("env", {}, () => import_effect19.Effect.void);
|
|
2179
|
+
var envCommand = envBase.pipe(
|
|
2180
|
+
import_cli7.Command.withSubcommands([envListCommand, envSetCommand, envRmCommand, envPullCommand])
|
|
2181
|
+
);
|
|
1685
2182
|
|
|
1686
2183
|
// src/commands/link/index.ts
|
|
1687
2184
|
var import_cli8 = require("@effect/cli");
|
|
1688
|
-
var
|
|
2185
|
+
var import_effect20 = require("effect");
|
|
1689
2186
|
var appOption4 = import_cli8.Options.text("app").pipe(
|
|
1690
2187
|
import_cli8.Options.withAlias("a"),
|
|
1691
2188
|
import_cli8.Options.withDescription("Application ID to link (skips the interactive picker)"),
|
|
@@ -1699,26 +2196,26 @@ var orgOption5 = import_cli8.Options.text("org").pipe(
|
|
|
1699
2196
|
var linkCommand = import_cli8.Command.make(
|
|
1700
2197
|
"link",
|
|
1701
2198
|
{ app: appOption4, org: orgOption5 },
|
|
1702
|
-
({ app, org }) =>
|
|
2199
|
+
({ app, org }) => import_effect20.Effect.gen(function* () {
|
|
1703
2200
|
const apiClient = yield* ApiClientService;
|
|
1704
2201
|
const projectLink = yield* ProjectLinkService;
|
|
1705
2202
|
const cwd = process.cwd();
|
|
1706
|
-
const organizationId =
|
|
2203
|
+
const organizationId = import_effect20.Option.getOrUndefined(org);
|
|
1707
2204
|
const { items: apps } = yield* apiClient.request((client) => client.applications.list({ organizationId }));
|
|
1708
2205
|
if (apps.length === 0) {
|
|
1709
|
-
return yield*
|
|
2206
|
+
return yield* import_effect20.Effect.fail(
|
|
1710
2207
|
new NoApplicationsFoundError({
|
|
1711
2208
|
message: 'No applications found. Create one in the Gigadrive console, then run "gigadrive link" again.'
|
|
1712
2209
|
})
|
|
1713
2210
|
);
|
|
1714
2211
|
}
|
|
1715
|
-
const explicitAppId =
|
|
2212
|
+
const explicitAppId = import_effect20.Option.getOrUndefined(app);
|
|
1716
2213
|
let applicationId;
|
|
1717
2214
|
let linkedOrganizationId;
|
|
1718
2215
|
if (explicitAppId !== void 0) {
|
|
1719
2216
|
const match = apps.find((a) => a.id === explicitAppId);
|
|
1720
2217
|
if (match === void 0) {
|
|
1721
|
-
return yield*
|
|
2218
|
+
return yield* import_effect20.Effect.fail(
|
|
1722
2219
|
new ApplicationNotFoundError({
|
|
1723
2220
|
message: `Application "${explicitAppId}" was not found among your applications.`
|
|
1724
2221
|
})
|
|
@@ -1740,106 +2237,109 @@ var linkCommand = import_cli8.Command.make(
|
|
|
1740
2237
|
linkedOrganizationId = chosen.organization.id;
|
|
1741
2238
|
}
|
|
1742
2239
|
yield* projectLink.save(cwd, { applicationId, organizationId: linkedOrganizationId });
|
|
1743
|
-
yield*
|
|
1744
|
-
yield*
|
|
2240
|
+
yield* import_effect20.Console.log(`Linked this directory to application ${applicationId}.`);
|
|
2241
|
+
yield* import_effect20.Console.log('Tip: add ".gigadrive/" to your .gitignore.');
|
|
1745
2242
|
}).pipe(
|
|
1746
|
-
|
|
2243
|
+
import_effect20.Effect.catchTags({
|
|
1747
2244
|
// Ctrl+C during the picker is a deliberate cancel — exit 0.
|
|
1748
|
-
QuitException: () =>
|
|
1749
|
-
NotAuthenticatedError: (err) =>
|
|
1750
|
-
|
|
2245
|
+
QuitException: () => import_effect20.Console.log("Cancelled."),
|
|
2246
|
+
NotAuthenticatedError: (err) => import_effect20.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
2247
|
+
import_effect20.Effect.andThen(import_effect20.Effect.fail(err))
|
|
1751
2248
|
),
|
|
1752
|
-
ApiRequestError: (err) =>
|
|
1753
|
-
NoApplicationsFoundError: (err) =>
|
|
1754
|
-
ApplicationNotFoundError: (err) =>
|
|
1755
|
-
ProjectLinkWriteError: (err) =>
|
|
2249
|
+
ApiRequestError: (err) => import_effect20.Console.error(`Failed to list applications: ${err.message}`).pipe(import_effect20.Effect.andThen(import_effect20.Effect.fail(err))),
|
|
2250
|
+
NoApplicationsFoundError: (err) => import_effect20.Console.error(err.message).pipe(import_effect20.Effect.andThen(import_effect20.Effect.fail(err))),
|
|
2251
|
+
ApplicationNotFoundError: (err) => import_effect20.Console.error(err.message).pipe(import_effect20.Effect.andThen(import_effect20.Effect.fail(err))),
|
|
2252
|
+
ProjectLinkWriteError: (err) => import_effect20.Console.error(err.message).pipe(import_effect20.Effect.andThen(import_effect20.Effect.fail(err)))
|
|
1756
2253
|
})
|
|
1757
2254
|
)
|
|
1758
2255
|
);
|
|
1759
2256
|
var unlinkCommand = import_cli8.Command.make(
|
|
1760
2257
|
"unlink",
|
|
1761
2258
|
{},
|
|
1762
|
-
() =>
|
|
2259
|
+
() => import_effect20.Effect.gen(function* () {
|
|
1763
2260
|
const projectLink = yield* ProjectLinkService;
|
|
1764
2261
|
yield* projectLink.remove(process.cwd());
|
|
1765
|
-
yield*
|
|
2262
|
+
yield* import_effect20.Console.log("Unlinked this directory.");
|
|
1766
2263
|
}).pipe(
|
|
1767
|
-
|
|
1768
|
-
ProjectLinkWriteError: (err) =>
|
|
2264
|
+
import_effect20.Effect.catchTags({
|
|
2265
|
+
ProjectLinkWriteError: (err) => import_effect20.Console.error(err.message).pipe(import_effect20.Effect.andThen(import_effect20.Effect.fail(err)))
|
|
1769
2266
|
})
|
|
1770
2267
|
)
|
|
1771
2268
|
);
|
|
1772
2269
|
|
|
1773
2270
|
// src/commands/login/index.ts
|
|
1774
2271
|
var import_cli9 = require("@effect/cli");
|
|
1775
|
-
var
|
|
2272
|
+
var import_effect21 = require("effect");
|
|
1776
2273
|
var loginCommand = import_cli9.Command.make(
|
|
1777
2274
|
"login",
|
|
1778
2275
|
{},
|
|
1779
|
-
() =>
|
|
1780
|
-
yield*
|
|
2276
|
+
() => import_effect21.Effect.gen(function* () {
|
|
2277
|
+
yield* import_effect21.Console.log("Initiating login...");
|
|
1781
2278
|
const auth = yield* AuthService;
|
|
1782
2279
|
yield* auth.login;
|
|
1783
|
-
const info = yield* auth.getUserInfo.pipe(
|
|
2280
|
+
const info = yield* auth.getUserInfo.pipe(import_effect21.Effect.catchAll(() => import_effect21.Effect.succeed({})));
|
|
1784
2281
|
const name = auth.inferUserName(info);
|
|
1785
|
-
yield*
|
|
2282
|
+
yield* import_effect21.Console.log(`You are now logged in as ${name}.`);
|
|
1786
2283
|
}).pipe(
|
|
1787
|
-
|
|
1788
|
-
LoginFlowError: (err) =>
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2284
|
+
import_effect21.Effect.catchTags({
|
|
2285
|
+
LoginFlowError: (err) => import_effect21.Console.error(err.message),
|
|
2286
|
+
DeviceAuthorizationError: (err) => import_effect21.Console.error(`Login failed: ${err.message}`),
|
|
2287
|
+
AuthorizationDeniedError: (err) => import_effect21.Console.error(err.message),
|
|
2288
|
+
DeviceCodeExpiredError: (err) => import_effect21.Console.error(err.message),
|
|
2289
|
+
TokenExchangeError: (err) => import_effect21.Console.error(`Login failed: ${err.message}`),
|
|
2290
|
+
OAuthDiscoveryError: (err) => import_effect21.Console.error(`Login failed: ${err.message}`),
|
|
2291
|
+
AuthStorageWriteError: (err) => import_effect21.Console.error(`Failed to save credentials: ${err.message}`)
|
|
1792
2292
|
})
|
|
1793
2293
|
)
|
|
1794
2294
|
);
|
|
1795
2295
|
|
|
1796
2296
|
// src/commands/logout/index.ts
|
|
1797
2297
|
var import_cli10 = require("@effect/cli");
|
|
1798
|
-
var
|
|
2298
|
+
var import_effect22 = require("effect");
|
|
1799
2299
|
var logoutCommand = import_cli10.Command.make(
|
|
1800
2300
|
"logout",
|
|
1801
2301
|
{},
|
|
1802
|
-
() =>
|
|
2302
|
+
() => import_effect22.Effect.gen(function* () {
|
|
1803
2303
|
const auth = yield* AuthService;
|
|
1804
2304
|
yield* auth.logout;
|
|
1805
|
-
yield*
|
|
2305
|
+
yield* import_effect22.Console.log("Logged out.");
|
|
1806
2306
|
}).pipe(
|
|
1807
|
-
|
|
1808
|
-
AuthStorageWriteError: (err) =>
|
|
2307
|
+
import_effect22.Effect.catchTags({
|
|
2308
|
+
AuthStorageWriteError: (err) => import_effect22.Console.error(`Failed to log out: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err)))
|
|
1809
2309
|
})
|
|
1810
2310
|
)
|
|
1811
2311
|
);
|
|
1812
2312
|
|
|
1813
2313
|
// src/commands/platform/index.ts
|
|
1814
2314
|
var import_cli12 = require("@effect/cli");
|
|
1815
|
-
var
|
|
2315
|
+
var import_effect26 = require("effect");
|
|
1816
2316
|
|
|
1817
2317
|
// src/commands/platform/deploy/index.ts
|
|
1818
2318
|
var import_cli11 = require("@effect/cli");
|
|
1819
|
-
var
|
|
2319
|
+
var import_platform9 = require("@effect/platform");
|
|
1820
2320
|
var import_commons = require("@gigadrive/commons");
|
|
1821
|
-
var
|
|
1822
|
-
var
|
|
2321
|
+
var import_effect25 = require("effect");
|
|
2322
|
+
var os4 = __toESM(require("os"), 1);
|
|
1823
2323
|
|
|
1824
2324
|
// src/services/archive.ts
|
|
1825
|
-
var
|
|
2325
|
+
var import_platform8 = require("@effect/platform");
|
|
1826
2326
|
var import_build_utils3 = require("@gigadrive/build-utils");
|
|
1827
2327
|
var import_archiver = __toESM(require("archiver"), 1);
|
|
1828
|
-
var
|
|
2328
|
+
var import_effect23 = require("effect");
|
|
1829
2329
|
var import_ignore = __toESM(require("ignore"), 1);
|
|
1830
2330
|
var nodeFs = __toESM(require("fs"), 1);
|
|
1831
2331
|
var nodeFsPromises = __toESM(require("fs/promises"), 1);
|
|
1832
2332
|
var IGNORE_FILE_NAMES = [".gigadriveignore", ".vercelignore", ".dockerignore", ".nowignore"];
|
|
1833
2333
|
var readIgnoreFile = (fs, ignorePath) => fs.readFileString(ignorePath, "utf8").pipe(
|
|
1834
|
-
|
|
1835
|
-
|
|
2334
|
+
import_effect23.Effect.map((content) => content.split("\n").filter((line) => line.trim() !== "")),
|
|
2335
|
+
import_effect23.Effect.catchAll(() => import_effect23.Effect.succeed([]))
|
|
1836
2336
|
);
|
|
1837
|
-
var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) =>
|
|
1838
|
-
const items = yield* fs.readDirectory(dir).pipe(
|
|
2337
|
+
var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) => import_effect23.Effect.gen(function* () {
|
|
2338
|
+
const items = yield* fs.readDirectory(dir).pipe(import_effect23.Effect.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${dir}` })));
|
|
1839
2339
|
for (const item of items) {
|
|
1840
2340
|
const fullPath = pathService.join(dir, item);
|
|
1841
2341
|
const relativePath = pathService.relative(baseDir, fullPath);
|
|
1842
|
-
const stat = yield*
|
|
2342
|
+
const stat = yield* import_effect23.Effect.tryPromise({
|
|
1843
2343
|
try: () => nodeFsPromises.lstat(fullPath),
|
|
1844
2344
|
catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
|
|
1845
2345
|
});
|
|
@@ -1859,8 +2359,8 @@ var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) => impo
|
|
|
1859
2359
|
yield* collectIgnorePatterns(fs, pathService, fullPath, baseDir, ignoreRules);
|
|
1860
2360
|
}
|
|
1861
2361
|
}
|
|
1862
|
-
}).pipe(
|
|
1863
|
-
var initializeIgnoreRules = (fs, pathService, baseDir) =>
|
|
2362
|
+
}).pipe(import_effect23.Effect.catchAll(() => import_effect23.Effect.void));
|
|
2363
|
+
var initializeIgnoreRules = (fs, pathService, baseDir) => import_effect23.Effect.gen(function* () {
|
|
1864
2364
|
const ignoreRules = (0, import_ignore.default)();
|
|
1865
2365
|
ignoreRules.add([".git/", "**/.DS_Store", "**/Thumbs.db"]);
|
|
1866
2366
|
for (const ignoreFileName of IGNORE_FILE_NAMES) {
|
|
@@ -1875,14 +2375,14 @@ var initializeIgnoreRules = (fs, pathService, baseDir) => import_effect20.Effect
|
|
|
1875
2375
|
yield* collectIgnorePatterns(fs, pathService, baseDir, baseDir, ignoreRules);
|
|
1876
2376
|
return ignoreRules;
|
|
1877
2377
|
});
|
|
1878
|
-
var getFilesToInclude = (fs, pathService, dir, ignoreRules) =>
|
|
2378
|
+
var getFilesToInclude = (fs, pathService, dir, ignoreRules) => import_effect23.Effect.gen(function* () {
|
|
1879
2379
|
const filesToInclude = [];
|
|
1880
|
-
const walkDir = (currentDir) =>
|
|
1881
|
-
const items = yield* fs.readDirectory(currentDir).pipe(
|
|
2380
|
+
const walkDir = (currentDir) => import_effect23.Effect.gen(function* () {
|
|
2381
|
+
const items = yield* fs.readDirectory(currentDir).pipe(import_effect23.Effect.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${currentDir}` })));
|
|
1882
2382
|
for (const item of items) {
|
|
1883
2383
|
const fullPath = pathService.join(currentDir, item);
|
|
1884
2384
|
const relativePath = pathService.relative(dir, fullPath);
|
|
1885
|
-
const stat = yield*
|
|
2385
|
+
const stat = yield* import_effect23.Effect.tryPromise({
|
|
1886
2386
|
try: () => nodeFsPromises.lstat(fullPath),
|
|
1887
2387
|
catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
|
|
1888
2388
|
});
|
|
@@ -1896,21 +2396,21 @@ var getFilesToInclude = (fs, pathService, dir, ignoreRules) => import_effect20.E
|
|
|
1896
2396
|
}
|
|
1897
2397
|
}
|
|
1898
2398
|
}
|
|
1899
|
-
}).pipe(
|
|
2399
|
+
}).pipe(import_effect23.Effect.catchAll(() => import_effect23.Effect.void));
|
|
1900
2400
|
yield* walkDir(dir);
|
|
1901
2401
|
return filesToInclude;
|
|
1902
2402
|
});
|
|
1903
|
-
var ArchiveService = class extends
|
|
2403
|
+
var ArchiveService = class extends import_effect23.Effect.Service()("ArchiveService", {
|
|
1904
2404
|
accessors: true,
|
|
1905
|
-
effect:
|
|
1906
|
-
const fs = yield*
|
|
1907
|
-
const pathService = yield*
|
|
1908
|
-
const createZipArchive =
|
|
1909
|
-
yield*
|
|
1910
|
-
yield*
|
|
1911
|
-
yield*
|
|
2405
|
+
effect: import_effect23.Effect.gen(function* () {
|
|
2406
|
+
const fs = yield* import_platform8.FileSystem.FileSystem;
|
|
2407
|
+
const pathService = yield* import_platform8.Path.Path;
|
|
2408
|
+
const createZipArchive = import_effect23.Effect.fn("ArchiveService.createZipArchive")(function* (inputDir, outputFile, options = {}) {
|
|
2409
|
+
yield* import_effect23.Effect.annotateCurrentSpan("inputDir", inputDir);
|
|
2410
|
+
yield* import_effect23.Effect.annotateCurrentSpan("outputFile", outputFile);
|
|
2411
|
+
yield* import_effect23.Effect.log("Creating zip archive", { inputDir, outputFile });
|
|
1912
2412
|
const ignoreRules = options.useIgnoreFiles !== false ? yield* initializeIgnoreRules(fs, pathService, inputDir) : (0, import_ignore.default)();
|
|
1913
|
-
const filesToInclude = options.whitelist ? yield*
|
|
2413
|
+
const filesToInclude = options.whitelist ? yield* import_effect23.Effect.tryPromise({
|
|
1914
2414
|
try: () => Promise.all(
|
|
1915
2415
|
options.whitelist.map((file) => (0, import_build_utils3.getFilesForPattern)(file, inputDir, options.excludeFiles ?? []))
|
|
1916
2416
|
),
|
|
@@ -1918,25 +2418,25 @@ var ArchiveService = class extends import_effect20.Effect.Service()("ArchiveServ
|
|
|
1918
2418
|
message: "Failed to resolve whitelist patterns",
|
|
1919
2419
|
cause: error instanceof Error ? error.message : String(error)
|
|
1920
2420
|
})
|
|
1921
|
-
}) : yield*
|
|
2421
|
+
}) : yield* import_effect23.Effect.gen(function* () {
|
|
1922
2422
|
if (options.excludeFiles && options.excludeFiles.length > 0) {
|
|
1923
2423
|
ignoreRules.add(options.excludeFiles);
|
|
1924
2424
|
}
|
|
1925
2425
|
return yield* getFilesToInclude(fs, pathService, inputDir, ignoreRules).pipe(
|
|
1926
|
-
|
|
2426
|
+
import_effect23.Effect.map((files) => [files])
|
|
1927
2427
|
);
|
|
1928
2428
|
});
|
|
1929
|
-
const archiveExists = yield* fs.exists(outputFile).pipe(
|
|
2429
|
+
const archiveExists = yield* fs.exists(outputFile).pipe(import_effect23.Effect.catchAll(() => import_effect23.Effect.succeed(false)));
|
|
1930
2430
|
if (archiveExists) {
|
|
1931
2431
|
yield* fs.remove(outputFile).pipe(
|
|
1932
|
-
|
|
2432
|
+
import_effect23.Effect.mapError(
|
|
1933
2433
|
(error) => new ArchiveCreateError({
|
|
1934
2434
|
message: `Failed to remove existing archive: ${String(error)}`
|
|
1935
2435
|
})
|
|
1936
2436
|
)
|
|
1937
2437
|
);
|
|
1938
2438
|
}
|
|
1939
|
-
yield*
|
|
2439
|
+
yield* import_effect23.Effect.tryPromise({
|
|
1940
2440
|
try: () => new Promise((resolve, reject) => {
|
|
1941
2441
|
const output = nodeFs.createWriteStream(outputFile);
|
|
1942
2442
|
const archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } });
|
|
@@ -1955,14 +2455,14 @@ var ArchiveService = class extends import_effect20.Effect.Service()("ArchiveServ
|
|
|
1955
2455
|
})
|
|
1956
2456
|
});
|
|
1957
2457
|
const fileInfo = yield* fs.stat(outputFile).pipe(
|
|
1958
|
-
|
|
2458
|
+
import_effect23.Effect.mapError(
|
|
1959
2459
|
(error) => new ArchiveCreateError({
|
|
1960
2460
|
message: `Failed to stat archive: ${String(error)}`
|
|
1961
2461
|
})
|
|
1962
2462
|
)
|
|
1963
2463
|
);
|
|
1964
2464
|
const size = Number(fileInfo.size);
|
|
1965
|
-
yield*
|
|
2465
|
+
yield* import_effect23.Effect.log("Archive created", { size });
|
|
1966
2466
|
return { path: outputFile, size };
|
|
1967
2467
|
});
|
|
1968
2468
|
return { createZipArchive };
|
|
@@ -1971,32 +2471,32 @@ var ArchiveService = class extends import_effect20.Effect.Service()("ArchiveServ
|
|
|
1971
2471
|
};
|
|
1972
2472
|
|
|
1973
2473
|
// src/services/deployment-api.ts
|
|
1974
|
-
var
|
|
1975
|
-
var DeploymentApiService = class extends
|
|
2474
|
+
var import_effect24 = require("effect");
|
|
2475
|
+
var DeploymentApiService = class extends import_effect24.Effect.Service()("DeploymentApiService", {
|
|
1976
2476
|
accessors: true,
|
|
1977
2477
|
dependencies: [ApiClientService.Default],
|
|
1978
|
-
effect:
|
|
2478
|
+
effect: import_effect24.Effect.gen(function* () {
|
|
1979
2479
|
const apiClient = yield* ApiClientService;
|
|
1980
2480
|
const getClient = apiClient.getClient.pipe(
|
|
1981
|
-
|
|
2481
|
+
import_effect24.Effect.mapError((err) => new DeploymentAuthError({ message: `Authentication failed: ${err.message}` }))
|
|
1982
2482
|
);
|
|
1983
|
-
const createDeployment =
|
|
1984
|
-
yield*
|
|
1985
|
-
yield*
|
|
2483
|
+
const createDeployment = import_effect24.Effect.fn("DeploymentApiService.createDeployment")(function* (applicationId) {
|
|
2484
|
+
yield* import_effect24.Effect.annotateCurrentSpan("applicationId", applicationId);
|
|
2485
|
+
yield* import_effect24.Effect.log("Creating deployment", { applicationId });
|
|
1986
2486
|
const client = yield* getClient;
|
|
1987
|
-
const deployment = yield*
|
|
2487
|
+
const deployment = yield* import_effect24.Effect.tryPromise({
|
|
1988
2488
|
try: () => client.deployments.create({ applicationId }),
|
|
1989
2489
|
catch: (error) => new DeploymentCreateError({
|
|
1990
2490
|
message: `Failed to create deployment: ${error instanceof Error ? error.message : String(error)}`
|
|
1991
2491
|
})
|
|
1992
2492
|
});
|
|
1993
|
-
yield*
|
|
2493
|
+
yield* import_effect24.Effect.log("Deployment created", { deploymentId: deployment.id });
|
|
1994
2494
|
return deployment.id;
|
|
1995
2495
|
});
|
|
1996
|
-
const startMultipartUpload =
|
|
1997
|
-
yield*
|
|
2496
|
+
const startMultipartUpload = import_effect24.Effect.fn("DeploymentApiService.startMultipartUpload")(function* (deploymentId) {
|
|
2497
|
+
yield* import_effect24.Effect.annotateCurrentSpan("deploymentId", deploymentId);
|
|
1998
2498
|
const client = yield* getClient;
|
|
1999
|
-
const result = yield*
|
|
2499
|
+
const result = yield* import_effect24.Effect.tryPromise({
|
|
2000
2500
|
try: () => client.deployments.startUpload(deploymentId),
|
|
2001
2501
|
catch: (error) => new UploadStartError({
|
|
2002
2502
|
message: `Failed to start multipart upload: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -2004,9 +2504,9 @@ var DeploymentApiService = class extends import_effect21.Effect.Service()("Deplo
|
|
|
2004
2504
|
});
|
|
2005
2505
|
return result.uploadId;
|
|
2006
2506
|
});
|
|
2007
|
-
const getPresignedUrl =
|
|
2507
|
+
const getPresignedUrl = import_effect24.Effect.fn("DeploymentApiService.getPresignedUrl")(function* (deploymentId, uploadId, partNumber) {
|
|
2008
2508
|
const client = yield* getClient;
|
|
2009
|
-
const result = yield*
|
|
2509
|
+
const result = yield* import_effect24.Effect.tryPromise({
|
|
2010
2510
|
try: () => client.deployments.getPresignedUrl(deploymentId, uploadId, partNumber),
|
|
2011
2511
|
catch: (error) => new PresignedUrlError({
|
|
2012
2512
|
message: `Failed to get presigned URL: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -2015,11 +2515,11 @@ var DeploymentApiService = class extends import_effect21.Effect.Service()("Deplo
|
|
|
2015
2515
|
});
|
|
2016
2516
|
return result.url;
|
|
2017
2517
|
});
|
|
2018
|
-
const uploadPart =
|
|
2019
|
-
yield*
|
|
2020
|
-
yield*
|
|
2518
|
+
const uploadPart = import_effect24.Effect.fn("DeploymentApiService.uploadPart")(function* (presignedUrl, data, partNumber) {
|
|
2519
|
+
yield* import_effect24.Effect.annotateCurrentSpan("partNumber", partNumber);
|
|
2520
|
+
yield* import_effect24.Effect.annotateCurrentSpan("size", data.length);
|
|
2021
2521
|
const client = yield* getClient;
|
|
2022
|
-
const result = yield*
|
|
2522
|
+
const result = yield* import_effect24.Effect.tryPromise({
|
|
2023
2523
|
try: () => client.deployments.uploadPart(presignedUrl, data, partNumber),
|
|
2024
2524
|
catch: (error) => new UploadPartError({
|
|
2025
2525
|
message: `Failed to upload part ${partNumber}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -2028,21 +2528,21 @@ var DeploymentApiService = class extends import_effect21.Effect.Service()("Deplo
|
|
|
2028
2528
|
});
|
|
2029
2529
|
return result;
|
|
2030
2530
|
});
|
|
2031
|
-
const completeUpload =
|
|
2032
|
-
yield*
|
|
2033
|
-
yield*
|
|
2531
|
+
const completeUpload = import_effect24.Effect.fn("DeploymentApiService.completeUpload")(function* (deploymentId, uploadId, parts) {
|
|
2532
|
+
yield* import_effect24.Effect.annotateCurrentSpan("deploymentId", deploymentId);
|
|
2533
|
+
yield* import_effect24.Effect.annotateCurrentSpan("partsCount", parts.length);
|
|
2034
2534
|
const client = yield* getClient;
|
|
2035
|
-
yield*
|
|
2535
|
+
yield* import_effect24.Effect.tryPromise({
|
|
2036
2536
|
try: () => client.deployments.completeUpload(deploymentId, uploadId, parts),
|
|
2037
2537
|
catch: (error) => new UploadCompleteError({
|
|
2038
2538
|
message: `Failed to complete upload: ${error instanceof Error ? error.message : String(error)}`
|
|
2039
2539
|
})
|
|
2040
2540
|
});
|
|
2041
|
-
yield*
|
|
2541
|
+
yield* import_effect24.Effect.log("Upload completed successfully");
|
|
2042
2542
|
});
|
|
2043
|
-
const getDeploymentStatus =
|
|
2543
|
+
const getDeploymentStatus = import_effect24.Effect.fn("DeploymentApiService.getDeploymentStatus")(function* (deploymentId) {
|
|
2044
2544
|
const client = yield* getClient;
|
|
2045
|
-
const deployment = yield*
|
|
2545
|
+
const deployment = yield* import_effect24.Effect.tryPromise({
|
|
2046
2546
|
try: () => client.deployments.get(deploymentId),
|
|
2047
2547
|
catch: (error) => new DeploymentStatusError({
|
|
2048
2548
|
message: `Failed to get deployment status: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -2050,9 +2550,9 @@ var DeploymentApiService = class extends import_effect21.Effect.Service()("Deplo
|
|
|
2050
2550
|
});
|
|
2051
2551
|
return deployment.status;
|
|
2052
2552
|
});
|
|
2053
|
-
const getLogs =
|
|
2553
|
+
const getLogs = import_effect24.Effect.fn("DeploymentApiService.getLogs")(function* (deploymentId, options) {
|
|
2054
2554
|
const client = yield* getClient;
|
|
2055
|
-
const result = yield*
|
|
2555
|
+
const result = yield* import_effect24.Effect.tryPromise({
|
|
2056
2556
|
try: () => client.deployments.getLogs(deploymentId, options),
|
|
2057
2557
|
catch: (error) => new DeploymentLogsFetchError({
|
|
2058
2558
|
message: `Failed to get logs: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -2060,9 +2560,9 @@ var DeploymentApiService = class extends import_effect21.Effect.Service()("Deplo
|
|
|
2060
2560
|
});
|
|
2061
2561
|
return result;
|
|
2062
2562
|
});
|
|
2063
|
-
const getHostnames =
|
|
2563
|
+
const getHostnames = import_effect24.Effect.fn("DeploymentApiService.getHostnames")(function* (deploymentId) {
|
|
2064
2564
|
const client = yield* getClient;
|
|
2065
|
-
const result = yield*
|
|
2565
|
+
const result = yield* import_effect24.Effect.tryPromise({
|
|
2066
2566
|
try: () => client.deployments.getHostnames(deploymentId),
|
|
2067
2567
|
catch: (error) => new DeploymentHostnamesFetchError({
|
|
2068
2568
|
message: `Failed to get hostnames: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -2093,86 +2593,86 @@ var appOption5 = import_cli11.Options.text("app").pipe(
|
|
|
2093
2593
|
var deployCommand = import_cli11.Command.make(
|
|
2094
2594
|
"deploy",
|
|
2095
2595
|
{ app: appOption5 },
|
|
2096
|
-
({ app }) =>
|
|
2596
|
+
({ app }) => import_effect25.Effect.gen(function* () {
|
|
2097
2597
|
const projectConfig = yield* ProjectConfigService;
|
|
2098
2598
|
const deploymentApi = yield* DeploymentApiService;
|
|
2099
2599
|
const archiveService = yield* ArchiveService;
|
|
2100
2600
|
const projectLink = yield* ProjectLinkService;
|
|
2101
|
-
const pathService = yield*
|
|
2601
|
+
const pathService = yield* import_platform9.Path.Path;
|
|
2102
2602
|
const cwd = process.cwd();
|
|
2103
|
-
const applicationId = yield*
|
|
2104
|
-
onSome: (id) =>
|
|
2105
|
-
onNone: () => projectLink.resolve(cwd).pipe(
|
|
2603
|
+
const applicationId = yield* import_effect25.Option.match(app, {
|
|
2604
|
+
onSome: (id) => import_effect25.Effect.succeed(id),
|
|
2605
|
+
onNone: () => projectLink.resolve(cwd).pipe(import_effect25.Effect.map((link) => link.applicationId))
|
|
2106
2606
|
});
|
|
2107
|
-
yield*
|
|
2607
|
+
yield* import_effect25.Effect.log("Starting deploy command");
|
|
2108
2608
|
const { config } = yield* projectConfig.resolve(cwd);
|
|
2109
|
-
yield*
|
|
2609
|
+
yield* import_effect25.Console.log("Creating deployment...");
|
|
2110
2610
|
const deploymentId = yield* deploymentApi.createDeployment(applicationId);
|
|
2111
|
-
yield*
|
|
2112
|
-
yield*
|
|
2113
|
-
const archivePath = pathService.join(
|
|
2611
|
+
yield* import_effect25.Console.log(`Deployment ID: ${deploymentId}`);
|
|
2612
|
+
yield* import_effect25.Console.log("Creating archive...");
|
|
2613
|
+
const archivePath = pathService.join(os4.tmpdir(), `project-${Date.now()}.zip`);
|
|
2114
2614
|
const archive = yield* archiveService.createZipArchive(config.userArchive?.rootOverwrite || cwd, archivePath, {
|
|
2115
2615
|
whitelist: config.userArchive?.fileWhitelist,
|
|
2116
2616
|
excludeFiles: config.excludeFiles,
|
|
2117
2617
|
useIgnoreFiles: false,
|
|
2118
2618
|
useManagedIgnore: false
|
|
2119
2619
|
});
|
|
2120
|
-
yield*
|
|
2121
|
-
yield*
|
|
2620
|
+
yield* import_effect25.Console.log(`Archive created (${(0, import_commons.formatFileSize)(archive.size)})`);
|
|
2621
|
+
yield* import_effect25.Console.log("Uploading archive...");
|
|
2122
2622
|
yield* uploadArchive(deploymentId, archivePath, archive.size);
|
|
2123
|
-
yield*
|
|
2124
|
-
yield*
|
|
2623
|
+
yield* import_effect25.Console.log("Upload complete.");
|
|
2624
|
+
yield* import_effect25.Console.log("The deployment pipeline is now being provisioned. This may take a few seconds.");
|
|
2125
2625
|
yield* pollDeployment(deploymentId);
|
|
2126
2626
|
}).pipe(
|
|
2127
|
-
|
|
2128
|
-
ProjectNotLinkedError: (err) =>
|
|
2129
|
-
ProjectLinkReadError: (err) =>
|
|
2130
|
-
ConfigNotFoundError: (err) =>
|
|
2131
|
-
ConfigParseError: (err) =>
|
|
2132
|
-
ConfigValidationError: (err) =>
|
|
2627
|
+
import_effect25.Effect.catchTags({
|
|
2628
|
+
ProjectNotLinkedError: (err) => import_effect25.Console.error(err.message).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2629
|
+
ProjectLinkReadError: (err) => import_effect25.Console.error(err.message).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2630
|
+
ConfigNotFoundError: (err) => import_effect25.Console.error(err.message).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2631
|
+
ConfigParseError: (err) => import_effect25.Console.error(`Config parse error: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2632
|
+
ConfigValidationError: (err) => import_effect25.Effect.gen(function* () {
|
|
2133
2633
|
for (const e of err.errors) {
|
|
2134
|
-
yield*
|
|
2634
|
+
yield* import_effect25.Console.error(e);
|
|
2135
2635
|
}
|
|
2136
|
-
yield*
|
|
2137
|
-
}).pipe(
|
|
2138
|
-
DeploymentCreateError: (err) =>
|
|
2139
|
-
ArchiveCreateError: (err) =>
|
|
2140
|
-
UploadStartError: (err) =>
|
|
2141
|
-
UploadPartError: (err) =>
|
|
2142
|
-
UploadCompleteError: (err) =>
|
|
2143
|
-
PresignedUrlError: (err) =>
|
|
2144
|
-
DeploymentAuthError: (err) =>
|
|
2145
|
-
DeploymentFailedError: (err) =>
|
|
2636
|
+
yield* import_effect25.Console.error(err.message);
|
|
2637
|
+
}).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2638
|
+
DeploymentCreateError: (err) => import_effect25.Console.error(`Deployment creation failed: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2639
|
+
ArchiveCreateError: (err) => import_effect25.Console.error(`Archive creation failed: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2640
|
+
UploadStartError: (err) => import_effect25.Console.error(`Upload failed: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2641
|
+
UploadPartError: (err) => import_effect25.Console.error(`Upload failed: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2642
|
+
UploadCompleteError: (err) => import_effect25.Console.error(`Upload failed: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2643
|
+
PresignedUrlError: (err) => import_effect25.Console.error(`Upload failed: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2644
|
+
DeploymentAuthError: (err) => import_effect25.Console.error(`Authentication failed: ${err.message}`).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err))),
|
|
2645
|
+
DeploymentFailedError: (err) => import_effect25.Console.error(err.message).pipe(import_effect25.Effect.andThen(import_effect25.Effect.fail(err)))
|
|
2146
2646
|
})
|
|
2147
2647
|
)
|
|
2148
2648
|
);
|
|
2149
|
-
var uploadArchive = (deploymentId, archivePath, fileSize) =>
|
|
2649
|
+
var uploadArchive = (deploymentId, archivePath, fileSize) => import_effect25.Effect.gen(function* () {
|
|
2150
2650
|
const deploymentApi = yield* DeploymentApiService;
|
|
2151
|
-
const fs = yield*
|
|
2651
|
+
const fs = yield* import_platform9.FileSystem.FileSystem;
|
|
2152
2652
|
const uploadId = yield* deploymentApi.startMultipartUpload(deploymentId);
|
|
2153
2653
|
const FILE_CHUNK_SIZE = 10 * 1024 * 1024;
|
|
2154
2654
|
const numChunks = Math.ceil(fileSize / FILE_CHUNK_SIZE);
|
|
2155
|
-
yield*
|
|
2156
|
-
const parts = yield*
|
|
2655
|
+
yield* import_effect25.Effect.log("Starting multipart upload", { uploadId, numChunks, fileSize });
|
|
2656
|
+
const parts = yield* import_effect25.Effect.all(
|
|
2157
2657
|
Array.from({ length: numChunks }, (_, i) => {
|
|
2158
2658
|
const partNumber = i + 1;
|
|
2159
2659
|
const start = i * FILE_CHUNK_SIZE;
|
|
2160
2660
|
const bytesToRead = partNumber < numChunks ? FILE_CHUNK_SIZE : fileSize - start;
|
|
2161
|
-
return
|
|
2661
|
+
return import_effect25.Effect.gen(function* () {
|
|
2162
2662
|
const presignedUrl = yield* deploymentApi.getPresignedUrl(deploymentId, uploadId, partNumber);
|
|
2163
|
-
const chunkData = yield*
|
|
2164
|
-
|
|
2663
|
+
const chunkData = yield* import_effect25.Stream.runCollect(fs.stream(archivePath, { offset: start, bytesToRead })).pipe(
|
|
2664
|
+
import_effect25.Effect.map((chunks) => {
|
|
2165
2665
|
const arrays = Array.from(chunks);
|
|
2166
2666
|
return Buffer.concat(arrays);
|
|
2167
2667
|
}),
|
|
2168
|
-
|
|
2668
|
+
import_effect25.Effect.mapError(
|
|
2169
2669
|
(error) => new UploadPartError({
|
|
2170
2670
|
message: `Failed to read chunk ${partNumber}: ${String(error)}`,
|
|
2171
2671
|
partNumber
|
|
2172
2672
|
})
|
|
2173
2673
|
)
|
|
2174
2674
|
);
|
|
2175
|
-
yield*
|
|
2675
|
+
yield* import_effect25.Effect.log(`Uploading part ${partNumber}/${numChunks}`, { size: chunkData.length });
|
|
2176
2676
|
return yield* deploymentApi.uploadPart(presignedUrl, chunkData, partNumber);
|
|
2177
2677
|
});
|
|
2178
2678
|
}),
|
|
@@ -2180,20 +2680,20 @@ var uploadArchive = (deploymentId, archivePath, fileSize) => import_effect22.Eff
|
|
|
2180
2680
|
);
|
|
2181
2681
|
yield* deploymentApi.completeUpload(deploymentId, uploadId, parts);
|
|
2182
2682
|
});
|
|
2183
|
-
var pollDeployment = (deploymentId) =>
|
|
2683
|
+
var pollDeployment = (deploymentId) => import_effect25.Effect.gen(function* () {
|
|
2184
2684
|
const deploymentApi = yield* DeploymentApiService;
|
|
2185
2685
|
let lastStatus = "PENDING";
|
|
2186
2686
|
let logOffset = 0;
|
|
2187
|
-
yield*
|
|
2188
|
-
yield*
|
|
2189
|
-
|
|
2190
|
-
const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(
|
|
2687
|
+
yield* import_effect25.Console.log("Status: Pending");
|
|
2688
|
+
yield* import_effect25.Effect.repeat(
|
|
2689
|
+
import_effect25.Effect.gen(function* () {
|
|
2690
|
+
const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(import_effect25.Effect.catchTag("DeploymentStatusError", () => import_effect25.Effect.succeed(lastStatus)));
|
|
2191
2691
|
if (newStatus !== lastStatus) {
|
|
2192
2692
|
lastStatus = newStatus;
|
|
2193
2693
|
const label = newStatus.charAt(0) + newStatus.slice(1).toLowerCase();
|
|
2194
|
-
yield*
|
|
2694
|
+
yield* import_effect25.Console.log(`Status: ${label}`);
|
|
2195
2695
|
}
|
|
2196
|
-
const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(
|
|
2696
|
+
const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(import_effect25.Effect.catchTag("DeploymentLogsFetchError", () => import_effect25.Effect.succeed(null)));
|
|
2197
2697
|
if (logsPage) {
|
|
2198
2698
|
for (const logEntry of logsPage.items) {
|
|
2199
2699
|
logOffset++;
|
|
@@ -2201,68 +2701,211 @@ var pollDeployment = (deploymentId) => import_effect22.Effect.gen(function* () {
|
|
|
2201
2701
|
}
|
|
2202
2702
|
}
|
|
2203
2703
|
if (newStatus === "ACTIVE") {
|
|
2204
|
-
const hostnames = yield* deploymentApi.getHostnames(deploymentId).pipe(
|
|
2704
|
+
const hostnames = yield* deploymentApi.getHostnames(deploymentId).pipe(import_effect25.Effect.catchTag("DeploymentHostnamesFetchError", () => import_effect25.Effect.succeed([])));
|
|
2205
2705
|
const active = hostnames.find((h) => h.active) ?? hostnames.at(0);
|
|
2206
2706
|
if (active) {
|
|
2207
|
-
yield*
|
|
2707
|
+
yield* import_effect25.Console.log(`Deployed to https://${active.hostname}`);
|
|
2208
2708
|
} else {
|
|
2209
|
-
yield*
|
|
2709
|
+
yield* import_effect25.Console.log("Deployment is live.");
|
|
2210
2710
|
}
|
|
2211
|
-
return yield*
|
|
2711
|
+
return yield* import_effect25.Effect.fail("done");
|
|
2212
2712
|
}
|
|
2213
2713
|
if (newStatus === "FAILED") {
|
|
2214
|
-
return yield*
|
|
2714
|
+
return yield* import_effect25.Effect.fail(
|
|
2215
2715
|
new DeploymentFailedError({
|
|
2216
2716
|
message: "The deployment failed. Please check the logs for more information."
|
|
2217
2717
|
})
|
|
2218
2718
|
);
|
|
2219
2719
|
}
|
|
2220
2720
|
}),
|
|
2221
|
-
|
|
2721
|
+
import_effect25.Schedule.addDelay(import_effect25.Schedule.forever, () => import_effect25.Duration.seconds(1))
|
|
2222
2722
|
).pipe(
|
|
2223
|
-
|
|
2224
|
-
if (err === "done") return
|
|
2225
|
-
return
|
|
2723
|
+
import_effect25.Effect.catchAll((err) => {
|
|
2724
|
+
if (err === "done") return import_effect25.Effect.void;
|
|
2725
|
+
return import_effect25.Effect.fail(err);
|
|
2226
2726
|
})
|
|
2227
2727
|
);
|
|
2228
2728
|
});
|
|
2229
2729
|
var printLog = (logEntry) => {
|
|
2230
2730
|
switch (logEntry.type) {
|
|
2231
2731
|
case "ERROR":
|
|
2232
|
-
return
|
|
2732
|
+
return import_effect25.Console.error(logEntry.message);
|
|
2233
2733
|
case "WARN":
|
|
2234
|
-
return
|
|
2734
|
+
return import_effect25.Console.warn(logEntry.message);
|
|
2235
2735
|
default:
|
|
2236
|
-
return
|
|
2736
|
+
return import_effect25.Console.log(logEntry.message);
|
|
2237
2737
|
}
|
|
2238
2738
|
};
|
|
2239
2739
|
|
|
2240
2740
|
// src/commands/platform/index.ts
|
|
2241
|
-
var platformBase = import_cli12.Command.make("platform", {}, () =>
|
|
2741
|
+
var platformBase = import_cli12.Command.make("platform", {}, () => import_effect26.Effect.void);
|
|
2242
2742
|
var platformCommand = platformBase.pipe(import_cli12.Command.withSubcommands([deployCommand]));
|
|
2243
2743
|
|
|
2244
|
-
// src/commands/
|
|
2744
|
+
// src/commands/setup/index.ts
|
|
2245
2745
|
var import_cli13 = require("@effect/cli");
|
|
2246
|
-
var
|
|
2247
|
-
var
|
|
2746
|
+
var import_effect27 = require("effect");
|
|
2747
|
+
var fileArg2 = import_cli13.Args.text({ name: "file" }).pipe(
|
|
2748
|
+
import_cli13.Args.withDescription("Output file to write (default: .env.local)"),
|
|
2749
|
+
import_cli13.Args.optional
|
|
2750
|
+
);
|
|
2751
|
+
var appOption6 = import_cli13.Options.text("app").pipe(
|
|
2752
|
+
import_cli13.Options.withAlias("a"),
|
|
2753
|
+
import_cli13.Options.withDescription("Application ID to set up (skips the interactive picker)"),
|
|
2754
|
+
import_cli13.Options.optional
|
|
2755
|
+
);
|
|
2756
|
+
var orgOption6 = import_cli13.Options.text("org").pipe(
|
|
2757
|
+
import_cli13.Options.withAlias("o"),
|
|
2758
|
+
import_cli13.Options.withDescription("Only list applications belonging to this organization ID when picking"),
|
|
2759
|
+
import_cli13.Options.optional
|
|
2760
|
+
);
|
|
2761
|
+
var environmentOption2 = import_cli13.Options.text("environment").pipe(
|
|
2762
|
+
import_cli13.Options.withAlias("e"),
|
|
2763
|
+
import_cli13.Options.withDescription("Environment slug to resolve overrides for (e.g. preview)"),
|
|
2764
|
+
import_cli13.Options.optional
|
|
2765
|
+
);
|
|
2766
|
+
var yesOption2 = import_cli13.Options.boolean("yes").pipe(
|
|
2767
|
+
import_cli13.Options.withAlias("y"),
|
|
2768
|
+
import_cli13.Options.withDescription("Overwrite an existing file without confirmation")
|
|
2769
|
+
);
|
|
2770
|
+
var rotateOption2 = import_cli13.Options.boolean("rotate").pipe(
|
|
2771
|
+
import_cli13.Options.withDescription("Force a fresh API key, revoking the previous one")
|
|
2772
|
+
);
|
|
2773
|
+
var setupCommand = import_cli13.Command.make(
|
|
2774
|
+
"setup",
|
|
2775
|
+
{
|
|
2776
|
+
file: fileArg2,
|
|
2777
|
+
app: appOption6,
|
|
2778
|
+
org: orgOption6,
|
|
2779
|
+
environment: environmentOption2,
|
|
2780
|
+
yes: yesOption2,
|
|
2781
|
+
rotate: rotateOption2
|
|
2782
|
+
},
|
|
2783
|
+
({ file, app, org, environment, yes, rotate }) => import_effect27.Effect.gen(function* () {
|
|
2784
|
+
const apiClient = yield* ApiClientService;
|
|
2785
|
+
const projectLink = yield* ProjectLinkService;
|
|
2786
|
+
const envFile = yield* EnvFileService;
|
|
2787
|
+
const localCredentials = yield* LocalCredentialsService;
|
|
2788
|
+
const cwd = process.cwd();
|
|
2789
|
+
const existingLink = yield* projectLink.load(cwd);
|
|
2790
|
+
let applicationId;
|
|
2791
|
+
if (import_effect27.Option.isSome(existingLink)) {
|
|
2792
|
+
applicationId = existingLink.value.applicationId;
|
|
2793
|
+
if (import_effect27.Option.isSome(app) || import_effect27.Option.isSome(org)) {
|
|
2794
|
+
yield* import_effect27.Console.log(
|
|
2795
|
+
`Note: this directory is already linked to ${applicationId}; ignoring --app/--org. Run "gigadrive unlink" first to target a different application.`
|
|
2796
|
+
);
|
|
2797
|
+
}
|
|
2798
|
+
} else {
|
|
2799
|
+
const organizationId = import_effect27.Option.getOrUndefined(org);
|
|
2800
|
+
const { items: apps } = yield* apiClient.request((client) => client.applications.list({ organizationId }));
|
|
2801
|
+
if (apps.length === 0) {
|
|
2802
|
+
return yield* import_effect27.Effect.fail(
|
|
2803
|
+
new NoApplicationsFoundError({
|
|
2804
|
+
message: 'No applications found. Create one in the Gigadrive console, then run "gigadrive setup" again.'
|
|
2805
|
+
})
|
|
2806
|
+
);
|
|
2807
|
+
}
|
|
2808
|
+
const explicitAppId = import_effect27.Option.getOrUndefined(app);
|
|
2809
|
+
let chosen;
|
|
2810
|
+
if (explicitAppId !== void 0) {
|
|
2811
|
+
const match = apps.find((a) => a.id === explicitAppId);
|
|
2812
|
+
if (match === void 0) {
|
|
2813
|
+
return yield* import_effect27.Effect.fail(
|
|
2814
|
+
new ApplicationNotFoundError({
|
|
2815
|
+
message: `Application "${explicitAppId}" was not found among your applications.`
|
|
2816
|
+
})
|
|
2817
|
+
);
|
|
2818
|
+
}
|
|
2819
|
+
chosen = match;
|
|
2820
|
+
} else if (apps.length === 1) {
|
|
2821
|
+
chosen = apps[0];
|
|
2822
|
+
} else {
|
|
2823
|
+
chosen = yield* import_cli13.Prompt.run(
|
|
2824
|
+
import_cli13.Prompt.select({
|
|
2825
|
+
message: "Select an application to set up",
|
|
2826
|
+
choices: apps.map((a) => ({ title: `${a.name} (${a.organization.name})`, value: a }))
|
|
2827
|
+
})
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2830
|
+
applicationId = chosen.id;
|
|
2831
|
+
yield* projectLink.save(cwd, { applicationId, organizationId: chosen.organization.id });
|
|
2832
|
+
yield* import_effect27.Console.log(`Linked this directory to application ${applicationId}.`);
|
|
2833
|
+
}
|
|
2834
|
+
const target = import_effect27.Option.getOrElse(file, () => ".env.local");
|
|
2835
|
+
const environmentSlug = import_effect27.Option.getOrUndefined(environment);
|
|
2836
|
+
const { items, omittedSensitive } = yield* apiClient.request(
|
|
2837
|
+
(client) => client.applications.envVars.pull(applicationId, environmentSlug ? { environment: environmentSlug } : void 0)
|
|
2838
|
+
);
|
|
2839
|
+
const existing = yield* envFile.read(target);
|
|
2840
|
+
if (import_effect27.Option.isSome(existing) && !yes) {
|
|
2841
|
+
const overwrite = yield* import_cli13.Prompt.run(
|
|
2842
|
+
import_cli13.Prompt.confirm({ message: `${target} already exists. Overwrite?`, initial: false })
|
|
2843
|
+
);
|
|
2844
|
+
if (!overwrite) {
|
|
2845
|
+
return yield* import_effect27.Console.log("Cancelled.");
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
const credentialEntries2 = yield* localCredentials.provision({
|
|
2849
|
+
applicationId,
|
|
2850
|
+
rotate,
|
|
2851
|
+
existingContent: import_effect27.Option.getOrUndefined(existing)
|
|
2852
|
+
});
|
|
2853
|
+
const entries = [...items.map((v) => ({ key: v.key, value: v.value })), ...credentialEntries2];
|
|
2854
|
+
yield* envFile.write(target, entries);
|
|
2855
|
+
const gitignored = yield* envFile.ensureGitignored(cwd, target);
|
|
2856
|
+
yield* import_effect27.Console.log("\nLocal dev environment ready.");
|
|
2857
|
+
yield* import_effect27.Console.log(` \u2022 Wrote ${items.length} variable(s) and API credentials to ${target}.`);
|
|
2858
|
+
if (omittedSensitive > 0) {
|
|
2859
|
+
yield* import_effect27.Console.log(
|
|
2860
|
+
` \u2022 Skipped ${omittedSensitive} sensitive variable(s) (only production/preview hold secrets).`
|
|
2861
|
+
);
|
|
2862
|
+
}
|
|
2863
|
+
if (gitignored) {
|
|
2864
|
+
yield* import_effect27.Console.log(` \u2022 Added ${target} to .gitignore.`);
|
|
2865
|
+
}
|
|
2866
|
+
yield* import_effect27.Console.log(" \u2022 Your app can now call the Gigadrive API via the SDK (GIGADRIVE_CLIENT_ID/SECRET).");
|
|
2867
|
+
}).pipe(
|
|
2868
|
+
import_effect27.Effect.catchTags({
|
|
2869
|
+
// Ctrl+C during a prompt is a deliberate cancel — exit 0.
|
|
2870
|
+
QuitException: () => import_effect27.Console.log("Cancelled."),
|
|
2871
|
+
NotAuthenticatedError: (err) => import_effect27.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
2872
|
+
import_effect27.Effect.andThen(import_effect27.Effect.fail(err))
|
|
2873
|
+
),
|
|
2874
|
+
ApiRequestError: (err) => import_effect27.Console.error(`Setup failed: ${err.message}`).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2875
|
+
NoApplicationsFoundError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2876
|
+
ApplicationNotFoundError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2877
|
+
ProjectLinkReadError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2878
|
+
ProjectLinkWriteError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2879
|
+
EnvFileReadError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2880
|
+
EnvFileWriteError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2881
|
+
DevCredentialsStoreReadError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err))),
|
|
2882
|
+
DevCredentialsStoreWriteError: (err) => import_effect27.Console.error(err.message).pipe(import_effect27.Effect.andThen(import_effect27.Effect.fail(err)))
|
|
2883
|
+
})
|
|
2884
|
+
)
|
|
2885
|
+
);
|
|
2886
|
+
|
|
2887
|
+
// src/commands/whoami/index.ts
|
|
2888
|
+
var import_cli14 = require("@effect/cli");
|
|
2889
|
+
var import_effect28 = require("effect");
|
|
2890
|
+
var whoamiCommand = import_cli14.Command.make(
|
|
2248
2891
|
"whoami",
|
|
2249
2892
|
{},
|
|
2250
|
-
() =>
|
|
2893
|
+
() => import_effect28.Effect.gen(function* () {
|
|
2251
2894
|
const auth = yield* AuthService;
|
|
2252
2895
|
const info = yield* auth.getUserInfo;
|
|
2253
|
-
yield*
|
|
2896
|
+
yield* import_effect28.Console.log(JSON.stringify(info, null, 2));
|
|
2254
2897
|
}).pipe(
|
|
2255
|
-
|
|
2256
|
-
NotAuthenticatedError: () =>
|
|
2257
|
-
UserInfoFetchError: (err) =>
|
|
2258
|
-
OAuthDiscoveryError: (err) =>
|
|
2898
|
+
import_effect28.Effect.catchTags({
|
|
2899
|
+
NotAuthenticatedError: () => import_effect28.Console.log('You are not logged in. Run "gigadrive login" to authenticate.'),
|
|
2900
|
+
UserInfoFetchError: (err) => import_effect28.Console.error(`Failed to retrieve user info: ${err.message}`),
|
|
2901
|
+
OAuthDiscoveryError: (err) => import_effect28.Console.error(`Failed to retrieve user info: ${err.message}`)
|
|
2259
2902
|
})
|
|
2260
2903
|
)
|
|
2261
2904
|
);
|
|
2262
2905
|
|
|
2263
2906
|
// src/index.ts
|
|
2264
|
-
var gigadrive =
|
|
2265
|
-
|
|
2907
|
+
var gigadrive = import_cli15.Command.make("gigadrive", {}, () => import_effect29.Effect.void).pipe(
|
|
2908
|
+
import_cli15.Command.withSubcommands([
|
|
2266
2909
|
loginCommand,
|
|
2267
2910
|
logoutCommand,
|
|
2268
2911
|
whoamiCommand,
|
|
@@ -2274,27 +2917,31 @@ var gigadrive = import_cli14.Command.make("gigadrive", {}, () => import_effect25
|
|
|
2274
2917
|
aiCommand,
|
|
2275
2918
|
buildCommand,
|
|
2276
2919
|
debugCommand,
|
|
2277
|
-
platformCommand
|
|
2920
|
+
platformCommand,
|
|
2921
|
+
setupCommand
|
|
2278
2922
|
])
|
|
2279
2923
|
);
|
|
2280
|
-
var cli =
|
|
2924
|
+
var cli = import_cli15.Command.run(gigadrive, {
|
|
2281
2925
|
name: "Gigadrive CLI",
|
|
2282
2926
|
version: package_default.version
|
|
2283
2927
|
});
|
|
2284
|
-
var BaseServices =
|
|
2928
|
+
var BaseServices = import_effect29.Layer.mergeAll(
|
|
2285
2929
|
OAuthConfigService.Default,
|
|
2286
2930
|
AuthStorageService.Default,
|
|
2287
2931
|
PackageManagerService.Default,
|
|
2288
2932
|
ArchiveService.Default,
|
|
2289
2933
|
import_network_config2.NetworkConfigLive,
|
|
2290
2934
|
ProjectConfigService.Default,
|
|
2291
|
-
ProjectLinkService.Default
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
var
|
|
2296
|
-
var
|
|
2297
|
-
|
|
2298
|
-
);
|
|
2299
|
-
|
|
2935
|
+
ProjectLinkService.Default,
|
|
2936
|
+
EnvFileService.Default,
|
|
2937
|
+
DevCredentialsStore.Default
|
|
2938
|
+
).pipe(import_effect29.Layer.provideMerge(AuthService.Default));
|
|
2939
|
+
var ApiClientLive = import_effect29.Layer.provide(ApiClientService.Default, BaseServices);
|
|
2940
|
+
var DeploymentApiLive = import_effect29.Layer.provide(DeploymentApiService.Default, BaseServices);
|
|
2941
|
+
var LocalCredentialsLive = import_effect29.Layer.provide(LocalCredentialsService.Default, BaseServices);
|
|
2942
|
+
var ServicesLive = import_effect29.Layer.mergeAll(BaseServices, ApiClientLive, DeploymentApiLive, LocalCredentialsLive);
|
|
2943
|
+
var AppLive = import_effect29.Layer.mergeAll(ServicesLive, import_effect29.Logger.minimumLogLevel(import_effect29.LogLevel.Info)).pipe(
|
|
2944
|
+
import_effect29.Layer.provideMerge(import_platform_node.NodeContext.layer)
|
|
2945
|
+
);
|
|
2946
|
+
import_platform_node.NodeRuntime.runMain(import_effect29.Effect.provide(cli(process.argv), AppLive));
|
|
2300
2947
|
//# sourceMappingURL=index.cjs.map
|