gigadrive 2.1.3 → 2.2.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 +1569 -836
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1759 -1026
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -24,16 +24,68 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
|
-
var
|
|
27
|
+
var import_cli14 = 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_effect25 = require("effect");
|
|
31
31
|
|
|
32
|
-
//
|
|
32
|
+
// package.json
|
|
33
|
+
var package_default = {
|
|
34
|
+
name: "gigadrive",
|
|
35
|
+
version: "2.2.0",
|
|
36
|
+
repository: {
|
|
37
|
+
type: "git",
|
|
38
|
+
url: "https://github.com/Gigadrive/sdk.git",
|
|
39
|
+
directory: "packages/cli"
|
|
40
|
+
},
|
|
41
|
+
license: "Apache-2.0",
|
|
42
|
+
author: "Gigadrive <business@gigadrivegroup.com> (https://gigadrive.de)",
|
|
43
|
+
type: "module",
|
|
44
|
+
module: "src/index.ts",
|
|
45
|
+
bin: {
|
|
46
|
+
gigadrive: "dist/index.mjs",
|
|
47
|
+
gn: "dist/index.mjs"
|
|
48
|
+
},
|
|
49
|
+
files: [
|
|
50
|
+
"dist"
|
|
51
|
+
],
|
|
52
|
+
scripts: {
|
|
53
|
+
build: "tsup",
|
|
54
|
+
clean: "rm -rf dist",
|
|
55
|
+
dev: "pnpm build && node dist/index.mjs",
|
|
56
|
+
typecheck: "tsc --noEmit"
|
|
57
|
+
},
|
|
58
|
+
dependencies: {
|
|
59
|
+
"@effect/cli": "^0.75.0",
|
|
60
|
+
"@effect/platform": "^0.96.0",
|
|
61
|
+
"@effect/platform-node": "^0.106.0",
|
|
62
|
+
"@gigadrive/build-utils": "workspace:*",
|
|
63
|
+
"@gigadrive/commons": "workspace:*",
|
|
64
|
+
"@gigadrive/network-config": "workspace:*",
|
|
65
|
+
"@gigadrive/sdk": "workspace:*",
|
|
66
|
+
archiver: "^7.0.1",
|
|
67
|
+
effect: "^3.19.17",
|
|
68
|
+
ignore: "^7.0.5",
|
|
69
|
+
open: "^10.2.0"
|
|
70
|
+
},
|
|
71
|
+
devDependencies: {
|
|
72
|
+
"@effect/language-service": "^0.84.0",
|
|
73
|
+
"@types/archiver": "^6.0.3",
|
|
74
|
+
esbuild: "^0.28.0",
|
|
75
|
+
typescript: "catalog:"
|
|
76
|
+
},
|
|
77
|
+
engines: {
|
|
78
|
+
node: ">=20.0.0"
|
|
79
|
+
},
|
|
80
|
+
publishConfig: {
|
|
81
|
+
access: "public"
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/commands/ai/index.ts
|
|
33
86
|
var import_cli = require("@effect/cli");
|
|
34
|
-
var
|
|
35
|
-
var
|
|
36
|
-
var import_effect3 = require("effect");
|
|
87
|
+
var import_platform3 = require("@effect/platform");
|
|
88
|
+
var import_effect8 = require("effect");
|
|
37
89
|
|
|
38
90
|
// src/errors.ts
|
|
39
91
|
var import_effect = require("effect");
|
|
@@ -75,11 +127,57 @@ var UserInfoFetchError = class extends import_effect.Schema.TaggedError()("UserI
|
|
|
75
127
|
statusCode: import_effect.Schema.optional(import_effect.Schema.Number)
|
|
76
128
|
}) {
|
|
77
129
|
};
|
|
130
|
+
var ApiRequestError = class extends import_effect.Schema.TaggedError()("ApiRequestError", {
|
|
131
|
+
message: import_effect.Schema.String,
|
|
132
|
+
statusCode: import_effect.Schema.optional(import_effect.Schema.Number),
|
|
133
|
+
code: import_effect.Schema.optional(import_effect.Schema.String)
|
|
134
|
+
}) {
|
|
135
|
+
};
|
|
136
|
+
var InvalidEnvVarFormatError = class extends import_effect.Schema.TaggedError()(
|
|
137
|
+
"InvalidEnvVarFormatError",
|
|
138
|
+
{
|
|
139
|
+
message: import_effect.Schema.String
|
|
140
|
+
}
|
|
141
|
+
) {
|
|
142
|
+
};
|
|
143
|
+
var EnvVarNotFoundError = class extends import_effect.Schema.TaggedError()("EnvVarNotFoundError", {
|
|
144
|
+
message: import_effect.Schema.String
|
|
145
|
+
}) {
|
|
146
|
+
};
|
|
147
|
+
var NoApplicationsFoundError = class extends import_effect.Schema.TaggedError()(
|
|
148
|
+
"NoApplicationsFoundError",
|
|
149
|
+
{
|
|
150
|
+
message: import_effect.Schema.String
|
|
151
|
+
}
|
|
152
|
+
) {
|
|
153
|
+
};
|
|
154
|
+
var ApplicationNotFoundError = class extends import_effect.Schema.TaggedError()(
|
|
155
|
+
"ApplicationNotFoundError",
|
|
156
|
+
{
|
|
157
|
+
message: import_effect.Schema.String
|
|
158
|
+
}
|
|
159
|
+
) {
|
|
160
|
+
};
|
|
78
161
|
var ConfigNotFoundError = class extends import_effect.Schema.TaggedError()("ConfigNotFoundError", {
|
|
79
162
|
message: import_effect.Schema.String,
|
|
80
163
|
directory: import_effect.Schema.String
|
|
81
164
|
}) {
|
|
82
165
|
};
|
|
166
|
+
var ProjectNotLinkedError = class extends import_effect.Schema.TaggedError()("ProjectNotLinkedError", {
|
|
167
|
+
message: import_effect.Schema.String,
|
|
168
|
+
directory: import_effect.Schema.String
|
|
169
|
+
}) {
|
|
170
|
+
};
|
|
171
|
+
var ProjectLinkReadError = class extends import_effect.Schema.TaggedError()("ProjectLinkReadError", {
|
|
172
|
+
message: import_effect.Schema.String,
|
|
173
|
+
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
174
|
+
}) {
|
|
175
|
+
};
|
|
176
|
+
var ProjectLinkWriteError = class extends import_effect.Schema.TaggedError()("ProjectLinkWriteError", {
|
|
177
|
+
message: import_effect.Schema.String,
|
|
178
|
+
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
179
|
+
}) {
|
|
180
|
+
};
|
|
83
181
|
var ConfigParseError = class extends import_effect.Schema.TaggedError()("ConfigParseError", {
|
|
84
182
|
message: import_effect.Schema.String,
|
|
85
183
|
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
@@ -160,6 +258,13 @@ var DeploymentLogsFetchError = class extends import_effect.Schema.TaggedError()(
|
|
|
160
258
|
}
|
|
161
259
|
) {
|
|
162
260
|
};
|
|
261
|
+
var DeploymentHostnamesFetchError = class extends import_effect.Schema.TaggedError()(
|
|
262
|
+
"DeploymentHostnamesFetchError",
|
|
263
|
+
{
|
|
264
|
+
message: import_effect.Schema.String
|
|
265
|
+
}
|
|
266
|
+
) {
|
|
267
|
+
};
|
|
163
268
|
var ArchiveCreateError = class extends import_effect.Schema.TaggedError()("ArchiveCreateError", {
|
|
164
269
|
message: import_effect.Schema.String,
|
|
165
270
|
cause: import_effect.Schema.optional(import_effect.Schema.String)
|
|
@@ -174,431 +279,150 @@ var DeploymentFailedError = class extends import_effect.Schema.TaggedError()("De
|
|
|
174
279
|
}) {
|
|
175
280
|
};
|
|
176
281
|
|
|
177
|
-
// src/services/
|
|
282
|
+
// src/services/api-client.ts
|
|
283
|
+
var import_sdk = require("@gigadrive/sdk");
|
|
284
|
+
var import_effect6 = require("effect");
|
|
285
|
+
|
|
286
|
+
// src/services/auth.ts
|
|
287
|
+
var import_effect5 = require("effect");
|
|
288
|
+
var crypto = __toESM(require("crypto"), 1);
|
|
289
|
+
var http = __toESM(require("http"), 1);
|
|
290
|
+
var import_open = __toESM(require("open"), 1);
|
|
291
|
+
|
|
292
|
+
// src/services/auth-storage.ts
|
|
178
293
|
var import_platform = require("@effect/platform");
|
|
179
|
-
var
|
|
294
|
+
var import_effect3 = require("effect");
|
|
295
|
+
var os = __toESM(require("os"), 1);
|
|
296
|
+
|
|
297
|
+
// src/domain.ts
|
|
180
298
|
var import_effect2 = require("effect");
|
|
181
|
-
var
|
|
299
|
+
var DeploymentId = import_effect2.Schema.String.pipe(import_effect2.Schema.brand("@Gigadrive/DeploymentId"));
|
|
300
|
+
var ApplicationId = import_effect2.Schema.String.pipe(import_effect2.Schema.brand("@Gigadrive/ApplicationId"));
|
|
301
|
+
var UploadId = import_effect2.Schema.String.pipe(import_effect2.Schema.brand("@Gigadrive/UploadId"));
|
|
302
|
+
var PackageManager = import_effect2.Schema.Literal("npm", "yarn", "pnpm", "bun");
|
|
303
|
+
var OAuthTokens = import_effect2.Schema.Struct({
|
|
304
|
+
access_token: import_effect2.Schema.String,
|
|
305
|
+
refresh_token: import_effect2.Schema.optional(import_effect2.Schema.String),
|
|
306
|
+
expires_in: import_effect2.Schema.optional(import_effect2.Schema.Number),
|
|
307
|
+
token_type: import_effect2.Schema.optional(import_effect2.Schema.String)
|
|
308
|
+
});
|
|
309
|
+
var OAuthClientConfig = import_effect2.Schema.Struct({
|
|
310
|
+
clientId: import_effect2.Schema.String,
|
|
311
|
+
issuer: import_effect2.Schema.String,
|
|
312
|
+
authorizeUrl: import_effect2.Schema.String,
|
|
313
|
+
tokenUrl: import_effect2.Schema.String,
|
|
314
|
+
scope: import_effect2.Schema.String,
|
|
315
|
+
userinfoUrl: import_effect2.Schema.String
|
|
316
|
+
});
|
|
317
|
+
var StoredAuthData = import_effect2.Schema.Struct({
|
|
318
|
+
refreshToken: import_effect2.Schema.String,
|
|
319
|
+
accessToken: import_effect2.Schema.optional(import_effect2.Schema.String),
|
|
320
|
+
tokenExpirationTime: import_effect2.Schema.optional(import_effect2.Schema.Number)
|
|
321
|
+
});
|
|
322
|
+
var ProjectLink = import_effect2.Schema.Struct({
|
|
323
|
+
applicationId: import_effect2.Schema.String,
|
|
324
|
+
organizationId: import_effect2.Schema.optional(import_effect2.Schema.String)
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// src/services/auth-storage.ts
|
|
328
|
+
var AuthStorageService = class extends import_effect3.Effect.Service()("AuthStorageService", {
|
|
182
329
|
accessors: true,
|
|
183
|
-
effect:
|
|
330
|
+
effect: import_effect3.Effect.gen(function* () {
|
|
184
331
|
const fs = yield* import_platform.FileSystem.FileSystem;
|
|
185
332
|
const pathService = yield* import_platform.Path.Path;
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
333
|
+
const homeDir = os.homedir();
|
|
334
|
+
const authDir = pathService.join(homeDir, ".gigadrive");
|
|
335
|
+
const authFile = pathService.join(authDir, "auth.json");
|
|
336
|
+
const ensureDirectory = import_effect3.Effect.gen(function* () {
|
|
337
|
+
yield* fs.makeDirectory(authDir, { recursive: true }).pipe(
|
|
338
|
+
import_effect3.Effect.mapError(
|
|
339
|
+
(error) => new AuthStorageWriteError({
|
|
340
|
+
message: "Failed to create auth directory",
|
|
341
|
+
cause: String(error)
|
|
342
|
+
})
|
|
192
343
|
)
|
|
193
344
|
);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
new
|
|
197
|
-
message: "
|
|
198
|
-
|
|
345
|
+
yield* fs.chmod(authDir, 448).pipe(
|
|
346
|
+
import_effect3.Effect.mapError(
|
|
347
|
+
(error) => new AuthStorageWriteError({
|
|
348
|
+
message: "Failed to set auth directory permissions",
|
|
349
|
+
cause: String(error)
|
|
199
350
|
})
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
const lockChecks = [
|
|
203
|
-
{ file: "yarn.lock", pm: "yarn" },
|
|
204
|
-
{ file: "pnpm-lock.yaml", pm: "pnpm" },
|
|
205
|
-
{ file: "bun.lockb", pm: "bun" },
|
|
206
|
-
{ file: "package-lock.json", pm: "npm" }
|
|
207
|
-
];
|
|
208
|
-
for (const { file, pm: pm2 } of lockChecks) {
|
|
209
|
-
const lockExists = yield* fs.exists(pathService.join(cwd, file)).pipe(import_effect2.Effect.catchAll(() => import_effect2.Effect.succeed(false)));
|
|
210
|
-
if (lockExists) {
|
|
211
|
-
yield* import_effect2.Effect.log("Package manager detected from lock file", { packageManager: pm2, lockFile: file });
|
|
212
|
-
return pm2;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
const bunAvailable = yield* import_effect2.Effect.tryPromise({
|
|
216
|
-
try: () => (0, import_build_utils.exec)({ command: "bun --version", cwd }),
|
|
217
|
-
catch: () => new ExecError({ message: "bun not found", command: "bun --version" })
|
|
218
|
-
}).pipe(
|
|
219
|
-
import_effect2.Effect.as(true),
|
|
220
|
-
import_effect2.Effect.catchTag("ExecError", () => import_effect2.Effect.succeed(false))
|
|
351
|
+
)
|
|
221
352
|
);
|
|
222
|
-
const pm = bunAvailable ? "bun" : "npm";
|
|
223
|
-
yield* import_effect2.Effect.log("Package manager detected via fallback", { packageManager: pm });
|
|
224
|
-
return pm;
|
|
225
353
|
});
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
return { detect, installCommand, buildCommand: buildCommand2 };
|
|
239
|
-
})
|
|
240
|
-
}) {
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// src/commands/build/index.ts
|
|
244
|
-
var buildCommand = import_cli.Command.make(
|
|
245
|
-
"build",
|
|
246
|
-
{},
|
|
247
|
-
() => import_effect3.Effect.gen(function* () {
|
|
248
|
-
const pmService = yield* PackageManagerService;
|
|
249
|
-
const fs = yield* import_platform2.FileSystem.FileSystem;
|
|
250
|
-
const pathService = yield* import_platform2.Path.Path;
|
|
251
|
-
const cwd = process.cwd();
|
|
252
|
-
yield* import_effect3.Effect.log("Starting build", { cwd });
|
|
253
|
-
const packageJsonPath = pathService.join(cwd, "package.json");
|
|
254
|
-
const packageJsonExists = yield* fs.exists(packageJsonPath).pipe(
|
|
255
|
-
import_effect3.Effect.mapError(
|
|
256
|
-
() => new PackageJsonNotFoundError({ message: "Failed to check for package.json", directory: cwd })
|
|
257
|
-
)
|
|
258
|
-
);
|
|
259
|
-
if (!packageJsonExists) {
|
|
260
|
-
return yield* import_effect3.Effect.fail(new PackageJsonNotFoundError({ message: "No package.json found", directory: cwd }));
|
|
261
|
-
}
|
|
262
|
-
const packageJsonContent = yield* fs.readFileString(packageJsonPath, "utf-8").pipe(
|
|
263
|
-
import_effect3.Effect.mapError(() => new PackageJsonNotFoundError({ message: "Failed to read package.json", directory: cwd }))
|
|
264
|
-
);
|
|
265
|
-
const packageJson = yield* import_effect3.Effect.try({
|
|
266
|
-
try: () => JSON.parse(packageJsonContent),
|
|
267
|
-
catch: (error) => new PackageJsonParseError({
|
|
268
|
-
message: "Failed to parse package.json",
|
|
269
|
-
directory: cwd,
|
|
270
|
-
cause: error instanceof Error ? error.message : String(error)
|
|
271
|
-
})
|
|
354
|
+
const load = import_effect3.Effect.gen(function* () {
|
|
355
|
+
const exists = yield* fs.exists(authFile).pipe(import_effect3.Effect.mapError(() => new AuthStorageReadError({ message: "Failed to check auth file existence" })));
|
|
356
|
+
if (!exists) return import_effect3.Option.none();
|
|
357
|
+
const data = yield* fs.readFileString(authFile, "utf8").pipe(import_effect3.Effect.mapError(() => new AuthStorageReadError({ message: "Failed to read auth file" })));
|
|
358
|
+
const json = yield* import_effect3.Effect.try({
|
|
359
|
+
try: () => JSON.parse(data),
|
|
360
|
+
catch: () => new AuthStorageReadError({ message: "Auth file contains invalid JSON" })
|
|
361
|
+
});
|
|
362
|
+
const authData = yield* import_effect3.Schema.decodeUnknown(StoredAuthData)(json).pipe(
|
|
363
|
+
import_effect3.Effect.mapError(() => new AuthStorageReadError({ message: "Auth file has invalid schema" }))
|
|
364
|
+
);
|
|
365
|
+
return import_effect3.Option.some(authData);
|
|
272
366
|
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const installCmd = pmService.installCommand(pm);
|
|
285
|
-
yield* import_effect3.Console.log(`Running: ${installCmd}`);
|
|
286
|
-
yield* import_effect3.Effect.tryPromise({
|
|
287
|
-
try: () => (0, import_build_utils2.exec)({
|
|
288
|
-
command: installCmd,
|
|
289
|
-
cwd,
|
|
290
|
-
env: buildEnv,
|
|
291
|
-
onOutput: (chunk) => {
|
|
292
|
-
import_effect3.Console.log(chunk).pipe(import_effect3.Effect.runSync);
|
|
293
|
-
}
|
|
294
|
-
}),
|
|
295
|
-
catch: (error) => new ExecError({
|
|
296
|
-
message: "Install failed",
|
|
297
|
-
command: installCmd,
|
|
298
|
-
cause: error instanceof Error ? error.message : String(error)
|
|
299
|
-
})
|
|
367
|
+
const save = import_effect3.Effect.fn("AuthStorageService.save")(function* (authData) {
|
|
368
|
+
yield* ensureDirectory;
|
|
369
|
+
yield* fs.writeFileString(authFile, JSON.stringify(authData, null, 2), { mode: 384 }).pipe(
|
|
370
|
+
import_effect3.Effect.mapError(
|
|
371
|
+
(error) => new AuthStorageWriteError({
|
|
372
|
+
message: "Failed to write auth file",
|
|
373
|
+
cause: String(error)
|
|
374
|
+
})
|
|
375
|
+
)
|
|
376
|
+
);
|
|
377
|
+
yield* import_effect3.Effect.log("Auth data saved to local storage");
|
|
300
378
|
});
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
379
|
+
const remove = import_effect3.Effect.gen(function* () {
|
|
380
|
+
yield* fs.remove(authFile).pipe(
|
|
381
|
+
import_effect3.Effect.mapError((error) => {
|
|
382
|
+
const cause = error instanceof Error ? error : error.error;
|
|
383
|
+
const code = cause && typeof cause === "object" && "code" in cause ? cause.code : "";
|
|
384
|
+
return { isNotFound: code === "ENOENT" || String(error).includes("ENOENT"), original: error };
|
|
385
|
+
}),
|
|
386
|
+
import_effect3.Effect.catchAll(
|
|
387
|
+
(mapped) => mapped.isNotFound ? import_effect3.Effect.void : import_effect3.Effect.fail(
|
|
388
|
+
new AuthStorageWriteError({
|
|
389
|
+
message: "Failed to remove auth file",
|
|
390
|
+
cause: String(mapped.original)
|
|
391
|
+
})
|
|
392
|
+
)
|
|
393
|
+
)
|
|
394
|
+
);
|
|
395
|
+
yield* import_effect3.Effect.log("Auth data removed from local storage");
|
|
317
396
|
});
|
|
318
|
-
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
PackageJsonParseError: (err) => import_effect3.Console.error(err.message).pipe(import_effect3.Effect.andThen(import_effect3.Effect.fail(err))),
|
|
323
|
-
BuildScriptNotFoundError: (err) => import_effect3.Console.error(err.message).pipe(import_effect3.Effect.andThen(import_effect3.Effect.fail(err))),
|
|
324
|
-
PackageManagerNotFoundError: (err) => import_effect3.Console.error(err.message).pipe(import_effect3.Effect.andThen(import_effect3.Effect.fail(err))),
|
|
325
|
-
ExecError: (err) => import_effect3.Console.error(`${err.message}: ${err.cause ?? err.command}`).pipe(import_effect3.Effect.andThen(import_effect3.Effect.fail(err)))
|
|
326
|
-
})
|
|
327
|
-
)
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
// src/commands/debug/index.ts
|
|
331
|
-
var import_cli3 = require("@effect/cli");
|
|
332
|
-
var import_effect6 = require("effect");
|
|
333
|
-
|
|
334
|
-
// src/commands/debug/config/index.ts
|
|
335
|
-
var import_cli2 = require("@effect/cli");
|
|
336
|
-
var import_effect5 = require("effect");
|
|
397
|
+
return { load, save, remove };
|
|
398
|
+
})
|
|
399
|
+
}) {
|
|
400
|
+
};
|
|
337
401
|
|
|
338
|
-
// src/services/
|
|
339
|
-
var import_network_config = require("@gigadrive/network-config");
|
|
402
|
+
// src/services/oauth-config.ts
|
|
340
403
|
var import_effect4 = require("effect");
|
|
341
|
-
var
|
|
342
|
-
import_effect4.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
);
|
|
351
|
-
var
|
|
404
|
+
var OAuthEnvConfig = import_effect4.Config.all({
|
|
405
|
+
issuerUrl: import_effect4.Config.string("GIGADRIVE_NETWORK_OAUTH_ISSUER_URL").pipe(import_effect4.Config.withDefault("https://idp.gigadrive.de")),
|
|
406
|
+
clientId: import_effect4.Config.string("GIGADRIVE_NETWORK_OAUTH_CLIENT_ID").pipe(import_effect4.Config.withDefault("todo_add_client_id"))
|
|
407
|
+
});
|
|
408
|
+
var OpenIdDiscoveryDocument = import_effect4.Schema.Struct({
|
|
409
|
+
issuer: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
410
|
+
authorization_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
411
|
+
token_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
412
|
+
userinfo_endpoint: import_effect4.Schema.optional(import_effect4.Schema.String)
|
|
413
|
+
});
|
|
414
|
+
var DEFAULT_SCOPE = "offline_access openid profile email";
|
|
415
|
+
var OAuthConfigService = class extends import_effect4.Effect.Service()("OAuthConfigService", {
|
|
352
416
|
accessors: true,
|
|
353
|
-
dependencies: [import_network_config.NetworkConfigLive],
|
|
354
417
|
effect: import_effect4.Effect.gen(function* () {
|
|
355
|
-
const rawReader = yield* import_network_config.RawConfigReader;
|
|
356
|
-
const resolve = import_effect4.Effect.fn("ProjectConfigService.resolve")(function* (cwd) {
|
|
357
|
-
yield* import_effect4.Effect.annotateCurrentSpan("cwd", cwd);
|
|
358
|
-
yield* import_effect4.Effect.log("Resolving project config", { cwd });
|
|
359
|
-
const configPath = yield* rawReader.findConfig(cwd);
|
|
360
|
-
const detection = yield* (0, import_network_config.detectFramework)(cwd).pipe(
|
|
361
|
-
import_effect4.Effect.catchTag("FrameworkNotDetectedError", () => import_effect4.Effect.succeed(null)),
|
|
362
|
-
import_effect4.Effect.catchTag(
|
|
363
|
-
"ManifestReadError",
|
|
364
|
-
(e) => import_effect4.Effect.fail(new ConfigParseError({ message: `Framework detection failed: ${e.message}`, cause: e.filePath }))
|
|
365
|
-
),
|
|
366
|
-
import_effect4.Effect.catchTag(
|
|
367
|
-
"ManifestParseError",
|
|
368
|
-
(e) => import_effect4.Effect.fail(new ConfigParseError({ message: `Framework detection failed: ${e.message}`, cause: e.filePath }))
|
|
369
|
-
)
|
|
370
|
-
);
|
|
371
|
-
if (detection) {
|
|
372
|
-
yield* import_effect4.Effect.log("Framework auto-detected", {
|
|
373
|
-
framework: detection.framework.name,
|
|
374
|
-
slug: detection.framework.slug
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
let config;
|
|
378
|
-
let resolvedConfigPath = null;
|
|
379
|
-
let framework;
|
|
380
|
-
if (configPath && detection) {
|
|
381
|
-
yield* import_effect4.Effect.log("Config file found, merging with framework defaults", { configPath });
|
|
382
|
-
resolvedConfigPath = configPath;
|
|
383
|
-
const userConfig = yield* wrapParseErrors((0, import_network_config.parseConfigRaw)(configPath, cwd));
|
|
384
|
-
const merged = yield* (0, import_network_config.mergeWithFrameworkDefaults)(userConfig, detection.config);
|
|
385
|
-
config = yield* wrapParseErrors((0, import_network_config.postProcessConfig)(merged, cwd));
|
|
386
|
-
framework = { name: detection.framework.name, slug: detection.framework.slug };
|
|
387
|
-
} else if (configPath) {
|
|
388
|
-
yield* import_effect4.Effect.log("Config file found", { configPath });
|
|
389
|
-
resolvedConfigPath = configPath;
|
|
390
|
-
config = yield* wrapParseErrors((0, import_network_config.parseConfig)(configPath, cwd));
|
|
391
|
-
} else if (detection) {
|
|
392
|
-
config = yield* wrapParseErrors((0, import_network_config.postProcessConfig)(detection.config, cwd));
|
|
393
|
-
framework = { name: detection.framework.name, slug: detection.framework.slug };
|
|
394
|
-
} else {
|
|
395
|
-
return yield* import_effect4.Effect.fail(
|
|
396
|
-
new ConfigNotFoundError({
|
|
397
|
-
message: "No config file found and no framework detected.",
|
|
398
|
-
directory: cwd
|
|
399
|
-
})
|
|
400
|
-
);
|
|
401
|
-
}
|
|
402
|
-
for (const warning of config.warnings) {
|
|
403
|
-
yield* import_effect4.Effect.logWarning(warning);
|
|
404
|
-
}
|
|
405
|
-
if (config.errors.length > 0) {
|
|
406
|
-
return yield* import_effect4.Effect.fail(
|
|
407
|
-
new ConfigValidationError({
|
|
408
|
-
message: "Config file has validation errors",
|
|
409
|
-
errors: config.errors
|
|
410
|
-
})
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
return { config, configPath: resolvedConfigPath, framework };
|
|
414
|
-
});
|
|
415
|
-
return { resolve };
|
|
416
|
-
})
|
|
417
|
-
}) {
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
// src/commands/debug/config/index.ts
|
|
421
|
-
var debugConfigCommand = import_cli2.Command.make(
|
|
422
|
-
"config",
|
|
423
|
-
{},
|
|
424
|
-
() => import_effect5.Effect.gen(function* () {
|
|
425
|
-
const projectConfig = yield* ProjectConfigService;
|
|
426
|
-
const cwd = process.cwd();
|
|
427
|
-
const { config, configPath } = yield* projectConfig.resolve(cwd);
|
|
428
|
-
yield* import_effect5.Console.log(`Config file found at: ${configPath}`);
|
|
429
|
-
yield* import_effect5.Console.log(JSON.stringify(config, null, 2));
|
|
430
|
-
}).pipe(
|
|
431
|
-
import_effect5.Effect.catchTags({
|
|
432
|
-
ConfigNotFoundError: (err) => import_effect5.Console.error(err.message),
|
|
433
|
-
ConfigParseError: (err) => import_effect5.Console.error(`Config parse error: ${err.message}`),
|
|
434
|
-
ConfigValidationError: (err) => import_effect5.Effect.gen(function* () {
|
|
435
|
-
for (const e of err.errors) {
|
|
436
|
-
yield* import_effect5.Console.error(e);
|
|
437
|
-
}
|
|
438
|
-
yield* import_effect5.Console.error(err.message);
|
|
439
|
-
})
|
|
440
|
-
})
|
|
441
|
-
)
|
|
442
|
-
);
|
|
443
|
-
|
|
444
|
-
// src/commands/debug/index.ts
|
|
445
|
-
var debugBase = import_cli3.Command.make("debug", {}, () => import_effect6.Effect.void);
|
|
446
|
-
var debugCommand = debugBase.pipe(import_cli3.Command.withSubcommands([debugConfigCommand]));
|
|
447
|
-
|
|
448
|
-
// src/commands/login/index.ts
|
|
449
|
-
var import_cli4 = require("@effect/cli");
|
|
450
|
-
var import_effect11 = require("effect");
|
|
451
|
-
|
|
452
|
-
// src/services/auth.ts
|
|
453
|
-
var import_effect10 = require("effect");
|
|
454
|
-
var crypto = __toESM(require("crypto"), 1);
|
|
455
|
-
var http = __toESM(require("http"), 1);
|
|
456
|
-
var import_open = __toESM(require("open"), 1);
|
|
457
|
-
|
|
458
|
-
// src/services/auth-storage.ts
|
|
459
|
-
var import_platform3 = require("@effect/platform");
|
|
460
|
-
var import_effect8 = require("effect");
|
|
461
|
-
var os = __toESM(require("os"), 1);
|
|
462
|
-
|
|
463
|
-
// src/domain.ts
|
|
464
|
-
var import_effect7 = require("effect");
|
|
465
|
-
var DeploymentId = import_effect7.Schema.String.pipe(import_effect7.Schema.brand("@Gigadrive/DeploymentId"));
|
|
466
|
-
var ApplicationId = import_effect7.Schema.String.pipe(import_effect7.Schema.brand("@Gigadrive/ApplicationId"));
|
|
467
|
-
var UploadId = import_effect7.Schema.String.pipe(import_effect7.Schema.brand("@Gigadrive/UploadId"));
|
|
468
|
-
var DeploymentStatus = import_effect7.Schema.Literal("PENDING", "BUILDING", "PROVISIONING", "FAILED", "ACTIVE", "SUSPENDED");
|
|
469
|
-
var DeploymentLogType = import_effect7.Schema.Literal("INFO", "ERROR", "WARN");
|
|
470
|
-
var DeploymentLog = import_effect7.Schema.Struct({
|
|
471
|
-
id: import_effect7.Schema.String,
|
|
472
|
-
message: import_effect7.Schema.String,
|
|
473
|
-
type: DeploymentLogType,
|
|
474
|
-
createdAt: import_effect7.Schema.String
|
|
475
|
-
});
|
|
476
|
-
var DeploymentLogPage = import_effect7.Schema.Struct({
|
|
477
|
-
totalItems: import_effect7.Schema.Number,
|
|
478
|
-
limit: import_effect7.Schema.Number,
|
|
479
|
-
offset: import_effect7.Schema.Number,
|
|
480
|
-
items: import_effect7.Schema.Array(DeploymentLog)
|
|
481
|
-
});
|
|
482
|
-
var PackageManager = import_effect7.Schema.Literal("npm", "yarn", "pnpm", "bun");
|
|
483
|
-
var OAuthTokens = import_effect7.Schema.Struct({
|
|
484
|
-
access_token: import_effect7.Schema.String,
|
|
485
|
-
refresh_token: import_effect7.Schema.optional(import_effect7.Schema.String),
|
|
486
|
-
expires_in: import_effect7.Schema.optional(import_effect7.Schema.Number),
|
|
487
|
-
token_type: import_effect7.Schema.optional(import_effect7.Schema.String)
|
|
488
|
-
});
|
|
489
|
-
var OAuthClientConfig = import_effect7.Schema.Struct({
|
|
490
|
-
clientId: import_effect7.Schema.String,
|
|
491
|
-
issuer: import_effect7.Schema.String,
|
|
492
|
-
authorizeUrl: import_effect7.Schema.String,
|
|
493
|
-
tokenUrl: import_effect7.Schema.String,
|
|
494
|
-
scope: import_effect7.Schema.String,
|
|
495
|
-
userinfoUrl: import_effect7.Schema.String
|
|
496
|
-
});
|
|
497
|
-
var StoredAuthData = import_effect7.Schema.Struct({
|
|
498
|
-
refreshToken: import_effect7.Schema.String,
|
|
499
|
-
accessToken: import_effect7.Schema.optional(import_effect7.Schema.String),
|
|
500
|
-
tokenExpirationTime: import_effect7.Schema.optional(import_effect7.Schema.Number)
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// src/services/auth-storage.ts
|
|
504
|
-
var AuthStorageService = class extends import_effect8.Effect.Service()("AuthStorageService", {
|
|
505
|
-
accessors: true,
|
|
506
|
-
effect: import_effect8.Effect.gen(function* () {
|
|
507
|
-
const fs = yield* import_platform3.FileSystem.FileSystem;
|
|
508
|
-
const pathService = yield* import_platform3.Path.Path;
|
|
509
|
-
const homeDir = os.homedir();
|
|
510
|
-
const authDir = pathService.join(homeDir, ".gigadrive");
|
|
511
|
-
const authFile = pathService.join(authDir, "auth.json");
|
|
512
|
-
const ensureDirectory = import_effect8.Effect.gen(function* () {
|
|
513
|
-
yield* fs.makeDirectory(authDir, { recursive: true }).pipe(
|
|
514
|
-
import_effect8.Effect.mapError(
|
|
515
|
-
(error) => new AuthStorageWriteError({
|
|
516
|
-
message: "Failed to create auth directory",
|
|
517
|
-
cause: String(error)
|
|
518
|
-
})
|
|
519
|
-
)
|
|
520
|
-
);
|
|
521
|
-
yield* fs.chmod(authDir, 448).pipe(
|
|
522
|
-
import_effect8.Effect.mapError(
|
|
523
|
-
(error) => new AuthStorageWriteError({
|
|
524
|
-
message: "Failed to set auth directory permissions",
|
|
525
|
-
cause: String(error)
|
|
526
|
-
})
|
|
527
|
-
)
|
|
528
|
-
);
|
|
529
|
-
});
|
|
530
|
-
const load = import_effect8.Effect.gen(function* () {
|
|
531
|
-
const exists = yield* fs.exists(authFile).pipe(import_effect8.Effect.mapError(() => new AuthStorageReadError({ message: "Failed to check auth file existence" })));
|
|
532
|
-
if (!exists) return import_effect8.Option.none();
|
|
533
|
-
const data = yield* fs.readFileString(authFile, "utf8").pipe(import_effect8.Effect.mapError(() => new AuthStorageReadError({ message: "Failed to read auth file" })));
|
|
534
|
-
const json = yield* import_effect8.Effect.try({
|
|
535
|
-
try: () => JSON.parse(data),
|
|
536
|
-
catch: () => new AuthStorageReadError({ message: "Auth file contains invalid JSON" })
|
|
537
|
-
});
|
|
538
|
-
const authData = yield* import_effect8.Schema.decodeUnknown(StoredAuthData)(json).pipe(
|
|
539
|
-
import_effect8.Effect.mapError(() => new AuthStorageReadError({ message: "Auth file has invalid schema" }))
|
|
540
|
-
);
|
|
541
|
-
return import_effect8.Option.some(authData);
|
|
542
|
-
});
|
|
543
|
-
const save = import_effect8.Effect.fn("AuthStorageService.save")(function* (authData) {
|
|
544
|
-
yield* ensureDirectory;
|
|
545
|
-
yield* fs.writeFileString(authFile, JSON.stringify(authData, null, 2), { mode: 384 }).pipe(
|
|
546
|
-
import_effect8.Effect.mapError(
|
|
547
|
-
(error) => new AuthStorageWriteError({
|
|
548
|
-
message: "Failed to write auth file",
|
|
549
|
-
cause: String(error)
|
|
550
|
-
})
|
|
551
|
-
)
|
|
552
|
-
);
|
|
553
|
-
yield* import_effect8.Effect.log("Auth data saved to local storage");
|
|
554
|
-
});
|
|
555
|
-
const remove = import_effect8.Effect.gen(function* () {
|
|
556
|
-
yield* fs.remove(authFile).pipe(
|
|
557
|
-
import_effect8.Effect.mapError((error) => {
|
|
558
|
-
const cause = error instanceof Error ? error : error.error;
|
|
559
|
-
const code = cause && typeof cause === "object" && "code" in cause ? cause.code : "";
|
|
560
|
-
return { isNotFound: code === "ENOENT" || String(error).includes("ENOENT"), original: error };
|
|
561
|
-
}),
|
|
562
|
-
import_effect8.Effect.catchAll(
|
|
563
|
-
(mapped) => mapped.isNotFound ? import_effect8.Effect.void : import_effect8.Effect.fail(
|
|
564
|
-
new AuthStorageWriteError({
|
|
565
|
-
message: "Failed to remove auth file",
|
|
566
|
-
cause: String(mapped.original)
|
|
567
|
-
})
|
|
568
|
-
)
|
|
569
|
-
)
|
|
570
|
-
);
|
|
571
|
-
yield* import_effect8.Effect.log("Auth data removed from local storage");
|
|
572
|
-
});
|
|
573
|
-
return { load, save, remove };
|
|
574
|
-
})
|
|
575
|
-
}) {
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
// src/services/oauth-config.ts
|
|
579
|
-
var import_effect9 = require("effect");
|
|
580
|
-
var OAuthEnvConfig = import_effect9.Config.all({
|
|
581
|
-
issuerUrl: import_effect9.Config.string("GIGADRIVE_NETWORK_OAUTH_ISSUER_URL").pipe(import_effect9.Config.withDefault("https://idp.gigadrive.de")),
|
|
582
|
-
clientId: import_effect9.Config.string("GIGADRIVE_NETWORK_OAUTH_CLIENT_ID").pipe(import_effect9.Config.withDefault("todo_add_client_id"))
|
|
583
|
-
});
|
|
584
|
-
var OpenIdDiscoveryDocument = import_effect9.Schema.Struct({
|
|
585
|
-
issuer: import_effect9.Schema.optional(import_effect9.Schema.String),
|
|
586
|
-
authorization_endpoint: import_effect9.Schema.optional(import_effect9.Schema.String),
|
|
587
|
-
token_endpoint: import_effect9.Schema.optional(import_effect9.Schema.String),
|
|
588
|
-
userinfo_endpoint: import_effect9.Schema.optional(import_effect9.Schema.String)
|
|
589
|
-
});
|
|
590
|
-
var DEFAULT_SCOPE = "offline_access openid profile email";
|
|
591
|
-
var OAuthConfigService = class extends import_effect9.Effect.Service()("OAuthConfigService", {
|
|
592
|
-
accessors: true,
|
|
593
|
-
effect: import_effect9.Effect.gen(function* () {
|
|
594
418
|
const envConfig = yield* OAuthEnvConfig;
|
|
595
419
|
let cached = null;
|
|
596
|
-
const getConfig =
|
|
420
|
+
const getConfig = import_effect4.Effect.gen(function* () {
|
|
597
421
|
if (cached) return cached;
|
|
598
422
|
const issuerBase = envConfig.issuerUrl.replace(/\/$/, "");
|
|
599
423
|
const discoveryUrl = `${issuerBase}/.well-known/openid-configuration`;
|
|
600
|
-
yield*
|
|
601
|
-
const response = yield*
|
|
424
|
+
yield* import_effect4.Effect.log("Fetching OIDC discovery document", { discoveryUrl });
|
|
425
|
+
const response = yield* import_effect4.Effect.tryPromise({
|
|
602
426
|
try: (signal) => fetch(discoveryUrl, { signal }),
|
|
603
427
|
catch: (error) => new OAuthDiscoveryError({
|
|
604
428
|
message: "Failed to fetch OIDC discovery document",
|
|
@@ -606,27 +430,27 @@ var OAuthConfigService = class extends import_effect9.Effect.Service()("OAuthCon
|
|
|
606
430
|
})
|
|
607
431
|
});
|
|
608
432
|
if (!response.ok) {
|
|
609
|
-
return yield*
|
|
433
|
+
return yield* import_effect4.Effect.fail(
|
|
610
434
|
new OAuthDiscoveryError({
|
|
611
435
|
message: `OIDC discovery returned ${response.status} ${response.statusText}`
|
|
612
436
|
})
|
|
613
437
|
);
|
|
614
438
|
}
|
|
615
|
-
const json = yield*
|
|
439
|
+
const json = yield* import_effect4.Effect.tryPromise({
|
|
616
440
|
try: () => response.json(),
|
|
617
441
|
catch: () => new OAuthDiscoveryError({
|
|
618
442
|
message: "Failed to parse OIDC discovery JSON"
|
|
619
443
|
})
|
|
620
444
|
});
|
|
621
|
-
const decoded = yield*
|
|
622
|
-
|
|
445
|
+
const decoded = yield* import_effect4.Schema.decodeUnknown(OpenIdDiscoveryDocument)(json).pipe(
|
|
446
|
+
import_effect4.Effect.mapError(
|
|
623
447
|
() => new OAuthDiscoveryError({
|
|
624
448
|
message: "Invalid OIDC discovery document schema"
|
|
625
449
|
})
|
|
626
450
|
)
|
|
627
451
|
);
|
|
628
452
|
if (!decoded.authorization_endpoint || !decoded.token_endpoint || !decoded.userinfo_endpoint) {
|
|
629
|
-
return yield*
|
|
453
|
+
return yield* import_effect4.Effect.fail(
|
|
630
454
|
new OAuthDiscoveryError({
|
|
631
455
|
message: "OIDC discovery returned incomplete endpoints"
|
|
632
456
|
})
|
|
@@ -641,7 +465,7 @@ var OAuthConfigService = class extends import_effect9.Effect.Service()("OAuthCon
|
|
|
641
465
|
userinfoUrl: decoded.userinfo_endpoint
|
|
642
466
|
};
|
|
643
467
|
cached = config;
|
|
644
|
-
yield*
|
|
468
|
+
yield* import_effect4.Effect.log("OIDC discovery completed", { issuer: config.issuer });
|
|
645
469
|
return config;
|
|
646
470
|
});
|
|
647
471
|
return { getConfig };
|
|
@@ -658,22 +482,22 @@ var generatePKCE = () => {
|
|
|
658
482
|
const codeChallenge = base64URLEncode(challengeBytes);
|
|
659
483
|
return { codeVerifier, codeChallenge };
|
|
660
484
|
};
|
|
661
|
-
var AuthService = class extends
|
|
485
|
+
var AuthService = class extends import_effect5.Effect.Service()("AuthService", {
|
|
662
486
|
accessors: true,
|
|
663
487
|
dependencies: [OAuthConfigService.Default, AuthStorageService.Default],
|
|
664
|
-
effect:
|
|
488
|
+
effect: import_effect5.Effect.gen(function* () {
|
|
665
489
|
const oauthConfig = yield* OAuthConfigService;
|
|
666
490
|
const storage = yield* AuthStorageService;
|
|
667
491
|
let accessToken = null;
|
|
668
492
|
let tokenExpirationTime = 0;
|
|
669
|
-
const logout =
|
|
493
|
+
const logout = import_effect5.Effect.gen(function* () {
|
|
670
494
|
accessToken = null;
|
|
671
495
|
tokenExpirationTime = 0;
|
|
672
496
|
yield* storage.remove;
|
|
673
|
-
yield*
|
|
497
|
+
yield* import_effect5.Effect.log("Logged out");
|
|
674
498
|
});
|
|
675
|
-
const exchangeCodeForTokens = (config, authCode, redirectUri, codeVerifier) =>
|
|
676
|
-
const response = yield*
|
|
499
|
+
const exchangeCodeForTokens = (config, authCode, redirectUri, codeVerifier) => import_effect5.Effect.gen(function* () {
|
|
500
|
+
const response = yield* import_effect5.Effect.tryPromise({
|
|
677
501
|
try: () => fetch(config.tokenUrl, {
|
|
678
502
|
method: "POST",
|
|
679
503
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
@@ -690,31 +514,31 @@ var AuthService = class extends import_effect10.Effect.Service()("AuthService",
|
|
|
690
514
|
})
|
|
691
515
|
});
|
|
692
516
|
if (!response.ok) {
|
|
693
|
-
const body = yield*
|
|
517
|
+
const body = yield* import_effect5.Effect.tryPromise({
|
|
694
518
|
try: () => response.text(),
|
|
695
519
|
catch: () => new TokenExchangeError({ message: "Failed to read token exchange error response" })
|
|
696
520
|
});
|
|
697
|
-
return yield*
|
|
521
|
+
return yield* import_effect5.Effect.fail(
|
|
698
522
|
new TokenExchangeError({
|
|
699
523
|
message: `Token exchange failed: ${response.status} ${response.statusText} - ${body}`,
|
|
700
524
|
statusCode: response.status
|
|
701
525
|
})
|
|
702
526
|
);
|
|
703
527
|
}
|
|
704
|
-
const tokens = yield*
|
|
528
|
+
const tokens = yield* import_effect5.Effect.tryPromise({
|
|
705
529
|
try: () => response.json(),
|
|
706
530
|
catch: () => new TokenExchangeError({ message: "Failed to parse token exchange response" })
|
|
707
531
|
});
|
|
708
532
|
return tokens;
|
|
709
533
|
});
|
|
710
|
-
const startCallbackServer = (config, codeChallenge, state) =>
|
|
534
|
+
const startCallbackServer = (config, codeChallenge, state) => import_effect5.Effect.async((resume) => {
|
|
711
535
|
const server = http.createServer();
|
|
712
536
|
const redirectPath = "/callback";
|
|
713
537
|
server.listen(0, "127.0.0.1", () => {
|
|
714
538
|
const address = server.address();
|
|
715
539
|
if (!address || typeof address !== "object") {
|
|
716
540
|
server.close(() => {
|
|
717
|
-
resume(
|
|
541
|
+
resume(import_effect5.Effect.fail(new LoginFlowError({ message: "Failed to determine callback server address" })));
|
|
718
542
|
});
|
|
719
543
|
return;
|
|
720
544
|
}
|
|
@@ -728,10 +552,10 @@ var AuthService = class extends import_effect10.Effect.Service()("AuthService",
|
|
|
728
552
|
authUrl.searchParams.append("code_challenge", codeChallenge);
|
|
729
553
|
authUrl.searchParams.append("code_challenge_method", "S256");
|
|
730
554
|
authUrl.searchParams.append("state", state);
|
|
731
|
-
|
|
555
|
+
import_effect5.Console.log(`Please open this URL in your browser to log in:
|
|
732
556
|
${authUrl.toString()}
|
|
733
|
-
`).pipe(
|
|
734
|
-
|
|
557
|
+
`).pipe(import_effect5.Effect.runSync);
|
|
558
|
+
import_effect5.Console.log("Waiting for login callback...").pipe(import_effect5.Effect.runSync);
|
|
735
559
|
void (0, import_open.default)(authUrl.toString());
|
|
736
560
|
server.on("request", (req, res) => {
|
|
737
561
|
const reqUrl = new URL(req.url || "", redirectUri);
|
|
@@ -747,7 +571,7 @@ ${authUrl.toString()}
|
|
|
747
571
|
const safeOauthError = escapeHtml(oauthError);
|
|
748
572
|
res.end(`<h1>Login Failed!</h1><p>Error: ${safeOauthError}</p><p>You can close this tab.</p>`);
|
|
749
573
|
server.close();
|
|
750
|
-
resume(
|
|
574
|
+
resume(import_effect5.Effect.fail(new LoginFlowError({ message: `OAuth error: ${oauthError}` })));
|
|
751
575
|
return;
|
|
752
576
|
}
|
|
753
577
|
if (receivedState !== state) {
|
|
@@ -755,26 +579,26 @@ ${authUrl.toString()}
|
|
|
755
579
|
"<h1>Login Failed!</h1><p>State mismatch. Possible CSRF attack.</p><p>You can close this tab.</p>"
|
|
756
580
|
);
|
|
757
581
|
server.close();
|
|
758
|
-
resume(
|
|
582
|
+
resume(import_effect5.Effect.fail(new LoginFlowError({ message: "State mismatch" })));
|
|
759
583
|
return;
|
|
760
584
|
}
|
|
761
585
|
if (authCode) {
|
|
762
586
|
res.end("<h1>Login Successful!</h1><p>You can close this tab.</p>");
|
|
763
587
|
server.close();
|
|
764
|
-
resume(
|
|
588
|
+
resume(import_effect5.Effect.succeed({ authCode, redirectUri }));
|
|
765
589
|
} else {
|
|
766
590
|
res.end("<h1>Login Failed!</h1><p>No authorization code received.</p><p>You can close this tab.</p>");
|
|
767
591
|
server.close();
|
|
768
|
-
resume(
|
|
592
|
+
resume(import_effect5.Effect.fail(new LoginFlowError({ message: "No authorization code received" })));
|
|
769
593
|
}
|
|
770
594
|
});
|
|
771
595
|
server.on("error", (err) => {
|
|
772
596
|
server.close();
|
|
773
|
-
resume(
|
|
597
|
+
resume(import_effect5.Effect.fail(new LoginFlowError({ message: `Local server error: ${err.message}` })));
|
|
774
598
|
});
|
|
775
599
|
});
|
|
776
600
|
});
|
|
777
|
-
const login =
|
|
601
|
+
const login = import_effect5.Effect.gen(function* () {
|
|
778
602
|
yield* logout;
|
|
779
603
|
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
780
604
|
const state = crypto.randomBytes(16).toString("hex");
|
|
@@ -782,7 +606,7 @@ ${authUrl.toString()}
|
|
|
782
606
|
const { authCode, redirectUri } = yield* startCallbackServer(config, codeChallenge, state);
|
|
783
607
|
const tokens = yield* exchangeCodeForTokens(config, authCode, redirectUri, codeVerifier);
|
|
784
608
|
if (!tokens.refresh_token) {
|
|
785
|
-
return yield*
|
|
609
|
+
return yield* import_effect5.Effect.fail(
|
|
786
610
|
new TokenExchangeError({ message: "No refresh token received from identity provider" })
|
|
787
611
|
);
|
|
788
612
|
}
|
|
@@ -793,21 +617,21 @@ ${authUrl.toString()}
|
|
|
793
617
|
accessToken,
|
|
794
618
|
tokenExpirationTime
|
|
795
619
|
});
|
|
796
|
-
yield*
|
|
620
|
+
yield* import_effect5.Effect.log("Login successful");
|
|
797
621
|
return true;
|
|
798
622
|
});
|
|
799
|
-
const refreshAccessToken =
|
|
623
|
+
const refreshAccessToken = import_effect5.Effect.gen(function* () {
|
|
800
624
|
const stored = yield* storage.load.pipe(
|
|
801
|
-
|
|
625
|
+
import_effect5.Effect.catchTag("AuthStorageReadError", (err) => import_effect5.Effect.fail(new TokenRefreshError({ message: err.message })))
|
|
802
626
|
);
|
|
803
627
|
const config = yield* oauthConfig.getConfig.pipe(
|
|
804
|
-
|
|
628
|
+
import_effect5.Effect.catchTag("OAuthDiscoveryError", (err) => import_effect5.Effect.fail(new TokenRefreshError({ message: err.message })))
|
|
805
629
|
);
|
|
806
|
-
const authData = yield*
|
|
807
|
-
onNone: () =>
|
|
808
|
-
onSome: (data) => data.refreshToken ?
|
|
630
|
+
const authData = yield* import_effect5.Option.match(stored, {
|
|
631
|
+
onNone: () => import_effect5.Effect.fail(new TokenRefreshError({ message: "No refresh token available. Please log in." })),
|
|
632
|
+
onSome: (data) => data.refreshToken ? import_effect5.Effect.succeed(data) : import_effect5.Effect.fail(new TokenRefreshError({ message: "No refresh token available. Please log in." }))
|
|
809
633
|
});
|
|
810
|
-
const response = yield*
|
|
634
|
+
const response = yield* import_effect5.Effect.tryPromise({
|
|
811
635
|
try: () => fetch(config.tokenUrl, {
|
|
812
636
|
method: "POST",
|
|
813
637
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
@@ -823,26 +647,26 @@ ${authUrl.toString()}
|
|
|
823
647
|
});
|
|
824
648
|
if (!response.ok) {
|
|
825
649
|
if (response.status === 400) {
|
|
826
|
-
yield* logout.pipe(
|
|
827
|
-
return yield*
|
|
650
|
+
yield* logout.pipe(import_effect5.Effect.catchAll(() => import_effect5.Effect.void));
|
|
651
|
+
return yield* import_effect5.Effect.fail(
|
|
828
652
|
new TokenRefreshError({
|
|
829
653
|
message: "Refresh token is invalid or expired. Please log in again.",
|
|
830
654
|
statusCode: response.status
|
|
831
655
|
})
|
|
832
656
|
);
|
|
833
657
|
}
|
|
834
|
-
const body = yield*
|
|
658
|
+
const body = yield* import_effect5.Effect.tryPromise({
|
|
835
659
|
try: () => response.text(),
|
|
836
660
|
catch: () => new TokenRefreshError({ message: "Failed to read refresh error response" })
|
|
837
661
|
});
|
|
838
|
-
return yield*
|
|
662
|
+
return yield* import_effect5.Effect.fail(
|
|
839
663
|
new TokenRefreshError({
|
|
840
664
|
message: `Token refresh failed: ${response.status} ${response.statusText} - ${body}`,
|
|
841
665
|
statusCode: response.status
|
|
842
666
|
})
|
|
843
667
|
);
|
|
844
668
|
}
|
|
845
|
-
const tokens = yield*
|
|
669
|
+
const tokens = yield* import_effect5.Effect.tryPromise({
|
|
846
670
|
try: () => response.json(),
|
|
847
671
|
catch: () => new TokenRefreshError({ message: "Failed to parse token refresh response" })
|
|
848
672
|
});
|
|
@@ -853,18 +677,18 @@ ${authUrl.toString()}
|
|
|
853
677
|
refreshToken: newRefreshToken,
|
|
854
678
|
accessToken,
|
|
855
679
|
tokenExpirationTime
|
|
856
|
-
}).pipe(
|
|
857
|
-
yield*
|
|
680
|
+
}).pipe(import_effect5.Effect.catchAll(() => import_effect5.Effect.void));
|
|
681
|
+
yield* import_effect5.Effect.log("Access token refreshed successfully");
|
|
858
682
|
return true;
|
|
859
683
|
});
|
|
860
|
-
const getAccessToken =
|
|
684
|
+
const getAccessToken = import_effect5.Effect.gen(function* () {
|
|
861
685
|
if (accessToken && Date.now() < tokenExpirationTime) {
|
|
862
686
|
return accessToken;
|
|
863
687
|
}
|
|
864
688
|
const stored = yield* storage.load.pipe(
|
|
865
|
-
|
|
689
|
+
import_effect5.Effect.catchAll(() => import_effect5.Effect.succeed(import_effect5.Option.none()))
|
|
866
690
|
);
|
|
867
|
-
|
|
691
|
+
import_effect5.Option.match(stored, {
|
|
868
692
|
onNone: () => {
|
|
869
693
|
},
|
|
870
694
|
onSome: (data) => {
|
|
@@ -877,124 +701,1145 @@ ${authUrl.toString()}
|
|
|
877
701
|
if (accessToken && Date.now() < tokenExpirationTime) {
|
|
878
702
|
return accessToken;
|
|
879
703
|
}
|
|
880
|
-
yield*
|
|
704
|
+
yield* import_effect5.Effect.log("Access token expired or not available. Attempting to refresh...");
|
|
881
705
|
yield* refreshAccessToken.pipe(
|
|
882
|
-
|
|
706
|
+
import_effect5.Effect.catchTag("TokenRefreshError", (err) => import_effect5.Effect.fail(new NotAuthenticatedError({ message: err.message })))
|
|
883
707
|
);
|
|
884
708
|
if (!accessToken) {
|
|
885
|
-
return yield*
|
|
709
|
+
return yield* import_effect5.Effect.fail(
|
|
886
710
|
new NotAuthenticatedError({ message: "No valid access token available. Please log in first." })
|
|
887
711
|
);
|
|
888
712
|
}
|
|
889
|
-
return accessToken;
|
|
890
|
-
});
|
|
891
|
-
const getUserInfo =
|
|
892
|
-
const config = yield* oauthConfig.getConfig;
|
|
893
|
-
const token = yield* getAccessToken;
|
|
894
|
-
const fetchUserInfo = (t) =>
|
|
895
|
-
try: () => fetch(config.userinfoUrl, {
|
|
896
|
-
headers: {
|
|
897
|
-
Authorization: `Bearer ${t}`,
|
|
898
|
-
Accept: "application/json"
|
|
899
|
-
}
|
|
900
|
-
}),
|
|
901
|
-
catch: (error) => new UserInfoFetchError({
|
|
902
|
-
message: `Failed to fetch user info: ${error instanceof Error ? error.message : String(error)}`
|
|
903
|
-
})
|
|
904
|
-
});
|
|
905
|
-
let response = yield* fetchUserInfo(token);
|
|
906
|
-
if (response.status === 401 || response.status === 403) {
|
|
907
|
-
yield* refreshAccessToken.pipe(
|
|
908
|
-
|
|
909
|
-
);
|
|
910
|
-
if (!accessToken) {
|
|
911
|
-
return yield*
|
|
912
|
-
}
|
|
913
|
-
response = yield* fetchUserInfo(accessToken);
|
|
713
|
+
return accessToken;
|
|
714
|
+
});
|
|
715
|
+
const getUserInfo = import_effect5.Effect.gen(function* () {
|
|
716
|
+
const config = yield* oauthConfig.getConfig;
|
|
717
|
+
const token = yield* getAccessToken;
|
|
718
|
+
const fetchUserInfo = (t) => import_effect5.Effect.tryPromise({
|
|
719
|
+
try: () => fetch(config.userinfoUrl, {
|
|
720
|
+
headers: {
|
|
721
|
+
Authorization: `Bearer ${t}`,
|
|
722
|
+
Accept: "application/json"
|
|
723
|
+
}
|
|
724
|
+
}),
|
|
725
|
+
catch: (error) => new UserInfoFetchError({
|
|
726
|
+
message: `Failed to fetch user info: ${error instanceof Error ? error.message : String(error)}`
|
|
727
|
+
})
|
|
728
|
+
});
|
|
729
|
+
let response = yield* fetchUserInfo(token);
|
|
730
|
+
if (response.status === 401 || response.status === 403) {
|
|
731
|
+
yield* refreshAccessToken.pipe(
|
|
732
|
+
import_effect5.Effect.catchTag("TokenRefreshError", (err) => import_effect5.Effect.fail(new UserInfoFetchError({ message: err.message })))
|
|
733
|
+
);
|
|
734
|
+
if (!accessToken) {
|
|
735
|
+
return yield* import_effect5.Effect.fail(new UserInfoFetchError({ message: "Token refresh failed" }));
|
|
736
|
+
}
|
|
737
|
+
response = yield* fetchUserInfo(accessToken);
|
|
738
|
+
}
|
|
739
|
+
if (!response.ok) {
|
|
740
|
+
const body = yield* import_effect5.Effect.tryPromise({
|
|
741
|
+
try: () => response.text(),
|
|
742
|
+
catch: () => new UserInfoFetchError({ message: "Failed to read user info error response" })
|
|
743
|
+
});
|
|
744
|
+
return yield* import_effect5.Effect.fail(
|
|
745
|
+
new UserInfoFetchError({
|
|
746
|
+
message: `Failed to fetch user info: ${response.status} ${response.statusText}${body ? ` - ${body}` : ""}`,
|
|
747
|
+
statusCode: response.status
|
|
748
|
+
})
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
const data = yield* import_effect5.Effect.tryPromise({
|
|
752
|
+
try: () => response.json(),
|
|
753
|
+
catch: () => new UserInfoFetchError({ message: "Failed to parse user info response" })
|
|
754
|
+
});
|
|
755
|
+
return data;
|
|
756
|
+
});
|
|
757
|
+
const inferUserName = (info) => {
|
|
758
|
+
const isNonEmptyString = (value) => typeof value === "string" && value.trim() !== "";
|
|
759
|
+
const name = info.name;
|
|
760
|
+
const givenName = info.given_name;
|
|
761
|
+
const familyName = info.family_name;
|
|
762
|
+
const preferredUsername = info.preferred_username;
|
|
763
|
+
const email = info.email;
|
|
764
|
+
return isNonEmptyString(name) && name || (isNonEmptyString(givenName) && isNonEmptyString(familyName) ? `${givenName} ${familyName}` : void 0) || isNonEmptyString(preferredUsername) && preferredUsername || isNonEmptyString(email) && email || "your account";
|
|
765
|
+
};
|
|
766
|
+
return { login, logout, getAccessToken, getUserInfo, refreshAccessToken, inferUserName };
|
|
767
|
+
})
|
|
768
|
+
}) {
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
// src/services/api-client.ts
|
|
772
|
+
var ApiBaseUrl = import_effect6.Config.string("GIGADRIVE_API_BASE_URL").pipe(import_effect6.Config.withDefault("https://api.gigadrive.network"));
|
|
773
|
+
var toApiRequestError = (error) => {
|
|
774
|
+
if (error instanceof import_sdk.ApiError) {
|
|
775
|
+
return new ApiRequestError({ message: error.message, statusCode: error.status, code: error.code });
|
|
776
|
+
}
|
|
777
|
+
return new ApiRequestError({ message: error instanceof Error ? error.message : String(error) });
|
|
778
|
+
};
|
|
779
|
+
var ApiClientService = class extends import_effect6.Effect.Service()("ApiClientService", {
|
|
780
|
+
accessors: true,
|
|
781
|
+
effect: import_effect6.Effect.gen(function* () {
|
|
782
|
+
const baseUrl = yield* ApiBaseUrl;
|
|
783
|
+
const authService = yield* AuthService;
|
|
784
|
+
const getClient = import_effect6.Effect.gen(function* () {
|
|
785
|
+
const token = yield* authService.getAccessToken;
|
|
786
|
+
return new import_sdk.GigadriveClient({ bearerToken: token, baseUrl });
|
|
787
|
+
});
|
|
788
|
+
const request = (f) => import_effect6.Effect.gen(function* () {
|
|
789
|
+
const client = yield* getClient;
|
|
790
|
+
return yield* import_effect6.Effect.tryPromise({
|
|
791
|
+
try: () => f(client),
|
|
792
|
+
catch: toApiRequestError
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
return { getClient, request };
|
|
796
|
+
})
|
|
797
|
+
}) {
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
// src/services/project-link.ts
|
|
801
|
+
var import_platform2 = require("@effect/platform");
|
|
802
|
+
var import_effect7 = require("effect");
|
|
803
|
+
var LINK_DIR = ".gigadrive";
|
|
804
|
+
var LINK_FILE = "project.json";
|
|
805
|
+
var ProjectLinkService = class extends import_effect7.Effect.Service()("ProjectLinkService", {
|
|
806
|
+
accessors: true,
|
|
807
|
+
effect: import_effect7.Effect.gen(function* () {
|
|
808
|
+
const fs = yield* import_platform2.FileSystem.FileSystem;
|
|
809
|
+
const pathService = yield* import_platform2.Path.Path;
|
|
810
|
+
const linkDir = (projectFolder) => pathService.join(projectFolder, LINK_DIR);
|
|
811
|
+
const linkFile = (projectFolder) => pathService.join(projectFolder, LINK_DIR, LINK_FILE);
|
|
812
|
+
const load = import_effect7.Effect.fn("ProjectLinkService.load")(function* (projectFolder) {
|
|
813
|
+
const file = linkFile(projectFolder);
|
|
814
|
+
const exists = yield* fs.exists(file).pipe(import_effect7.Effect.mapError(() => new ProjectLinkReadError({ message: "Failed to check project link existence" })));
|
|
815
|
+
if (!exists) return import_effect7.Option.none();
|
|
816
|
+
const data = yield* fs.readFileString(file, "utf8").pipe(import_effect7.Effect.mapError(() => new ProjectLinkReadError({ message: "Failed to read project link file" })));
|
|
817
|
+
const json = yield* import_effect7.Effect.try({
|
|
818
|
+
try: () => JSON.parse(data),
|
|
819
|
+
catch: () => new ProjectLinkReadError({ message: `${LINK_DIR}/${LINK_FILE} contains invalid JSON` })
|
|
820
|
+
});
|
|
821
|
+
const link = yield* import_effect7.Schema.decodeUnknown(ProjectLink)(json).pipe(
|
|
822
|
+
import_effect7.Effect.mapError(() => new ProjectLinkReadError({ message: `${LINK_DIR}/${LINK_FILE} has an invalid schema` }))
|
|
823
|
+
);
|
|
824
|
+
return import_effect7.Option.some(link);
|
|
825
|
+
});
|
|
826
|
+
const resolve = import_effect7.Effect.fn("ProjectLinkService.resolve")(function* (projectFolder) {
|
|
827
|
+
const link = yield* load(projectFolder);
|
|
828
|
+
return yield* import_effect7.Option.match(link, {
|
|
829
|
+
onNone: () => import_effect7.Effect.fail(
|
|
830
|
+
new ProjectNotLinkedError({
|
|
831
|
+
message: 'This directory is not linked to an application. Run "gigadrive link" first.',
|
|
832
|
+
directory: projectFolder
|
|
833
|
+
})
|
|
834
|
+
),
|
|
835
|
+
onSome: (value) => import_effect7.Effect.succeed(value)
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
const save = import_effect7.Effect.fn("ProjectLinkService.save")(function* (projectFolder, link) {
|
|
839
|
+
yield* fs.makeDirectory(linkDir(projectFolder), { recursive: true }).pipe(
|
|
840
|
+
import_effect7.Effect.mapError(
|
|
841
|
+
(error) => new ProjectLinkWriteError({ message: "Failed to create .gigadrive directory", cause: String(error) })
|
|
842
|
+
)
|
|
843
|
+
);
|
|
844
|
+
yield* fs.writeFileString(linkFile(projectFolder), `${JSON.stringify(link, null, 2)}
|
|
845
|
+
`).pipe(
|
|
846
|
+
import_effect7.Effect.mapError(
|
|
847
|
+
(error) => new ProjectLinkWriteError({ message: "Failed to write project link file", cause: String(error) })
|
|
848
|
+
)
|
|
849
|
+
);
|
|
850
|
+
yield* import_effect7.Effect.log("Project link saved", { applicationId: link.applicationId });
|
|
851
|
+
});
|
|
852
|
+
const remove = import_effect7.Effect.fn("ProjectLinkService.remove")(function* (projectFolder) {
|
|
853
|
+
yield* fs.remove(linkFile(projectFolder), { force: true }).pipe(
|
|
854
|
+
import_effect7.Effect.mapError(
|
|
855
|
+
(error) => new ProjectLinkWriteError({ message: "Failed to remove project link file", cause: String(error) })
|
|
856
|
+
)
|
|
857
|
+
);
|
|
858
|
+
});
|
|
859
|
+
return { load, resolve, save, remove };
|
|
860
|
+
})
|
|
861
|
+
}) {
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
// src/commands/ai/index.ts
|
|
865
|
+
var orgOption = import_cli.Options.text("org").pipe(
|
|
866
|
+
import_cli.Options.withAlias("o"),
|
|
867
|
+
import_cli.Options.withDescription("Organization ID (defaults to the linked organization)"),
|
|
868
|
+
import_cli.Options.optional
|
|
869
|
+
);
|
|
870
|
+
var appOption = import_cli.Options.text("app").pipe(
|
|
871
|
+
import_cli.Options.withAlias("a"),
|
|
872
|
+
import_cli.Options.withDescription("Restrict to this application ID"),
|
|
873
|
+
import_cli.Options.optional
|
|
874
|
+
);
|
|
875
|
+
var fromOption = import_cli.Options.text("from").pipe(
|
|
876
|
+
import_cli.Options.withDescription("Include usage at or after this ISO 8601 timestamp"),
|
|
877
|
+
import_cli.Options.optional
|
|
878
|
+
);
|
|
879
|
+
var toOption = import_cli.Options.text("to").pipe(
|
|
880
|
+
import_cli.Options.withDescription("Include usage before or at this ISO 8601 timestamp"),
|
|
881
|
+
import_cli.Options.optional
|
|
882
|
+
);
|
|
883
|
+
var fileOption = import_cli.Options.text("file").pipe(
|
|
884
|
+
import_cli.Options.withAlias("f"),
|
|
885
|
+
import_cli.Options.withDescription('Path to a JSON file, or "-" for stdin (default: stdin)'),
|
|
886
|
+
import_cli.Options.optional
|
|
887
|
+
);
|
|
888
|
+
var resolveOrgId = (org) => import_effect8.Effect.gen(function* () {
|
|
889
|
+
if (import_effect8.Option.isSome(org)) return org.value;
|
|
890
|
+
const projectLink = yield* ProjectLinkService;
|
|
891
|
+
const link = yield* projectLink.resolve(process.cwd());
|
|
892
|
+
if (link.organizationId === void 0) {
|
|
893
|
+
return yield* import_effect8.Effect.fail(
|
|
894
|
+
new ProjectNotLinkedError({
|
|
895
|
+
message: 'No organization is linked. Pass --org <id> or re-run "gigadrive link".',
|
|
896
|
+
directory: process.cwd()
|
|
897
|
+
})
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
return link.organizationId;
|
|
901
|
+
});
|
|
902
|
+
var readStdin = import_effect8.Effect.async((resume) => {
|
|
903
|
+
let data = "";
|
|
904
|
+
const stdin = process.stdin;
|
|
905
|
+
stdin.setEncoding("utf8");
|
|
906
|
+
const onData = (chunk) => {
|
|
907
|
+
data += chunk;
|
|
908
|
+
};
|
|
909
|
+
const cleanup = () => {
|
|
910
|
+
stdin.off("data", onData);
|
|
911
|
+
stdin.off("end", onEnd);
|
|
912
|
+
stdin.off("error", onError);
|
|
913
|
+
};
|
|
914
|
+
const onEnd = () => {
|
|
915
|
+
cleanup();
|
|
916
|
+
resume(import_effect8.Effect.succeed(data));
|
|
917
|
+
};
|
|
918
|
+
const onError = (err) => {
|
|
919
|
+
cleanup();
|
|
920
|
+
resume(import_effect8.Effect.fail(new ApiRequestError({ message: `Failed to read stdin: ${err.message}` })));
|
|
921
|
+
};
|
|
922
|
+
stdin.on("data", onData);
|
|
923
|
+
stdin.on("end", onEnd);
|
|
924
|
+
stdin.on("error", onError);
|
|
925
|
+
stdin.resume();
|
|
926
|
+
});
|
|
927
|
+
var readJsonInput = (file) => import_effect8.Effect.gen(function* () {
|
|
928
|
+
const path = import_effect8.Option.getOrUndefined(file);
|
|
929
|
+
let raw;
|
|
930
|
+
if (path === void 0 || path === "-") {
|
|
931
|
+
raw = yield* readStdin;
|
|
932
|
+
} else {
|
|
933
|
+
const fs = yield* import_platform3.FileSystem.FileSystem;
|
|
934
|
+
raw = yield* fs.readFileString(path, "utf8").pipe(import_effect8.Effect.mapError((e) => new ApiRequestError({ message: `Failed to read ${path}: ${String(e)}` })));
|
|
935
|
+
}
|
|
936
|
+
return yield* import_effect8.Effect.try({
|
|
937
|
+
try: () => JSON.parse(raw),
|
|
938
|
+
catch: () => new ApiRequestError({ message: "Input is not valid JSON." })
|
|
939
|
+
});
|
|
940
|
+
});
|
|
941
|
+
var governanceErrorHandlers = {
|
|
942
|
+
NotAuthenticatedError: (err) => import_effect8.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
943
|
+
import_effect8.Effect.andThen(import_effect8.Effect.fail(err))
|
|
944
|
+
),
|
|
945
|
+
ApiRequestError: (err) => import_effect8.Console.error(err.message).pipe(import_effect8.Effect.andThen(import_effect8.Effect.fail(err))),
|
|
946
|
+
ProjectNotLinkedError: (err) => import_effect8.Console.error(err.message).pipe(import_effect8.Effect.andThen(import_effect8.Effect.fail(err))),
|
|
947
|
+
ProjectLinkReadError: (err) => import_effect8.Console.error(err.message).pipe(import_effect8.Effect.andThen(import_effect8.Effect.fail(err)))
|
|
948
|
+
};
|
|
949
|
+
var usageSummaryCommand = import_cli.Command.make(
|
|
950
|
+
"summary",
|
|
951
|
+
{ org: orgOption, app: appOption, from: fromOption, to: toOption },
|
|
952
|
+
({ org, app, from, to }) => import_effect8.Effect.gen(function* () {
|
|
953
|
+
const apiClient = yield* ApiClientService;
|
|
954
|
+
const orgId = yield* resolveOrgId(org);
|
|
955
|
+
const summary = yield* apiClient.request(
|
|
956
|
+
(client) => client.organizations.aiGateway.usage.summary(orgId, {
|
|
957
|
+
applicationId: import_effect8.Option.getOrUndefined(app),
|
|
958
|
+
from: import_effect8.Option.getOrUndefined(from),
|
|
959
|
+
to: import_effect8.Option.getOrUndefined(to)
|
|
960
|
+
})
|
|
961
|
+
);
|
|
962
|
+
yield* import_effect8.Console.log(JSON.stringify(summary, null, 2));
|
|
963
|
+
}).pipe(import_effect8.Effect.catchTags(governanceErrorHandlers))
|
|
964
|
+
);
|
|
965
|
+
var usageRequestsCommand = import_cli.Command.make(
|
|
966
|
+
"requests",
|
|
967
|
+
{ org: orgOption, app: appOption, from: fromOption, to: toOption },
|
|
968
|
+
({ org, app, from, to }) => import_effect8.Effect.gen(function* () {
|
|
969
|
+
const apiClient = yield* ApiClientService;
|
|
970
|
+
const orgId = yield* resolveOrgId(org);
|
|
971
|
+
const { items, total } = yield* apiClient.request(
|
|
972
|
+
(client) => client.organizations.aiGateway.usage.requests(orgId, {
|
|
973
|
+
applicationId: import_effect8.Option.getOrUndefined(app),
|
|
974
|
+
from: import_effect8.Option.getOrUndefined(from),
|
|
975
|
+
to: import_effect8.Option.getOrUndefined(to)
|
|
976
|
+
})
|
|
977
|
+
);
|
|
978
|
+
if (items.length === 0) {
|
|
979
|
+
yield* import_effect8.Console.log("No AI Gateway requests found.");
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
for (const e of items) {
|
|
983
|
+
yield* import_effect8.Console.log(
|
|
984
|
+
`${e.createdAt} ${e.modelRequested} ${e.status} ${e.totalTokens} tok ${e.billableCostMicros}\xB5$`
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
yield* import_effect8.Console.log(`
|
|
988
|
+
${total} request(s).`);
|
|
989
|
+
}).pipe(import_effect8.Effect.catchTags(governanceErrorHandlers))
|
|
990
|
+
);
|
|
991
|
+
var outOption = import_cli.Options.text("out").pipe(
|
|
992
|
+
import_cli.Options.withDescription("Write the CSV to this file instead of stdout"),
|
|
993
|
+
import_cli.Options.optional
|
|
994
|
+
);
|
|
995
|
+
var usageExportCommand = import_cli.Command.make(
|
|
996
|
+
"export",
|
|
997
|
+
{ org: orgOption, app: appOption, from: fromOption, to: toOption, out: outOption },
|
|
998
|
+
({ org, app, from, to, out }) => import_effect8.Effect.gen(function* () {
|
|
999
|
+
const apiClient = yield* ApiClientService;
|
|
1000
|
+
const orgId = yield* resolveOrgId(org);
|
|
1001
|
+
const csv = yield* apiClient.request(
|
|
1002
|
+
(client) => client.organizations.aiGateway.usage.export(orgId, {
|
|
1003
|
+
applicationId: import_effect8.Option.getOrUndefined(app),
|
|
1004
|
+
from: import_effect8.Option.getOrUndefined(from),
|
|
1005
|
+
to: import_effect8.Option.getOrUndefined(to)
|
|
1006
|
+
})
|
|
1007
|
+
);
|
|
1008
|
+
const outPath = import_effect8.Option.getOrUndefined(out);
|
|
1009
|
+
if (outPath === void 0) {
|
|
1010
|
+
yield* import_effect8.Console.log(csv);
|
|
1011
|
+
} else {
|
|
1012
|
+
const fs = yield* import_platform3.FileSystem.FileSystem;
|
|
1013
|
+
yield* fs.writeFileString(outPath, csv).pipe(import_effect8.Effect.mapError((e) => new ApiRequestError({ message: `Failed to write ${outPath}: ${String(e)}` })));
|
|
1014
|
+
yield* import_effect8.Console.log(`Wrote ${outPath}.`);
|
|
1015
|
+
}
|
|
1016
|
+
}).pipe(import_effect8.Effect.catchTags(governanceErrorHandlers))
|
|
1017
|
+
);
|
|
1018
|
+
var usageCommand = import_cli.Command.make("usage", {}, () => import_effect8.Effect.void).pipe(
|
|
1019
|
+
import_cli.Command.withSubcommands([usageSummaryCommand, usageRequestsCommand, usageExportCommand])
|
|
1020
|
+
);
|
|
1021
|
+
var budgetsGetCommand = import_cli.Command.make(
|
|
1022
|
+
"get",
|
|
1023
|
+
{ org: orgOption },
|
|
1024
|
+
({ org }) => import_effect8.Effect.gen(function* () {
|
|
1025
|
+
const apiClient = yield* ApiClientService;
|
|
1026
|
+
const orgId = yield* resolveOrgId(org);
|
|
1027
|
+
const { items } = yield* apiClient.request((client) => client.organizations.aiGateway.budgets.list(orgId));
|
|
1028
|
+
yield* import_effect8.Console.log(JSON.stringify(items, null, 2));
|
|
1029
|
+
}).pipe(import_effect8.Effect.catchTags(governanceErrorHandlers))
|
|
1030
|
+
);
|
|
1031
|
+
var budgetsSetCommand = import_cli.Command.make(
|
|
1032
|
+
"set",
|
|
1033
|
+
{ org: orgOption, file: fileOption },
|
|
1034
|
+
({ org, file }) => import_effect8.Effect.gen(function* () {
|
|
1035
|
+
const apiClient = yield* ApiClientService;
|
|
1036
|
+
const orgId = yield* resolveOrgId(org);
|
|
1037
|
+
const parsed = yield* readJsonInput(file);
|
|
1038
|
+
const budgets = Array.isArray(parsed) ? parsed : parsed.budgets;
|
|
1039
|
+
if (!Array.isArray(budgets)) {
|
|
1040
|
+
return yield* import_effect8.Effect.fail(
|
|
1041
|
+
new ApiRequestError({
|
|
1042
|
+
message: 'Expected a JSON array of budgets, or an object of the form { "budgets": [...] }.'
|
|
1043
|
+
})
|
|
1044
|
+
);
|
|
1045
|
+
}
|
|
1046
|
+
const { items } = yield* apiClient.request(
|
|
1047
|
+
(client) => client.organizations.aiGateway.budgets.replace(orgId, budgets)
|
|
1048
|
+
);
|
|
1049
|
+
yield* import_effect8.Console.log(`Saved ${items.length} budget(s).`);
|
|
1050
|
+
}).pipe(import_effect8.Effect.catchTags(governanceErrorHandlers))
|
|
1051
|
+
);
|
|
1052
|
+
var budgetsCommand = import_cli.Command.make("budgets", {}, () => import_effect8.Effect.void).pipe(
|
|
1053
|
+
import_cli.Command.withSubcommands([budgetsGetCommand, budgetsSetCommand])
|
|
1054
|
+
);
|
|
1055
|
+
var policiesGetCommand = import_cli.Command.make(
|
|
1056
|
+
"get",
|
|
1057
|
+
{ org: orgOption, app: appOption },
|
|
1058
|
+
({ org, app }) => import_effect8.Effect.gen(function* () {
|
|
1059
|
+
const apiClient = yield* ApiClientService;
|
|
1060
|
+
const orgId = yield* resolveOrgId(org);
|
|
1061
|
+
const policy = yield* apiClient.request(
|
|
1062
|
+
(client) => client.organizations.aiGateway.policies.get(orgId, { applicationId: import_effect8.Option.getOrUndefined(app) })
|
|
1063
|
+
);
|
|
1064
|
+
yield* import_effect8.Console.log(policy === null ? "No policy set." : JSON.stringify(policy, null, 2));
|
|
1065
|
+
}).pipe(import_effect8.Effect.catchTags(governanceErrorHandlers))
|
|
1066
|
+
);
|
|
1067
|
+
var policiesSetCommand = import_cli.Command.make(
|
|
1068
|
+
"set",
|
|
1069
|
+
{ org: orgOption, file: fileOption },
|
|
1070
|
+
({ org, file }) => import_effect8.Effect.gen(function* () {
|
|
1071
|
+
const apiClient = yield* ApiClientService;
|
|
1072
|
+
const orgId = yield* resolveOrgId(org);
|
|
1073
|
+
const parsed = yield* readJsonInput(file);
|
|
1074
|
+
const policy = yield* apiClient.request(
|
|
1075
|
+
(client) => client.organizations.aiGateway.policies.put(orgId, parsed)
|
|
1076
|
+
);
|
|
1077
|
+
yield* import_effect8.Console.log(`Policy saved${policy.applicationId ? ` for application ${policy.applicationId}` : ""}.`);
|
|
1078
|
+
}).pipe(import_effect8.Effect.catchTags(governanceErrorHandlers))
|
|
1079
|
+
);
|
|
1080
|
+
var policiesCommand = import_cli.Command.make("policies", {}, () => import_effect8.Effect.void).pipe(
|
|
1081
|
+
import_cli.Command.withSubcommands([policiesGetCommand, policiesSetCommand])
|
|
1082
|
+
);
|
|
1083
|
+
var inferenceErrorHandlers = {
|
|
1084
|
+
NotAuthenticatedError: (err) => import_effect8.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1085
|
+
import_effect8.Effect.andThen(import_effect8.Effect.fail(err))
|
|
1086
|
+
),
|
|
1087
|
+
ApiRequestError: (err) => import_effect8.Console.error(err.message).pipe(import_effect8.Effect.andThen(import_effect8.Effect.fail(err)))
|
|
1088
|
+
};
|
|
1089
|
+
var modelsListCommand = import_cli.Command.make(
|
|
1090
|
+
"list",
|
|
1091
|
+
{},
|
|
1092
|
+
() => import_effect8.Effect.gen(function* () {
|
|
1093
|
+
const apiClient = yield* ApiClientService;
|
|
1094
|
+
const { items } = yield* apiClient.request((client) => client.aiGateway.listModels());
|
|
1095
|
+
for (const m of items) {
|
|
1096
|
+
yield* import_effect8.Console.log(`${m.id} ${m.name} (ctx ${m.contextWindow})`);
|
|
1097
|
+
}
|
|
1098
|
+
}).pipe(import_effect8.Effect.catchTags(inferenceErrorHandlers))
|
|
1099
|
+
);
|
|
1100
|
+
var modelIdArg = import_cli.Args.text({ name: "model-id" }).pipe(import_cli.Args.withDescription("The model ID, e.g. openai/gpt-4o"));
|
|
1101
|
+
var modelsGetCommand = import_cli.Command.make(
|
|
1102
|
+
"get",
|
|
1103
|
+
{ modelId: modelIdArg },
|
|
1104
|
+
({ modelId }) => import_effect8.Effect.gen(function* () {
|
|
1105
|
+
const apiClient = yield* ApiClientService;
|
|
1106
|
+
const model = yield* apiClient.request((client) => client.aiGateway.getModel(modelId));
|
|
1107
|
+
yield* import_effect8.Console.log(JSON.stringify(model, null, 2));
|
|
1108
|
+
}).pipe(import_effect8.Effect.catchTags(inferenceErrorHandlers))
|
|
1109
|
+
);
|
|
1110
|
+
var modelsCommand = import_cli.Command.make("models", {}, () => import_effect8.Effect.void).pipe(
|
|
1111
|
+
import_cli.Command.withSubcommands([modelsListCommand, modelsGetCommand])
|
|
1112
|
+
);
|
|
1113
|
+
var modelOption = import_cli.Options.text("model").pipe(
|
|
1114
|
+
import_cli.Options.withAlias("m"),
|
|
1115
|
+
import_cli.Options.withDescription("The model ID to use, e.g. openai/gpt-4o")
|
|
1116
|
+
);
|
|
1117
|
+
var streamOption = import_cli.Options.boolean("stream").pipe(import_cli.Options.withDescription("Stream the response token by token"));
|
|
1118
|
+
var promptArg = import_cli.Args.text({ name: "prompt" }).pipe(
|
|
1119
|
+
import_cli.Args.withDescription('The prompt text, or "-" to read from stdin')
|
|
1120
|
+
);
|
|
1121
|
+
var chatCommand = import_cli.Command.make(
|
|
1122
|
+
"chat",
|
|
1123
|
+
{ prompt: promptArg, model: modelOption, stream: streamOption },
|
|
1124
|
+
({ prompt, model, stream }) => import_effect8.Effect.gen(function* () {
|
|
1125
|
+
const apiClient = yield* ApiClientService;
|
|
1126
|
+
const text = prompt === "-" ? yield* readStdin : prompt;
|
|
1127
|
+
const messages = [{ role: "user", content: text }];
|
|
1128
|
+
if (stream) {
|
|
1129
|
+
const client = yield* apiClient.getClient;
|
|
1130
|
+
yield* import_effect8.Effect.tryPromise({
|
|
1131
|
+
try: async () => {
|
|
1132
|
+
for await (const chunk of client.aiGateway.chatCompletionsStream({ model, messages })) {
|
|
1133
|
+
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
|
|
1134
|
+
}
|
|
1135
|
+
process.stdout.write("\n");
|
|
1136
|
+
},
|
|
1137
|
+
catch: (error) => new ApiRequestError({ message: error instanceof Error ? error.message : String(error) })
|
|
1138
|
+
});
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
const response = yield* apiClient.request((client) => client.aiGateway.chatCompletions({ model, messages }));
|
|
1142
|
+
const content = response.choices[0]?.message.content;
|
|
1143
|
+
yield* import_effect8.Console.log(typeof content === "string" ? content : JSON.stringify(content));
|
|
1144
|
+
}).pipe(import_effect8.Effect.catchTags(inferenceErrorHandlers))
|
|
1145
|
+
);
|
|
1146
|
+
var aiBase = import_cli.Command.make("ai", {}, () => import_effect8.Effect.void);
|
|
1147
|
+
var aiCommand = aiBase.pipe(
|
|
1148
|
+
import_cli.Command.withSubcommands([usageCommand, budgetsCommand, policiesCommand, modelsCommand, chatCommand])
|
|
1149
|
+
);
|
|
1150
|
+
|
|
1151
|
+
// src/commands/apps/index.ts
|
|
1152
|
+
var import_cli2 = require("@effect/cli");
|
|
1153
|
+
var import_effect9 = require("effect");
|
|
1154
|
+
var orgOption2 = import_cli2.Options.text("org").pipe(
|
|
1155
|
+
import_cli2.Options.withAlias("o"),
|
|
1156
|
+
import_cli2.Options.withDescription("Only list applications belonging to this organization ID"),
|
|
1157
|
+
import_cli2.Options.optional
|
|
1158
|
+
);
|
|
1159
|
+
var appsListCommand = import_cli2.Command.make(
|
|
1160
|
+
"list",
|
|
1161
|
+
{ org: orgOption2 },
|
|
1162
|
+
({ org }) => import_effect9.Effect.gen(function* () {
|
|
1163
|
+
const apiClient = yield* ApiClientService;
|
|
1164
|
+
const organizationId = import_effect9.Option.getOrUndefined(org);
|
|
1165
|
+
const { items, total } = yield* apiClient.request((client) => client.applications.list({ organizationId }));
|
|
1166
|
+
if (items.length === 0) {
|
|
1167
|
+
yield* import_effect9.Console.log("No applications found.");
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
for (const app of items) {
|
|
1171
|
+
yield* import_effect9.Console.log(`${app.id} ${app.name} (${app.organization.name})`);
|
|
1172
|
+
}
|
|
1173
|
+
yield* import_effect9.Console.log(`
|
|
1174
|
+
${total} application(s).`);
|
|
1175
|
+
}).pipe(
|
|
1176
|
+
import_effect9.Effect.catchTags({
|
|
1177
|
+
NotAuthenticatedError: (err) => import_effect9.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1178
|
+
import_effect9.Effect.andThen(import_effect9.Effect.fail(err))
|
|
1179
|
+
),
|
|
1180
|
+
ApiRequestError: (err) => import_effect9.Console.error(`Failed to list applications: ${err.message}`).pipe(import_effect9.Effect.andThen(import_effect9.Effect.fail(err)))
|
|
1181
|
+
})
|
|
1182
|
+
)
|
|
1183
|
+
);
|
|
1184
|
+
var appsBase = import_cli2.Command.make("apps", {}, () => import_effect9.Effect.void);
|
|
1185
|
+
var appsCommand = appsBase.pipe(import_cli2.Command.withSubcommands([appsListCommand]));
|
|
1186
|
+
|
|
1187
|
+
// src/commands/build/index.ts
|
|
1188
|
+
var import_cli3 = require("@effect/cli");
|
|
1189
|
+
var import_platform5 = require("@effect/platform");
|
|
1190
|
+
var import_build_utils2 = require("@gigadrive/build-utils");
|
|
1191
|
+
var import_effect11 = require("effect");
|
|
1192
|
+
|
|
1193
|
+
// src/services/package-manager.ts
|
|
1194
|
+
var import_platform4 = require("@effect/platform");
|
|
1195
|
+
var import_build_utils = require("@gigadrive/build-utils");
|
|
1196
|
+
var import_effect10 = require("effect");
|
|
1197
|
+
var PackageManagerService = class extends import_effect10.Effect.Service()("PackageManagerService", {
|
|
1198
|
+
accessors: true,
|
|
1199
|
+
effect: import_effect10.Effect.gen(function* () {
|
|
1200
|
+
const fs = yield* import_platform4.FileSystem.FileSystem;
|
|
1201
|
+
const pathService = yield* import_platform4.Path.Path;
|
|
1202
|
+
const detect = import_effect10.Effect.fn("PackageManagerService.detect")(function* (cwd) {
|
|
1203
|
+
yield* import_effect10.Effect.annotateCurrentSpan("cwd", cwd);
|
|
1204
|
+
const packageJsonPath = pathService.join(cwd, "package.json");
|
|
1205
|
+
const exists = yield* fs.exists(packageJsonPath).pipe(
|
|
1206
|
+
import_effect10.Effect.mapError(
|
|
1207
|
+
() => new PackageManagerNotFoundError({ message: "Failed to check for package.json", directory: cwd })
|
|
1208
|
+
)
|
|
1209
|
+
);
|
|
1210
|
+
if (!exists) {
|
|
1211
|
+
return yield* import_effect10.Effect.fail(
|
|
1212
|
+
new PackageManagerNotFoundError({
|
|
1213
|
+
message: "No package.json found",
|
|
1214
|
+
directory: cwd
|
|
1215
|
+
})
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
const lockChecks = [
|
|
1219
|
+
{ file: "yarn.lock", pm: "yarn" },
|
|
1220
|
+
{ file: "pnpm-lock.yaml", pm: "pnpm" },
|
|
1221
|
+
{ file: "bun.lockb", pm: "bun" },
|
|
1222
|
+
{ file: "package-lock.json", pm: "npm" }
|
|
1223
|
+
];
|
|
1224
|
+
for (const { file, pm: pm2 } of lockChecks) {
|
|
1225
|
+
const lockExists = yield* fs.exists(pathService.join(cwd, file)).pipe(import_effect10.Effect.catchAll(() => import_effect10.Effect.succeed(false)));
|
|
1226
|
+
if (lockExists) {
|
|
1227
|
+
yield* import_effect10.Effect.log("Package manager detected from lock file", { packageManager: pm2, lockFile: file });
|
|
1228
|
+
return pm2;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
const bunAvailable = yield* import_effect10.Effect.tryPromise({
|
|
1232
|
+
try: () => (0, import_build_utils.exec)({ command: "bun --version", cwd }),
|
|
1233
|
+
catch: () => new ExecError({ message: "bun not found", command: "bun --version" })
|
|
1234
|
+
}).pipe(
|
|
1235
|
+
import_effect10.Effect.as(true),
|
|
1236
|
+
import_effect10.Effect.catchTag("ExecError", () => import_effect10.Effect.succeed(false))
|
|
1237
|
+
);
|
|
1238
|
+
const pm = bunAvailable ? "bun" : "npm";
|
|
1239
|
+
yield* import_effect10.Effect.log("Package manager detected via fallback", { packageManager: pm });
|
|
1240
|
+
return pm;
|
|
1241
|
+
});
|
|
1242
|
+
const installCommand = (pm) => ({
|
|
1243
|
+
bun: "bun install",
|
|
1244
|
+
npm: "npm install",
|
|
1245
|
+
pnpm: "pnpm install",
|
|
1246
|
+
yarn: "yarn install"
|
|
1247
|
+
})[pm];
|
|
1248
|
+
const buildCommand2 = (pm) => ({
|
|
1249
|
+
bun: "bun run build",
|
|
1250
|
+
npm: "npm run build",
|
|
1251
|
+
pnpm: "pnpm build",
|
|
1252
|
+
yarn: "yarn build"
|
|
1253
|
+
})[pm];
|
|
1254
|
+
return { detect, installCommand, buildCommand: buildCommand2 };
|
|
1255
|
+
})
|
|
1256
|
+
}) {
|
|
1257
|
+
};
|
|
1258
|
+
|
|
1259
|
+
// src/commands/build/index.ts
|
|
1260
|
+
var buildCommand = import_cli3.Command.make(
|
|
1261
|
+
"build",
|
|
1262
|
+
{},
|
|
1263
|
+
() => import_effect11.Effect.gen(function* () {
|
|
1264
|
+
const pmService = yield* PackageManagerService;
|
|
1265
|
+
const fs = yield* import_platform5.FileSystem.FileSystem;
|
|
1266
|
+
const pathService = yield* import_platform5.Path.Path;
|
|
1267
|
+
const cwd = process.cwd();
|
|
1268
|
+
yield* import_effect11.Effect.log("Starting build", { cwd });
|
|
1269
|
+
const packageJsonPath = pathService.join(cwd, "package.json");
|
|
1270
|
+
const packageJsonExists = yield* fs.exists(packageJsonPath).pipe(
|
|
1271
|
+
import_effect11.Effect.mapError(
|
|
1272
|
+
() => new PackageJsonNotFoundError({ message: "Failed to check for package.json", directory: cwd })
|
|
1273
|
+
)
|
|
1274
|
+
);
|
|
1275
|
+
if (!packageJsonExists) {
|
|
1276
|
+
return yield* import_effect11.Effect.fail(new PackageJsonNotFoundError({ message: "No package.json found", directory: cwd }));
|
|
1277
|
+
}
|
|
1278
|
+
const packageJsonContent = yield* fs.readFileString(packageJsonPath, "utf-8").pipe(
|
|
1279
|
+
import_effect11.Effect.mapError(() => new PackageJsonNotFoundError({ message: "Failed to read package.json", directory: cwd }))
|
|
1280
|
+
);
|
|
1281
|
+
const packageJson = yield* import_effect11.Effect.try({
|
|
1282
|
+
try: () => JSON.parse(packageJsonContent),
|
|
1283
|
+
catch: (error) => new PackageJsonParseError({
|
|
1284
|
+
message: "Failed to parse package.json",
|
|
1285
|
+
directory: cwd,
|
|
1286
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
1287
|
+
})
|
|
1288
|
+
});
|
|
1289
|
+
if (!packageJson.scripts?.build) {
|
|
1290
|
+
return yield* import_effect11.Effect.fail(new BuildScriptNotFoundError({ message: "No build script found in package.json" }));
|
|
1291
|
+
}
|
|
1292
|
+
const pm = yield* pmService.detect(cwd);
|
|
1293
|
+
const buildEnv = {
|
|
1294
|
+
...process.env,
|
|
1295
|
+
NODE_ENV: "production",
|
|
1296
|
+
NEBULA: "1",
|
|
1297
|
+
VERCEL: "1",
|
|
1298
|
+
NOW_BUILDER: "1"
|
|
1299
|
+
};
|
|
1300
|
+
const installCmd = pmService.installCommand(pm);
|
|
1301
|
+
yield* import_effect11.Console.log(`Running: ${installCmd}`);
|
|
1302
|
+
yield* import_effect11.Effect.tryPromise({
|
|
1303
|
+
try: () => (0, import_build_utils2.exec)({
|
|
1304
|
+
command: installCmd,
|
|
1305
|
+
cwd,
|
|
1306
|
+
env: buildEnv,
|
|
1307
|
+
onOutput: (chunk) => {
|
|
1308
|
+
import_effect11.Console.log(chunk).pipe(import_effect11.Effect.runSync);
|
|
1309
|
+
}
|
|
1310
|
+
}),
|
|
1311
|
+
catch: (error) => new ExecError({
|
|
1312
|
+
message: "Install failed",
|
|
1313
|
+
command: installCmd,
|
|
1314
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
1315
|
+
})
|
|
1316
|
+
});
|
|
1317
|
+
const buildCmd = pmService.buildCommand(pm);
|
|
1318
|
+
yield* import_effect11.Console.log(`Running: ${buildCmd}`);
|
|
1319
|
+
yield* import_effect11.Effect.tryPromise({
|
|
1320
|
+
try: () => (0, import_build_utils2.exec)({
|
|
1321
|
+
command: buildCmd,
|
|
1322
|
+
cwd,
|
|
1323
|
+
env: buildEnv,
|
|
1324
|
+
onOutput: (chunk) => {
|
|
1325
|
+
import_effect11.Console.log(chunk).pipe(import_effect11.Effect.runSync);
|
|
1326
|
+
}
|
|
1327
|
+
}),
|
|
1328
|
+
catch: (error) => new ExecError({
|
|
1329
|
+
message: "Build failed",
|
|
1330
|
+
command: buildCmd,
|
|
1331
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
1332
|
+
})
|
|
1333
|
+
});
|
|
1334
|
+
yield* import_effect11.Console.log("Build completed successfully.");
|
|
1335
|
+
}).pipe(
|
|
1336
|
+
import_effect11.Effect.catchTags({
|
|
1337
|
+
PackageJsonNotFoundError: (err) => import_effect11.Console.error(err.message).pipe(import_effect11.Effect.andThen(import_effect11.Effect.fail(err))),
|
|
1338
|
+
PackageJsonParseError: (err) => import_effect11.Console.error(err.message).pipe(import_effect11.Effect.andThen(import_effect11.Effect.fail(err))),
|
|
1339
|
+
BuildScriptNotFoundError: (err) => import_effect11.Console.error(err.message).pipe(import_effect11.Effect.andThen(import_effect11.Effect.fail(err))),
|
|
1340
|
+
PackageManagerNotFoundError: (err) => import_effect11.Console.error(err.message).pipe(import_effect11.Effect.andThen(import_effect11.Effect.fail(err))),
|
|
1341
|
+
ExecError: (err) => import_effect11.Console.error(`${err.message}: ${err.cause ?? err.command}`).pipe(import_effect11.Effect.andThen(import_effect11.Effect.fail(err)))
|
|
1342
|
+
})
|
|
1343
|
+
)
|
|
1344
|
+
);
|
|
1345
|
+
|
|
1346
|
+
// src/commands/debug/index.ts
|
|
1347
|
+
var import_cli5 = require("@effect/cli");
|
|
1348
|
+
var import_effect14 = require("effect");
|
|
1349
|
+
|
|
1350
|
+
// src/commands/debug/config/index.ts
|
|
1351
|
+
var import_cli4 = require("@effect/cli");
|
|
1352
|
+
var import_effect13 = require("effect");
|
|
1353
|
+
|
|
1354
|
+
// src/services/project-config.ts
|
|
1355
|
+
var import_network_config = require("@gigadrive/network-config");
|
|
1356
|
+
var import_effect12 = require("effect");
|
|
1357
|
+
var wrapParseErrors = (effect) => effect.pipe(
|
|
1358
|
+
import_effect12.Effect.catchTags({
|
|
1359
|
+
ConfigFileNotFoundError: (e) => import_effect12.Effect.fail(new ConfigParseError({ message: e.message, cause: e.filePath })),
|
|
1360
|
+
ConfigFileEmptyError: (e) => import_effect12.Effect.fail(new ConfigParseError({ message: e.message, cause: e.filePath })),
|
|
1361
|
+
ConfigFileParseError: (e) => import_effect12.Effect.fail(new ConfigParseError({ message: e.message, cause: e.cause })),
|
|
1362
|
+
ConfigVersionError: (e) => import_effect12.Effect.fail(new ConfigParseError({ message: e.message, cause: e.filePath })),
|
|
1363
|
+
ConfigSchemaValidationError: (e) => import_effect12.Effect.fail(new ConfigParseError({ message: e.message, cause: e.validationErrors.join(", ") })),
|
|
1364
|
+
FunctionConfigError: (e) => import_effect12.Effect.fail(new ConfigParseError({ message: e.message, cause: e.functionPath }))
|
|
1365
|
+
})
|
|
1366
|
+
);
|
|
1367
|
+
var ProjectConfigService = class extends import_effect12.Effect.Service()("ProjectConfigService", {
|
|
1368
|
+
accessors: true,
|
|
1369
|
+
dependencies: [import_network_config.NetworkConfigLive],
|
|
1370
|
+
effect: import_effect12.Effect.gen(function* () {
|
|
1371
|
+
const rawReader = yield* import_network_config.RawConfigReader;
|
|
1372
|
+
const resolve = import_effect12.Effect.fn("ProjectConfigService.resolve")(function* (cwd) {
|
|
1373
|
+
yield* import_effect12.Effect.annotateCurrentSpan("cwd", cwd);
|
|
1374
|
+
yield* import_effect12.Effect.log("Resolving project config", { cwd });
|
|
1375
|
+
const configPath = yield* rawReader.findConfig(cwd);
|
|
1376
|
+
const detection = yield* (0, import_network_config.detectFramework)(cwd).pipe(
|
|
1377
|
+
import_effect12.Effect.catchTag("FrameworkNotDetectedError", () => import_effect12.Effect.succeed(null)),
|
|
1378
|
+
import_effect12.Effect.catchTag(
|
|
1379
|
+
"ManifestReadError",
|
|
1380
|
+
(e) => import_effect12.Effect.fail(new ConfigParseError({ message: `Framework detection failed: ${e.message}`, cause: e.filePath }))
|
|
1381
|
+
),
|
|
1382
|
+
import_effect12.Effect.catchTag(
|
|
1383
|
+
"ManifestParseError",
|
|
1384
|
+
(e) => import_effect12.Effect.fail(new ConfigParseError({ message: `Framework detection failed: ${e.message}`, cause: e.filePath }))
|
|
1385
|
+
)
|
|
1386
|
+
);
|
|
1387
|
+
if (detection) {
|
|
1388
|
+
yield* import_effect12.Effect.log("Framework auto-detected", {
|
|
1389
|
+
framework: detection.framework.name,
|
|
1390
|
+
slug: detection.framework.slug
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
let config;
|
|
1394
|
+
let resolvedConfigPath = null;
|
|
1395
|
+
let framework;
|
|
1396
|
+
if (configPath && detection) {
|
|
1397
|
+
yield* import_effect12.Effect.log("Config file found, merging with framework defaults", { configPath });
|
|
1398
|
+
resolvedConfigPath = configPath;
|
|
1399
|
+
const userConfig = yield* wrapParseErrors((0, import_network_config.parseConfigRaw)(configPath, cwd));
|
|
1400
|
+
const merged = yield* (0, import_network_config.mergeWithFrameworkDefaults)(userConfig, detection.config);
|
|
1401
|
+
config = yield* wrapParseErrors((0, import_network_config.postProcessConfig)(merged, cwd));
|
|
1402
|
+
framework = { name: detection.framework.name, slug: detection.framework.slug };
|
|
1403
|
+
} else if (configPath) {
|
|
1404
|
+
yield* import_effect12.Effect.log("Config file found", { configPath });
|
|
1405
|
+
resolvedConfigPath = configPath;
|
|
1406
|
+
config = yield* wrapParseErrors((0, import_network_config.parseConfig)(configPath, cwd));
|
|
1407
|
+
} else if (detection) {
|
|
1408
|
+
config = yield* wrapParseErrors((0, import_network_config.postProcessConfig)(detection.config, cwd));
|
|
1409
|
+
framework = { name: detection.framework.name, slug: detection.framework.slug };
|
|
1410
|
+
} else {
|
|
1411
|
+
return yield* import_effect12.Effect.fail(
|
|
1412
|
+
new ConfigNotFoundError({
|
|
1413
|
+
message: "No config file found and no framework detected.",
|
|
1414
|
+
directory: cwd
|
|
1415
|
+
})
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
for (const warning of config.warnings) {
|
|
1419
|
+
yield* import_effect12.Effect.logWarning(warning);
|
|
914
1420
|
}
|
|
915
|
-
if (
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
return yield* import_effect10.Effect.fail(
|
|
921
|
-
new UserInfoFetchError({
|
|
922
|
-
message: `Failed to fetch user info: ${response.status} ${response.statusText}${body ? ` - ${body}` : ""}`,
|
|
923
|
-
statusCode: response.status
|
|
1421
|
+
if (config.errors.length > 0) {
|
|
1422
|
+
return yield* import_effect12.Effect.fail(
|
|
1423
|
+
new ConfigValidationError({
|
|
1424
|
+
message: "Config file has validation errors",
|
|
1425
|
+
errors: config.errors
|
|
924
1426
|
})
|
|
925
1427
|
);
|
|
926
1428
|
}
|
|
927
|
-
|
|
928
|
-
try: () => response.json(),
|
|
929
|
-
catch: () => new UserInfoFetchError({ message: "Failed to parse user info response" })
|
|
930
|
-
});
|
|
931
|
-
return data;
|
|
1429
|
+
return { config, configPath: resolvedConfigPath, framework };
|
|
932
1430
|
});
|
|
933
|
-
|
|
934
|
-
const isNonEmptyString = (value) => typeof value === "string" && value.trim() !== "";
|
|
935
|
-
const name = info.name;
|
|
936
|
-
const givenName = info.given_name;
|
|
937
|
-
const familyName = info.family_name;
|
|
938
|
-
const preferredUsername = info.preferred_username;
|
|
939
|
-
const email = info.email;
|
|
940
|
-
return isNonEmptyString(name) && name || (isNonEmptyString(givenName) && isNonEmptyString(familyName) ? `${givenName} ${familyName}` : void 0) || isNonEmptyString(preferredUsername) && preferredUsername || isNonEmptyString(email) && email || "your account";
|
|
941
|
-
};
|
|
942
|
-
return { login, logout, getAccessToken, getUserInfo, refreshAccessToken, inferUserName };
|
|
1431
|
+
return { resolve };
|
|
943
1432
|
})
|
|
944
1433
|
}) {
|
|
945
1434
|
};
|
|
946
1435
|
|
|
1436
|
+
// src/commands/debug/config/index.ts
|
|
1437
|
+
var debugConfigCommand = import_cli4.Command.make(
|
|
1438
|
+
"config",
|
|
1439
|
+
{},
|
|
1440
|
+
() => import_effect13.Effect.gen(function* () {
|
|
1441
|
+
const projectConfig = yield* ProjectConfigService;
|
|
1442
|
+
const cwd = process.cwd();
|
|
1443
|
+
const { config, configPath } = yield* projectConfig.resolve(cwd);
|
|
1444
|
+
yield* import_effect13.Console.log(`Config file found at: ${configPath}`);
|
|
1445
|
+
yield* import_effect13.Console.log(JSON.stringify(config, null, 2));
|
|
1446
|
+
}).pipe(
|
|
1447
|
+
import_effect13.Effect.catchTags({
|
|
1448
|
+
ConfigNotFoundError: (err) => import_effect13.Console.error(err.message),
|
|
1449
|
+
ConfigParseError: (err) => import_effect13.Console.error(`Config parse error: ${err.message}`),
|
|
1450
|
+
ConfigValidationError: (err) => import_effect13.Effect.gen(function* () {
|
|
1451
|
+
for (const e of err.errors) {
|
|
1452
|
+
yield* import_effect13.Console.error(e);
|
|
1453
|
+
}
|
|
1454
|
+
yield* import_effect13.Console.error(err.message);
|
|
1455
|
+
})
|
|
1456
|
+
})
|
|
1457
|
+
)
|
|
1458
|
+
);
|
|
1459
|
+
|
|
1460
|
+
// src/commands/debug/index.ts
|
|
1461
|
+
var debugBase = import_cli5.Command.make("debug", {}, () => import_effect14.Effect.void);
|
|
1462
|
+
var debugCommand = debugBase.pipe(import_cli5.Command.withSubcommands([debugConfigCommand]));
|
|
1463
|
+
|
|
1464
|
+
// src/commands/deployments/index.ts
|
|
1465
|
+
var import_cli6 = require("@effect/cli");
|
|
1466
|
+
var import_effect15 = require("effect");
|
|
1467
|
+
var DEPLOYMENT_STATUSES = ["PENDING", "QUEUED", "STARTING", "BUILDING", "PROVISIONING", "ACTIVE", "FAILED"];
|
|
1468
|
+
var appOption2 = import_cli6.Options.text("app").pipe(
|
|
1469
|
+
import_cli6.Options.withAlias("a"),
|
|
1470
|
+
import_cli6.Options.withDescription("Filter by application ID (defaults to the linked application)"),
|
|
1471
|
+
import_cli6.Options.optional
|
|
1472
|
+
);
|
|
1473
|
+
var orgOption3 = import_cli6.Options.text("org").pipe(
|
|
1474
|
+
import_cli6.Options.withAlias("o"),
|
|
1475
|
+
import_cli6.Options.withDescription("Filter by organization ID"),
|
|
1476
|
+
import_cli6.Options.optional
|
|
1477
|
+
);
|
|
1478
|
+
var statusOption = import_cli6.Options.choice("status", DEPLOYMENT_STATUSES).pipe(
|
|
1479
|
+
import_cli6.Options.withAlias("s"),
|
|
1480
|
+
import_cli6.Options.withDescription("Filter by deployment status"),
|
|
1481
|
+
import_cli6.Options.optional
|
|
1482
|
+
);
|
|
1483
|
+
var resolveApplicationFilter = (app) => import_effect15.Option.match(app, {
|
|
1484
|
+
onSome: (id) => import_effect15.Effect.succeed(id),
|
|
1485
|
+
onNone: () => import_effect15.Effect.gen(function* () {
|
|
1486
|
+
const projectLink = yield* ProjectLinkService;
|
|
1487
|
+
const link = yield* projectLink.load(process.cwd());
|
|
1488
|
+
return import_effect15.Option.match(link, { onNone: () => void 0, onSome: (l) => l.applicationId });
|
|
1489
|
+
})
|
|
1490
|
+
});
|
|
1491
|
+
var deploymentsListCommand = import_cli6.Command.make(
|
|
1492
|
+
"list",
|
|
1493
|
+
{ app: appOption2, org: orgOption3, status: statusOption },
|
|
1494
|
+
({ app, org, status }) => import_effect15.Effect.gen(function* () {
|
|
1495
|
+
const apiClient = yield* ApiClientService;
|
|
1496
|
+
const applicationId = yield* resolveApplicationFilter(app);
|
|
1497
|
+
const { items, total } = yield* apiClient.request(
|
|
1498
|
+
(client) => client.deployments.list({
|
|
1499
|
+
applicationId,
|
|
1500
|
+
organizationId: import_effect15.Option.getOrUndefined(org),
|
|
1501
|
+
status: import_effect15.Option.getOrUndefined(status)
|
|
1502
|
+
})
|
|
1503
|
+
);
|
|
1504
|
+
if (items.length === 0) {
|
|
1505
|
+
yield* import_effect15.Console.log("No deployments found.");
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
for (const d of items) {
|
|
1509
|
+
yield* import_effect15.Console.log(`${d.id} ${d.status.padEnd(12)} ${d.createdAt}`);
|
|
1510
|
+
}
|
|
1511
|
+
yield* import_effect15.Console.log(`
|
|
1512
|
+
${total} deployment(s).`);
|
|
1513
|
+
}).pipe(
|
|
1514
|
+
import_effect15.Effect.catchTags({
|
|
1515
|
+
NotAuthenticatedError: (err) => import_effect15.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1516
|
+
import_effect15.Effect.andThen(import_effect15.Effect.fail(err))
|
|
1517
|
+
),
|
|
1518
|
+
ApiRequestError: (err) => import_effect15.Console.error(`Failed to list deployments: ${err.message}`).pipe(import_effect15.Effect.andThen(import_effect15.Effect.fail(err))),
|
|
1519
|
+
ProjectLinkReadError: (err) => import_effect15.Console.error(err.message).pipe(import_effect15.Effect.andThen(import_effect15.Effect.fail(err)))
|
|
1520
|
+
})
|
|
1521
|
+
)
|
|
1522
|
+
);
|
|
1523
|
+
var deploymentIdArg = import_cli6.Args.text({ name: "deployment-id" }).pipe(import_cli6.Args.withDescription("The deployment ID to inspect"));
|
|
1524
|
+
var deploymentsInspectCommand = import_cli6.Command.make(
|
|
1525
|
+
"inspect",
|
|
1526
|
+
{ deploymentId: deploymentIdArg },
|
|
1527
|
+
({ deploymentId }) => import_effect15.Effect.gen(function* () {
|
|
1528
|
+
const apiClient = yield* ApiClientService;
|
|
1529
|
+
const deployment = yield* apiClient.request((client) => client.deployments.get(deploymentId));
|
|
1530
|
+
yield* import_effect15.Console.log(`ID: ${deployment.id}`);
|
|
1531
|
+
yield* import_effect15.Console.log(`Application: ${deployment.applicationId}`);
|
|
1532
|
+
yield* import_effect15.Console.log(`Status: ${deployment.status}`);
|
|
1533
|
+
yield* import_effect15.Console.log(`Created: ${deployment.createdAt}`);
|
|
1534
|
+
yield* import_effect15.Console.log(`Updated: ${deployment.updatedAt}`);
|
|
1535
|
+
const hostnames = yield* apiClient.request((client) => client.deployments.getHostnames(deploymentId)).pipe(import_effect15.Effect.catchAll(() => import_effect15.Effect.succeed({ items: [], total: 0 })));
|
|
1536
|
+
if (hostnames.items.length > 0) {
|
|
1537
|
+
yield* import_effect15.Console.log("Hostnames:");
|
|
1538
|
+
for (const h of hostnames.items) {
|
|
1539
|
+
yield* import_effect15.Console.log(` https://${h.hostname}${h.active ? "" : " (inactive)"}`);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}).pipe(
|
|
1543
|
+
import_effect15.Effect.catchTags({
|
|
1544
|
+
NotAuthenticatedError: (err) => import_effect15.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1545
|
+
import_effect15.Effect.andThen(import_effect15.Effect.fail(err))
|
|
1546
|
+
),
|
|
1547
|
+
ApiRequestError: (err) => import_effect15.Console.error(`Failed to inspect deployment: ${err.message}`).pipe(import_effect15.Effect.andThen(import_effect15.Effect.fail(err)))
|
|
1548
|
+
})
|
|
1549
|
+
)
|
|
1550
|
+
);
|
|
1551
|
+
var deploymentsBase = import_cli6.Command.make("deployments", {}, () => import_effect15.Effect.void);
|
|
1552
|
+
var deploymentsCommand = deploymentsBase.pipe(
|
|
1553
|
+
import_cli6.Command.withSubcommands([deploymentsListCommand, deploymentsInspectCommand])
|
|
1554
|
+
);
|
|
1555
|
+
|
|
1556
|
+
// src/commands/env/index.ts
|
|
1557
|
+
var import_cli7 = require("@effect/cli");
|
|
1558
|
+
var import_effect16 = require("effect");
|
|
1559
|
+
var appOption3 = import_cli7.Options.text("app").pipe(
|
|
1560
|
+
import_cli7.Options.withAlias("a"),
|
|
1561
|
+
import_cli7.Options.withDescription("Operate on this application (overrides the linked application)"),
|
|
1562
|
+
import_cli7.Options.optional
|
|
1563
|
+
);
|
|
1564
|
+
var orgOption4 = import_cli7.Options.text("org").pipe(
|
|
1565
|
+
import_cli7.Options.withAlias("o"),
|
|
1566
|
+
import_cli7.Options.withDescription("Operate on this organization instead of an application"),
|
|
1567
|
+
import_cli7.Options.optional
|
|
1568
|
+
);
|
|
1569
|
+
var sensitiveOption = import_cli7.Options.boolean("sensitive").pipe(
|
|
1570
|
+
import_cli7.Options.withDescription("Store the value as sensitive (hidden in API responses)")
|
|
1571
|
+
);
|
|
1572
|
+
var envIdOption = import_cli7.Options.text("env").pipe(
|
|
1573
|
+
import_cli7.Options.withAlias("e"),
|
|
1574
|
+
import_cli7.Options.withDescription("Environment ID for an environment-scoped variable (application scope only)"),
|
|
1575
|
+
import_cli7.Options.optional
|
|
1576
|
+
);
|
|
1577
|
+
var keyValueArg = import_cli7.Args.text({ name: "key=value" }).pipe(
|
|
1578
|
+
import_cli7.Args.withDescription("Variable assignment, e.g. DATABASE_URL=postgres://user:pass@host/db")
|
|
1579
|
+
);
|
|
1580
|
+
var keyOrIdArg = import_cli7.Args.text({ name: "key-or-id" }).pipe(import_cli7.Args.withDescription("Variable key or ID to remove"));
|
|
1581
|
+
var resolveScope = (app, org) => import_effect16.Effect.gen(function* () {
|
|
1582
|
+
if (import_effect16.Option.isSome(org)) {
|
|
1583
|
+
return { kind: "organization", id: org.value };
|
|
1584
|
+
}
|
|
1585
|
+
const projectLink = yield* ProjectLinkService;
|
|
1586
|
+
const id = yield* import_effect16.Option.match(app, {
|
|
1587
|
+
onSome: (value) => import_effect16.Effect.succeed(value),
|
|
1588
|
+
onNone: () => projectLink.resolve(process.cwd()).pipe(import_effect16.Effect.map((link) => link.applicationId))
|
|
1589
|
+
});
|
|
1590
|
+
return { kind: "application", id };
|
|
1591
|
+
});
|
|
1592
|
+
var envListCommand = import_cli7.Command.make(
|
|
1593
|
+
"list",
|
|
1594
|
+
{ app: appOption3, org: orgOption4 },
|
|
1595
|
+
({ app, org }) => import_effect16.Effect.gen(function* () {
|
|
1596
|
+
const apiClient = yield* ApiClientService;
|
|
1597
|
+
const scope = yield* resolveScope(app, org);
|
|
1598
|
+
const { items } = yield* apiClient.request(
|
|
1599
|
+
(client) => scope.kind === "organization" ? client.organizations.envVars.list(scope.id) : client.applications.envVars.list(scope.id)
|
|
1600
|
+
);
|
|
1601
|
+
if (items.length === 0) {
|
|
1602
|
+
yield* import_effect16.Console.log("No environment variables set.");
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
for (const v of items) {
|
|
1606
|
+
yield* import_effect16.Console.log(`${v.key}=${v.sensitive ? "***" : v.value ?? ""}`);
|
|
1607
|
+
}
|
|
1608
|
+
}).pipe(
|
|
1609
|
+
import_effect16.Effect.catchTags({
|
|
1610
|
+
NotAuthenticatedError: (err) => import_effect16.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1611
|
+
import_effect16.Effect.andThen(import_effect16.Effect.fail(err))
|
|
1612
|
+
),
|
|
1613
|
+
ApiRequestError: (err) => import_effect16.Console.error(`Failed to list environment variables: ${err.message}`).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1614
|
+
ProjectNotLinkedError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1615
|
+
ProjectLinkReadError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err)))
|
|
1616
|
+
})
|
|
1617
|
+
)
|
|
1618
|
+
);
|
|
1619
|
+
var envSetCommand = import_cli7.Command.make(
|
|
1620
|
+
"set",
|
|
1621
|
+
{ keyValue: keyValueArg, app: appOption3, org: orgOption4, sensitive: sensitiveOption, env: envIdOption },
|
|
1622
|
+
({ keyValue, app, org, sensitive, env }) => import_effect16.Effect.gen(function* () {
|
|
1623
|
+
const separator = keyValue.indexOf("=");
|
|
1624
|
+
if (separator <= 0) {
|
|
1625
|
+
return yield* import_effect16.Effect.fail(
|
|
1626
|
+
new InvalidEnvVarFormatError({
|
|
1627
|
+
message: 'Invalid format. Use KEY=VALUE, e.g. "gigadrive env set DATABASE_URL=postgres://...".'
|
|
1628
|
+
})
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
const key = keyValue.slice(0, separator);
|
|
1632
|
+
const value = keyValue.slice(separator + 1);
|
|
1633
|
+
const apiClient = yield* ApiClientService;
|
|
1634
|
+
const scope = yield* resolveScope(app, org);
|
|
1635
|
+
const environmentId = import_effect16.Option.getOrUndefined(env);
|
|
1636
|
+
const created = yield* apiClient.request(
|
|
1637
|
+
(client) => scope.kind === "organization" ? client.organizations.envVars.create(scope.id, { key, value, sensitive }) : client.applications.envVars.create(scope.id, { key, value, sensitive, environmentId })
|
|
1638
|
+
);
|
|
1639
|
+
yield* import_effect16.Console.log(`Set ${created.key}.`);
|
|
1640
|
+
}).pipe(
|
|
1641
|
+
import_effect16.Effect.catchTags({
|
|
1642
|
+
InvalidEnvVarFormatError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1643
|
+
NotAuthenticatedError: (err) => import_effect16.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1644
|
+
import_effect16.Effect.andThen(import_effect16.Effect.fail(err))
|
|
1645
|
+
),
|
|
1646
|
+
ApiRequestError: (err) => import_effect16.Console.error(`Failed to set environment variable: ${err.message}`).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1647
|
+
ProjectNotLinkedError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1648
|
+
ProjectLinkReadError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err)))
|
|
1649
|
+
})
|
|
1650
|
+
)
|
|
1651
|
+
);
|
|
1652
|
+
var envRmCommand = import_cli7.Command.make(
|
|
1653
|
+
"rm",
|
|
1654
|
+
{ keyOrId: keyOrIdArg, app: appOption3, org: orgOption4 },
|
|
1655
|
+
({ keyOrId, app, org }) => import_effect16.Effect.gen(function* () {
|
|
1656
|
+
const apiClient = yield* ApiClientService;
|
|
1657
|
+
const scope = yield* resolveScope(app, org);
|
|
1658
|
+
const { items } = yield* apiClient.request(
|
|
1659
|
+
(client) => scope.kind === "organization" ? client.organizations.envVars.list(scope.id) : client.applications.envVars.list(scope.id)
|
|
1660
|
+
);
|
|
1661
|
+
const target = items.find((v) => v.id === keyOrId || v.key === keyOrId);
|
|
1662
|
+
if (target === void 0) {
|
|
1663
|
+
return yield* import_effect16.Effect.fail(
|
|
1664
|
+
new EnvVarNotFoundError({ message: `No environment variable matching "${keyOrId}".` })
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
yield* apiClient.request(
|
|
1668
|
+
(client) => scope.kind === "organization" ? client.organizations.envVars.delete(scope.id, target.id) : client.applications.envVars.delete(scope.id, target.id)
|
|
1669
|
+
);
|
|
1670
|
+
yield* import_effect16.Console.log(`Removed ${target.key}.`);
|
|
1671
|
+
}).pipe(
|
|
1672
|
+
import_effect16.Effect.catchTags({
|
|
1673
|
+
EnvVarNotFoundError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1674
|
+
NotAuthenticatedError: (err) => import_effect16.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1675
|
+
import_effect16.Effect.andThen(import_effect16.Effect.fail(err))
|
|
1676
|
+
),
|
|
1677
|
+
ApiRequestError: (err) => import_effect16.Console.error(`Failed to remove environment variable: ${err.message}`).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1678
|
+
ProjectNotLinkedError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err))),
|
|
1679
|
+
ProjectLinkReadError: (err) => import_effect16.Console.error(err.message).pipe(import_effect16.Effect.andThen(import_effect16.Effect.fail(err)))
|
|
1680
|
+
})
|
|
1681
|
+
)
|
|
1682
|
+
);
|
|
1683
|
+
var envBase = import_cli7.Command.make("env", {}, () => import_effect16.Effect.void);
|
|
1684
|
+
var envCommand = envBase.pipe(import_cli7.Command.withSubcommands([envListCommand, envSetCommand, envRmCommand]));
|
|
1685
|
+
|
|
1686
|
+
// src/commands/link/index.ts
|
|
1687
|
+
var import_cli8 = require("@effect/cli");
|
|
1688
|
+
var import_effect17 = require("effect");
|
|
1689
|
+
var appOption4 = import_cli8.Options.text("app").pipe(
|
|
1690
|
+
import_cli8.Options.withAlias("a"),
|
|
1691
|
+
import_cli8.Options.withDescription("Application ID to link (skips the interactive picker)"),
|
|
1692
|
+
import_cli8.Options.optional
|
|
1693
|
+
);
|
|
1694
|
+
var orgOption5 = import_cli8.Options.text("org").pipe(
|
|
1695
|
+
import_cli8.Options.withAlias("o"),
|
|
1696
|
+
import_cli8.Options.withDescription("Only list applications belonging to this organization ID"),
|
|
1697
|
+
import_cli8.Options.optional
|
|
1698
|
+
);
|
|
1699
|
+
var linkCommand = import_cli8.Command.make(
|
|
1700
|
+
"link",
|
|
1701
|
+
{ app: appOption4, org: orgOption5 },
|
|
1702
|
+
({ app, org }) => import_effect17.Effect.gen(function* () {
|
|
1703
|
+
const apiClient = yield* ApiClientService;
|
|
1704
|
+
const projectLink = yield* ProjectLinkService;
|
|
1705
|
+
const cwd = process.cwd();
|
|
1706
|
+
const organizationId = import_effect17.Option.getOrUndefined(org);
|
|
1707
|
+
const { items: apps } = yield* apiClient.request((client) => client.applications.list({ organizationId }));
|
|
1708
|
+
if (apps.length === 0) {
|
|
1709
|
+
return yield* import_effect17.Effect.fail(
|
|
1710
|
+
new NoApplicationsFoundError({
|
|
1711
|
+
message: 'No applications found. Create one in the Gigadrive console, then run "gigadrive link" again.'
|
|
1712
|
+
})
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
const explicitAppId = import_effect17.Option.getOrUndefined(app);
|
|
1716
|
+
let applicationId;
|
|
1717
|
+
let linkedOrganizationId;
|
|
1718
|
+
if (explicitAppId !== void 0) {
|
|
1719
|
+
const match = apps.find((a) => a.id === explicitAppId);
|
|
1720
|
+
if (match === void 0) {
|
|
1721
|
+
return yield* import_effect17.Effect.fail(
|
|
1722
|
+
new ApplicationNotFoundError({
|
|
1723
|
+
message: `Application "${explicitAppId}" was not found among your applications.`
|
|
1724
|
+
})
|
|
1725
|
+
);
|
|
1726
|
+
}
|
|
1727
|
+
applicationId = match.id;
|
|
1728
|
+
linkedOrganizationId = match.organization.id;
|
|
1729
|
+
} else if (apps.length === 1) {
|
|
1730
|
+
applicationId = apps[0].id;
|
|
1731
|
+
linkedOrganizationId = apps[0].organization.id;
|
|
1732
|
+
} else {
|
|
1733
|
+
const chosen = yield* import_cli8.Prompt.run(
|
|
1734
|
+
import_cli8.Prompt.select({
|
|
1735
|
+
message: "Select an application to link",
|
|
1736
|
+
choices: apps.map((a) => ({ title: `${a.name} (${a.organization.name})`, value: a }))
|
|
1737
|
+
})
|
|
1738
|
+
);
|
|
1739
|
+
applicationId = chosen.id;
|
|
1740
|
+
linkedOrganizationId = chosen.organization.id;
|
|
1741
|
+
}
|
|
1742
|
+
yield* projectLink.save(cwd, { applicationId, organizationId: linkedOrganizationId });
|
|
1743
|
+
yield* import_effect17.Console.log(`Linked this directory to application ${applicationId}.`);
|
|
1744
|
+
yield* import_effect17.Console.log('Tip: add ".gigadrive/" to your .gitignore.');
|
|
1745
|
+
}).pipe(
|
|
1746
|
+
import_effect17.Effect.catchTags({
|
|
1747
|
+
// Ctrl+C during the picker is a deliberate cancel — exit 0.
|
|
1748
|
+
QuitException: () => import_effect17.Console.log("Cancelled."),
|
|
1749
|
+
NotAuthenticatedError: (err) => import_effect17.Console.error('You are not logged in. Run "gigadrive login" to authenticate.').pipe(
|
|
1750
|
+
import_effect17.Effect.andThen(import_effect17.Effect.fail(err))
|
|
1751
|
+
),
|
|
1752
|
+
ApiRequestError: (err) => import_effect17.Console.error(`Failed to list applications: ${err.message}`).pipe(import_effect17.Effect.andThen(import_effect17.Effect.fail(err))),
|
|
1753
|
+
NoApplicationsFoundError: (err) => import_effect17.Console.error(err.message).pipe(import_effect17.Effect.andThen(import_effect17.Effect.fail(err))),
|
|
1754
|
+
ApplicationNotFoundError: (err) => import_effect17.Console.error(err.message).pipe(import_effect17.Effect.andThen(import_effect17.Effect.fail(err))),
|
|
1755
|
+
ProjectLinkWriteError: (err) => import_effect17.Console.error(err.message).pipe(import_effect17.Effect.andThen(import_effect17.Effect.fail(err)))
|
|
1756
|
+
})
|
|
1757
|
+
)
|
|
1758
|
+
);
|
|
1759
|
+
var unlinkCommand = import_cli8.Command.make(
|
|
1760
|
+
"unlink",
|
|
1761
|
+
{},
|
|
1762
|
+
() => import_effect17.Effect.gen(function* () {
|
|
1763
|
+
const projectLink = yield* ProjectLinkService;
|
|
1764
|
+
yield* projectLink.remove(process.cwd());
|
|
1765
|
+
yield* import_effect17.Console.log("Unlinked this directory.");
|
|
1766
|
+
}).pipe(
|
|
1767
|
+
import_effect17.Effect.catchTags({
|
|
1768
|
+
ProjectLinkWriteError: (err) => import_effect17.Console.error(err.message).pipe(import_effect17.Effect.andThen(import_effect17.Effect.fail(err)))
|
|
1769
|
+
})
|
|
1770
|
+
)
|
|
1771
|
+
);
|
|
1772
|
+
|
|
947
1773
|
// src/commands/login/index.ts
|
|
948
|
-
var
|
|
1774
|
+
var import_cli9 = require("@effect/cli");
|
|
1775
|
+
var import_effect18 = require("effect");
|
|
1776
|
+
var loginCommand = import_cli9.Command.make(
|
|
949
1777
|
"login",
|
|
950
1778
|
{},
|
|
951
|
-
() =>
|
|
952
|
-
yield*
|
|
1779
|
+
() => import_effect18.Effect.gen(function* () {
|
|
1780
|
+
yield* import_effect18.Console.log("Initiating login...");
|
|
953
1781
|
const auth = yield* AuthService;
|
|
954
1782
|
yield* auth.login;
|
|
955
|
-
const info = yield* auth.getUserInfo.pipe(
|
|
1783
|
+
const info = yield* auth.getUserInfo.pipe(import_effect18.Effect.catchAll(() => import_effect18.Effect.succeed({})));
|
|
956
1784
|
const name = auth.inferUserName(info);
|
|
957
|
-
yield*
|
|
1785
|
+
yield* import_effect18.Console.log(`You are now logged in as ${name}.`);
|
|
958
1786
|
}).pipe(
|
|
959
|
-
|
|
960
|
-
LoginFlowError: (err) =>
|
|
961
|
-
TokenExchangeError: (err) =>
|
|
962
|
-
OAuthDiscoveryError: (err) =>
|
|
963
|
-
AuthStorageWriteError: (err) =>
|
|
1787
|
+
import_effect18.Effect.catchTags({
|
|
1788
|
+
LoginFlowError: (err) => import_effect18.Console.error(`Login failed: ${err.message}`),
|
|
1789
|
+
TokenExchangeError: (err) => import_effect18.Console.error(`Login failed: ${err.message}`),
|
|
1790
|
+
OAuthDiscoveryError: (err) => import_effect18.Console.error(`Login failed: ${err.message}`),
|
|
1791
|
+
AuthStorageWriteError: (err) => import_effect18.Console.error(`Failed to save credentials: ${err.message}`)
|
|
1792
|
+
})
|
|
1793
|
+
)
|
|
1794
|
+
);
|
|
1795
|
+
|
|
1796
|
+
// src/commands/logout/index.ts
|
|
1797
|
+
var import_cli10 = require("@effect/cli");
|
|
1798
|
+
var import_effect19 = require("effect");
|
|
1799
|
+
var logoutCommand = import_cli10.Command.make(
|
|
1800
|
+
"logout",
|
|
1801
|
+
{},
|
|
1802
|
+
() => import_effect19.Effect.gen(function* () {
|
|
1803
|
+
const auth = yield* AuthService;
|
|
1804
|
+
yield* auth.logout;
|
|
1805
|
+
yield* import_effect19.Console.log("Logged out.");
|
|
1806
|
+
}).pipe(
|
|
1807
|
+
import_effect19.Effect.catchTags({
|
|
1808
|
+
AuthStorageWriteError: (err) => import_effect19.Console.error(`Failed to log out: ${err.message}`).pipe(import_effect19.Effect.andThen(import_effect19.Effect.fail(err)))
|
|
964
1809
|
})
|
|
965
1810
|
)
|
|
966
1811
|
);
|
|
967
1812
|
|
|
968
1813
|
// src/commands/platform/index.ts
|
|
969
|
-
var
|
|
970
|
-
var
|
|
1814
|
+
var import_cli12 = require("@effect/cli");
|
|
1815
|
+
var import_effect23 = require("effect");
|
|
971
1816
|
|
|
972
1817
|
// src/commands/platform/deploy/index.ts
|
|
973
|
-
var
|
|
974
|
-
var
|
|
975
|
-
var
|
|
976
|
-
var
|
|
1818
|
+
var import_cli11 = require("@effect/cli");
|
|
1819
|
+
var import_platform7 = require("@effect/platform");
|
|
1820
|
+
var import_commons = require("@gigadrive/commons");
|
|
1821
|
+
var import_effect22 = require("effect");
|
|
977
1822
|
var os2 = __toESM(require("os"), 1);
|
|
978
1823
|
|
|
979
1824
|
// src/services/archive.ts
|
|
980
|
-
var
|
|
1825
|
+
var import_platform6 = require("@effect/platform");
|
|
981
1826
|
var import_build_utils3 = require("@gigadrive/build-utils");
|
|
982
1827
|
var import_archiver = __toESM(require("archiver"), 1);
|
|
983
|
-
var
|
|
1828
|
+
var import_effect20 = require("effect");
|
|
984
1829
|
var import_ignore = __toESM(require("ignore"), 1);
|
|
985
1830
|
var nodeFs = __toESM(require("fs"), 1);
|
|
986
1831
|
var nodeFsPromises = __toESM(require("fs/promises"), 1);
|
|
987
1832
|
var IGNORE_FILE_NAMES = [".gigadriveignore", ".vercelignore", ".dockerignore", ".nowignore"];
|
|
988
1833
|
var readIgnoreFile = (fs, ignorePath) => fs.readFileString(ignorePath, "utf8").pipe(
|
|
989
|
-
|
|
990
|
-
|
|
1834
|
+
import_effect20.Effect.map((content) => content.split("\n").filter((line) => line.trim() !== "")),
|
|
1835
|
+
import_effect20.Effect.catchAll(() => import_effect20.Effect.succeed([]))
|
|
991
1836
|
);
|
|
992
|
-
var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) =>
|
|
993
|
-
const items = yield* fs.readDirectory(dir).pipe(
|
|
1837
|
+
var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) => import_effect20.Effect.gen(function* () {
|
|
1838
|
+
const items = yield* fs.readDirectory(dir).pipe(import_effect20.Effect.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${dir}` })));
|
|
994
1839
|
for (const item of items) {
|
|
995
1840
|
const fullPath = pathService.join(dir, item);
|
|
996
1841
|
const relativePath = pathService.relative(baseDir, fullPath);
|
|
997
|
-
const stat = yield*
|
|
1842
|
+
const stat = yield* import_effect20.Effect.tryPromise({
|
|
998
1843
|
try: () => nodeFsPromises.lstat(fullPath),
|
|
999
1844
|
catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
|
|
1000
1845
|
});
|
|
@@ -1014,8 +1859,8 @@ var collectIgnorePatterns = (fs, pathService, dir, baseDir, ignoreRules) => impo
|
|
|
1014
1859
|
yield* collectIgnorePatterns(fs, pathService, fullPath, baseDir, ignoreRules);
|
|
1015
1860
|
}
|
|
1016
1861
|
}
|
|
1017
|
-
}).pipe(
|
|
1018
|
-
var initializeIgnoreRules = (fs, pathService, baseDir) =>
|
|
1862
|
+
}).pipe(import_effect20.Effect.catchAll(() => import_effect20.Effect.void));
|
|
1863
|
+
var initializeIgnoreRules = (fs, pathService, baseDir) => import_effect20.Effect.gen(function* () {
|
|
1019
1864
|
const ignoreRules = (0, import_ignore.default)();
|
|
1020
1865
|
ignoreRules.add([".git/", "**/.DS_Store", "**/Thumbs.db"]);
|
|
1021
1866
|
for (const ignoreFileName of IGNORE_FILE_NAMES) {
|
|
@@ -1030,14 +1875,14 @@ var initializeIgnoreRules = (fs, pathService, baseDir) => import_effect12.Effect
|
|
|
1030
1875
|
yield* collectIgnorePatterns(fs, pathService, baseDir, baseDir, ignoreRules);
|
|
1031
1876
|
return ignoreRules;
|
|
1032
1877
|
});
|
|
1033
|
-
var getFilesToInclude = (fs, pathService, dir, ignoreRules) =>
|
|
1878
|
+
var getFilesToInclude = (fs, pathService, dir, ignoreRules) => import_effect20.Effect.gen(function* () {
|
|
1034
1879
|
const filesToInclude = [];
|
|
1035
|
-
const walkDir = (currentDir) =>
|
|
1036
|
-
const items = yield* fs.readDirectory(currentDir).pipe(
|
|
1880
|
+
const walkDir = (currentDir) => import_effect20.Effect.gen(function* () {
|
|
1881
|
+
const items = yield* fs.readDirectory(currentDir).pipe(import_effect20.Effect.mapError(() => new ArchiveCreateError({ message: `Failed to read directory: ${currentDir}` })));
|
|
1037
1882
|
for (const item of items) {
|
|
1038
1883
|
const fullPath = pathService.join(currentDir, item);
|
|
1039
1884
|
const relativePath = pathService.relative(dir, fullPath);
|
|
1040
|
-
const stat = yield*
|
|
1885
|
+
const stat = yield* import_effect20.Effect.tryPromise({
|
|
1041
1886
|
try: () => nodeFsPromises.lstat(fullPath),
|
|
1042
1887
|
catch: () => new ArchiveCreateError({ message: `Failed to stat: ${fullPath}` })
|
|
1043
1888
|
});
|
|
@@ -1051,21 +1896,21 @@ var getFilesToInclude = (fs, pathService, dir, ignoreRules) => import_effect12.E
|
|
|
1051
1896
|
}
|
|
1052
1897
|
}
|
|
1053
1898
|
}
|
|
1054
|
-
}).pipe(
|
|
1899
|
+
}).pipe(import_effect20.Effect.catchAll(() => import_effect20.Effect.void));
|
|
1055
1900
|
yield* walkDir(dir);
|
|
1056
1901
|
return filesToInclude;
|
|
1057
1902
|
});
|
|
1058
|
-
var ArchiveService = class extends
|
|
1903
|
+
var ArchiveService = class extends import_effect20.Effect.Service()("ArchiveService", {
|
|
1059
1904
|
accessors: true,
|
|
1060
|
-
effect:
|
|
1061
|
-
const fs = yield*
|
|
1062
|
-
const pathService = yield*
|
|
1063
|
-
const createZipArchive =
|
|
1064
|
-
yield*
|
|
1065
|
-
yield*
|
|
1066
|
-
yield*
|
|
1905
|
+
effect: import_effect20.Effect.gen(function* () {
|
|
1906
|
+
const fs = yield* import_platform6.FileSystem.FileSystem;
|
|
1907
|
+
const pathService = yield* import_platform6.Path.Path;
|
|
1908
|
+
const createZipArchive = import_effect20.Effect.fn("ArchiveService.createZipArchive")(function* (inputDir, outputFile, options = {}) {
|
|
1909
|
+
yield* import_effect20.Effect.annotateCurrentSpan("inputDir", inputDir);
|
|
1910
|
+
yield* import_effect20.Effect.annotateCurrentSpan("outputFile", outputFile);
|
|
1911
|
+
yield* import_effect20.Effect.log("Creating zip archive", { inputDir, outputFile });
|
|
1067
1912
|
const ignoreRules = options.useIgnoreFiles !== false ? yield* initializeIgnoreRules(fs, pathService, inputDir) : (0, import_ignore.default)();
|
|
1068
|
-
const filesToInclude = options.whitelist ? yield*
|
|
1913
|
+
const filesToInclude = options.whitelist ? yield* import_effect20.Effect.tryPromise({
|
|
1069
1914
|
try: () => Promise.all(
|
|
1070
1915
|
options.whitelist.map((file) => (0, import_build_utils3.getFilesForPattern)(file, inputDir, options.excludeFiles ?? []))
|
|
1071
1916
|
),
|
|
@@ -1073,25 +1918,25 @@ var ArchiveService = class extends import_effect12.Effect.Service()("ArchiveServ
|
|
|
1073
1918
|
message: "Failed to resolve whitelist patterns",
|
|
1074
1919
|
cause: error instanceof Error ? error.message : String(error)
|
|
1075
1920
|
})
|
|
1076
|
-
}) : yield*
|
|
1921
|
+
}) : yield* import_effect20.Effect.gen(function* () {
|
|
1077
1922
|
if (options.excludeFiles && options.excludeFiles.length > 0) {
|
|
1078
1923
|
ignoreRules.add(options.excludeFiles);
|
|
1079
1924
|
}
|
|
1080
1925
|
return yield* getFilesToInclude(fs, pathService, inputDir, ignoreRules).pipe(
|
|
1081
|
-
|
|
1926
|
+
import_effect20.Effect.map((files) => [files])
|
|
1082
1927
|
);
|
|
1083
1928
|
});
|
|
1084
|
-
const archiveExists = yield* fs.exists(outputFile).pipe(
|
|
1929
|
+
const archiveExists = yield* fs.exists(outputFile).pipe(import_effect20.Effect.catchAll(() => import_effect20.Effect.succeed(false)));
|
|
1085
1930
|
if (archiveExists) {
|
|
1086
1931
|
yield* fs.remove(outputFile).pipe(
|
|
1087
|
-
|
|
1932
|
+
import_effect20.Effect.mapError(
|
|
1088
1933
|
(error) => new ArchiveCreateError({
|
|
1089
1934
|
message: `Failed to remove existing archive: ${String(error)}`
|
|
1090
1935
|
})
|
|
1091
1936
|
)
|
|
1092
1937
|
);
|
|
1093
1938
|
}
|
|
1094
|
-
yield*
|
|
1939
|
+
yield* import_effect20.Effect.tryPromise({
|
|
1095
1940
|
try: () => new Promise((resolve, reject) => {
|
|
1096
1941
|
const output = nodeFs.createWriteStream(outputFile);
|
|
1097
1942
|
const archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } });
|
|
@@ -1110,14 +1955,14 @@ var ArchiveService = class extends import_effect12.Effect.Service()("ArchiveServ
|
|
|
1110
1955
|
})
|
|
1111
1956
|
});
|
|
1112
1957
|
const fileInfo = yield* fs.stat(outputFile).pipe(
|
|
1113
|
-
|
|
1958
|
+
import_effect20.Effect.mapError(
|
|
1114
1959
|
(error) => new ArchiveCreateError({
|
|
1115
1960
|
message: `Failed to stat archive: ${String(error)}`
|
|
1116
1961
|
})
|
|
1117
1962
|
)
|
|
1118
1963
|
);
|
|
1119
1964
|
const size = Number(fileInfo.size);
|
|
1120
|
-
yield*
|
|
1965
|
+
yield* import_effect20.Effect.log("Archive created", { size });
|
|
1121
1966
|
return { path: outputFile, size };
|
|
1122
1967
|
});
|
|
1123
1968
|
return { createZipArchive };
|
|
@@ -1126,250 +1971,104 @@ var ArchiveService = class extends import_effect12.Effect.Service()("ArchiveServ
|
|
|
1126
1971
|
};
|
|
1127
1972
|
|
|
1128
1973
|
// src/services/deployment-api.ts
|
|
1129
|
-
var
|
|
1130
|
-
var
|
|
1131
|
-
var CreateDeploymentResponse = import_effect13.Schema.Struct({ id: import_effect13.Schema.String });
|
|
1132
|
-
var StartUploadResponse = import_effect13.Schema.Struct({ uploadId: import_effect13.Schema.String });
|
|
1133
|
-
var PresignedUrlResponse = import_effect13.Schema.Struct({ url: import_effect13.Schema.String });
|
|
1134
|
-
var DeploymentStatusResponse = import_effect13.Schema.Struct({
|
|
1135
|
-
status: import_effect13.Schema.Literal("PENDING", "BUILDING", "PROVISIONING", "FAILED", "ACTIVE", "SUSPENDED")
|
|
1136
|
-
});
|
|
1137
|
-
var DeploymentLogPageResponse = import_effect13.Schema.Struct({
|
|
1138
|
-
totalItems: import_effect13.Schema.Number,
|
|
1139
|
-
limit: import_effect13.Schema.Number,
|
|
1140
|
-
offset: import_effect13.Schema.Number,
|
|
1141
|
-
items: import_effect13.Schema.Array(
|
|
1142
|
-
import_effect13.Schema.Struct({
|
|
1143
|
-
id: import_effect13.Schema.String,
|
|
1144
|
-
message: import_effect13.Schema.String,
|
|
1145
|
-
type: import_effect13.Schema.Literal("INFO", "ERROR", "WARN"),
|
|
1146
|
-
createdAt: import_effect13.Schema.String
|
|
1147
|
-
})
|
|
1148
|
-
)
|
|
1149
|
-
});
|
|
1150
|
-
var ApiBaseUrl = import_effect13.Config.string("GIGADRIVE_API_BASE_URL").pipe(import_effect13.Config.withDefault("http://localhost:3000"));
|
|
1151
|
-
var DeploymentApiService = class extends import_effect13.Effect.Service()("DeploymentApiService", {
|
|
1974
|
+
var import_effect21 = require("effect");
|
|
1975
|
+
var DeploymentApiService = class extends import_effect21.Effect.Service()("DeploymentApiService", {
|
|
1152
1976
|
accessors: true,
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
const
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
yield*
|
|
1164
|
-
|
|
1165
|
-
const authHeaders = yield* getAuthHeaders;
|
|
1166
|
-
const response = yield* import_effect13.Effect.tryPromise({
|
|
1167
|
-
try: () => fetch(`${baseUrl}/${applicationId}/deployments`, {
|
|
1168
|
-
method: "POST",
|
|
1169
|
-
headers: { "Content-Type": "application/json", ...authHeaders },
|
|
1170
|
-
body: JSON.stringify({})
|
|
1171
|
-
}),
|
|
1977
|
+
dependencies: [ApiClientService.Default],
|
|
1978
|
+
effect: import_effect21.Effect.gen(function* () {
|
|
1979
|
+
const apiClient = yield* ApiClientService;
|
|
1980
|
+
const getClient = apiClient.getClient.pipe(
|
|
1981
|
+
import_effect21.Effect.mapError((err) => new DeploymentAuthError({ message: `Authentication failed: ${err.message}` }))
|
|
1982
|
+
);
|
|
1983
|
+
const createDeployment = import_effect21.Effect.fn("DeploymentApiService.createDeployment")(function* (applicationId) {
|
|
1984
|
+
yield* import_effect21.Effect.annotateCurrentSpan("applicationId", applicationId);
|
|
1985
|
+
yield* import_effect21.Effect.log("Creating deployment", { applicationId });
|
|
1986
|
+
const client = yield* getClient;
|
|
1987
|
+
const deployment = yield* import_effect21.Effect.tryPromise({
|
|
1988
|
+
try: () => client.deployments.create({ applicationId }),
|
|
1172
1989
|
catch: (error) => new DeploymentCreateError({
|
|
1173
1990
|
message: `Failed to create deployment: ${error instanceof Error ? error.message : String(error)}`
|
|
1174
1991
|
})
|
|
1175
1992
|
});
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
try: () => response.text(),
|
|
1179
|
-
catch: () => new DeploymentCreateError({
|
|
1180
|
-
message: "Failed to read deployment creation error",
|
|
1181
|
-
statusCode: response.status
|
|
1182
|
-
})
|
|
1183
|
-
});
|
|
1184
|
-
return yield* import_effect13.Effect.fail(
|
|
1185
|
-
new DeploymentCreateError({
|
|
1186
|
-
message: `Failed to create deployment: ${body}`,
|
|
1187
|
-
statusCode: response.status
|
|
1188
|
-
})
|
|
1189
|
-
);
|
|
1190
|
-
}
|
|
1191
|
-
const json = yield* import_effect13.Effect.tryPromise({
|
|
1192
|
-
try: () => response.json(),
|
|
1193
|
-
catch: () => new DeploymentCreateError({ message: "Failed to parse deployment response" })
|
|
1194
|
-
});
|
|
1195
|
-
const decoded = yield* import_effect13.Schema.decodeUnknown(CreateDeploymentResponse)(json).pipe(
|
|
1196
|
-
import_effect13.Effect.mapError(() => new DeploymentCreateError({ message: "Invalid deployment response schema" }))
|
|
1197
|
-
);
|
|
1198
|
-
yield* import_effect13.Effect.log("Deployment created", { deploymentId: decoded.id });
|
|
1199
|
-
return decoded.id;
|
|
1993
|
+
yield* import_effect21.Effect.log("Deployment created", { deploymentId: deployment.id });
|
|
1994
|
+
return deployment.id;
|
|
1200
1995
|
});
|
|
1201
|
-
const startMultipartUpload =
|
|
1202
|
-
yield*
|
|
1203
|
-
const
|
|
1204
|
-
const
|
|
1205
|
-
try: () =>
|
|
1206
|
-
method: "GET",
|
|
1207
|
-
headers: { "Content-Type": "application/json", ...authHeaders }
|
|
1208
|
-
}),
|
|
1996
|
+
const startMultipartUpload = import_effect21.Effect.fn("DeploymentApiService.startMultipartUpload")(function* (deploymentId) {
|
|
1997
|
+
yield* import_effect21.Effect.annotateCurrentSpan("deploymentId", deploymentId);
|
|
1998
|
+
const client = yield* getClient;
|
|
1999
|
+
const result = yield* import_effect21.Effect.tryPromise({
|
|
2000
|
+
try: () => client.deployments.startUpload(deploymentId),
|
|
1209
2001
|
catch: (error) => new UploadStartError({
|
|
1210
2002
|
message: `Failed to start multipart upload: ${error instanceof Error ? error.message : String(error)}`
|
|
1211
2003
|
})
|
|
1212
2004
|
});
|
|
1213
|
-
|
|
1214
|
-
const body = yield* import_effect13.Effect.tryPromise({
|
|
1215
|
-
try: () => response.text(),
|
|
1216
|
-
catch: () => new UploadStartError({ message: "Failed to read upload start error" })
|
|
1217
|
-
});
|
|
1218
|
-
return yield* import_effect13.Effect.fail(
|
|
1219
|
-
new UploadStartError({ message: `Failed to start multipart upload: ${body}`, statusCode: response.status })
|
|
1220
|
-
);
|
|
1221
|
-
}
|
|
1222
|
-
const json = yield* import_effect13.Effect.tryPromise({
|
|
1223
|
-
try: () => response.json(),
|
|
1224
|
-
catch: () => new UploadStartError({ message: "Failed to parse upload start response" })
|
|
1225
|
-
});
|
|
1226
|
-
const decoded = yield* import_effect13.Schema.decodeUnknown(StartUploadResponse)(json).pipe(
|
|
1227
|
-
import_effect13.Effect.mapError(() => new UploadStartError({ message: "Invalid upload start response schema" }))
|
|
1228
|
-
);
|
|
1229
|
-
return decoded.uploadId;
|
|
2005
|
+
return result.uploadId;
|
|
1230
2006
|
});
|
|
1231
|
-
const getPresignedUrl =
|
|
1232
|
-
const
|
|
1233
|
-
const
|
|
1234
|
-
try: () =>
|
|
1235
|
-
`${baseUrl}/deployments/${deploymentId}/pre-signed-url/part?uploadId=${uploadId}&partNumber=${partNumber}`,
|
|
1236
|
-
{
|
|
1237
|
-
method: "GET",
|
|
1238
|
-
headers: { "Content-Type": "application/json", ...authHeaders }
|
|
1239
|
-
}
|
|
1240
|
-
),
|
|
2007
|
+
const getPresignedUrl = import_effect21.Effect.fn("DeploymentApiService.getPresignedUrl")(function* (deploymentId, uploadId, partNumber) {
|
|
2008
|
+
const client = yield* getClient;
|
|
2009
|
+
const result = yield* import_effect21.Effect.tryPromise({
|
|
2010
|
+
try: () => client.deployments.getPresignedUrl(deploymentId, uploadId, partNumber),
|
|
1241
2011
|
catch: (error) => new PresignedUrlError({
|
|
1242
2012
|
message: `Failed to get presigned URL: ${error instanceof Error ? error.message : String(error)}`,
|
|
1243
2013
|
partNumber
|
|
1244
2014
|
})
|
|
1245
2015
|
});
|
|
1246
|
-
|
|
1247
|
-
const body = yield* import_effect13.Effect.tryPromise({
|
|
1248
|
-
try: () => response.text(),
|
|
1249
|
-
catch: () => new PresignedUrlError({ message: "Failed to read presigned URL error", partNumber })
|
|
1250
|
-
});
|
|
1251
|
-
return yield* import_effect13.Effect.fail(
|
|
1252
|
-
new PresignedUrlError({ message: `Failed to get presigned URL: ${body}`, partNumber })
|
|
1253
|
-
);
|
|
1254
|
-
}
|
|
1255
|
-
const json = yield* import_effect13.Effect.tryPromise({
|
|
1256
|
-
try: () => response.json(),
|
|
1257
|
-
catch: () => new PresignedUrlError({ message: "Failed to parse presigned URL response", partNumber })
|
|
1258
|
-
});
|
|
1259
|
-
const decoded = yield* import_effect13.Schema.decodeUnknown(PresignedUrlResponse)(json).pipe(
|
|
1260
|
-
import_effect13.Effect.mapError(() => new PresignedUrlError({ message: "Invalid presigned URL response schema", partNumber }))
|
|
1261
|
-
);
|
|
1262
|
-
return decoded.url;
|
|
2016
|
+
return result.url;
|
|
1263
2017
|
});
|
|
1264
|
-
const uploadPart =
|
|
1265
|
-
yield*
|
|
1266
|
-
yield*
|
|
1267
|
-
const
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
headers: {
|
|
1271
|
-
"Content-Type": "application/zip",
|
|
1272
|
-
"Content-Length": String(data.length)
|
|
1273
|
-
},
|
|
1274
|
-
body: data
|
|
1275
|
-
}),
|
|
2018
|
+
const uploadPart = import_effect21.Effect.fn("DeploymentApiService.uploadPart")(function* (presignedUrl, data, partNumber) {
|
|
2019
|
+
yield* import_effect21.Effect.annotateCurrentSpan("partNumber", partNumber);
|
|
2020
|
+
yield* import_effect21.Effect.annotateCurrentSpan("size", data.length);
|
|
2021
|
+
const client = yield* getClient;
|
|
2022
|
+
const result = yield* import_effect21.Effect.tryPromise({
|
|
2023
|
+
try: () => client.deployments.uploadPart(presignedUrl, data, partNumber),
|
|
1276
2024
|
catch: (error) => new UploadPartError({
|
|
1277
2025
|
message: `Failed to upload part ${partNumber}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1278
2026
|
partNumber
|
|
1279
2027
|
})
|
|
1280
2028
|
});
|
|
1281
|
-
|
|
1282
|
-
return yield* import_effect13.Effect.fail(
|
|
1283
|
-
new UploadPartError({
|
|
1284
|
-
message: `Failed to upload part ${partNumber}: ${response.statusText}`,
|
|
1285
|
-
partNumber
|
|
1286
|
-
})
|
|
1287
|
-
);
|
|
1288
|
-
}
|
|
1289
|
-
const etag = response.headers.get("ETag");
|
|
1290
|
-
if (!etag) {
|
|
1291
|
-
return yield* import_effect13.Effect.fail(
|
|
1292
|
-
new UploadPartError({ message: `No ETag received for part ${partNumber}`, partNumber })
|
|
1293
|
-
);
|
|
1294
|
-
}
|
|
1295
|
-
return { partNumber, etag };
|
|
2029
|
+
return result;
|
|
1296
2030
|
});
|
|
1297
|
-
const completeUpload =
|
|
1298
|
-
yield*
|
|
1299
|
-
yield*
|
|
1300
|
-
const
|
|
1301
|
-
|
|
1302
|
-
try: () =>
|
|
1303
|
-
method: "POST",
|
|
1304
|
-
headers: { "Content-Type": "application/json", ...authHeaders },
|
|
1305
|
-
body: JSON.stringify({ uploadId, parts })
|
|
1306
|
-
}),
|
|
2031
|
+
const completeUpload = import_effect21.Effect.fn("DeploymentApiService.completeUpload")(function* (deploymentId, uploadId, parts) {
|
|
2032
|
+
yield* import_effect21.Effect.annotateCurrentSpan("deploymentId", deploymentId);
|
|
2033
|
+
yield* import_effect21.Effect.annotateCurrentSpan("partsCount", parts.length);
|
|
2034
|
+
const client = yield* getClient;
|
|
2035
|
+
yield* import_effect21.Effect.tryPromise({
|
|
2036
|
+
try: () => client.deployments.completeUpload(deploymentId, uploadId, parts),
|
|
1307
2037
|
catch: (error) => new UploadCompleteError({
|
|
1308
2038
|
message: `Failed to complete upload: ${error instanceof Error ? error.message : String(error)}`
|
|
1309
2039
|
})
|
|
1310
2040
|
});
|
|
1311
|
-
|
|
1312
|
-
const body = yield* import_effect13.Effect.tryPromise({
|
|
1313
|
-
try: () => response.text(),
|
|
1314
|
-
catch: () => new UploadCompleteError({ message: "Failed to read upload complete error" })
|
|
1315
|
-
});
|
|
1316
|
-
return yield* import_effect13.Effect.fail(new UploadCompleteError({ message: `Failed to complete upload: ${body}` }));
|
|
1317
|
-
}
|
|
1318
|
-
yield* import_effect13.Effect.log("Upload completed successfully");
|
|
2041
|
+
yield* import_effect21.Effect.log("Upload completed successfully");
|
|
1319
2042
|
});
|
|
1320
|
-
const getDeploymentStatus =
|
|
1321
|
-
const
|
|
1322
|
-
const
|
|
1323
|
-
try: () =>
|
|
1324
|
-
method: "GET",
|
|
1325
|
-
headers: { "Content-Type": "application/json", ...authHeaders }
|
|
1326
|
-
}),
|
|
2043
|
+
const getDeploymentStatus = import_effect21.Effect.fn("DeploymentApiService.getDeploymentStatus")(function* (deploymentId) {
|
|
2044
|
+
const client = yield* getClient;
|
|
2045
|
+
const deployment = yield* import_effect21.Effect.tryPromise({
|
|
2046
|
+
try: () => client.deployments.get(deploymentId),
|
|
1327
2047
|
catch: (error) => new DeploymentStatusError({
|
|
1328
2048
|
message: `Failed to get deployment status: ${error instanceof Error ? error.message : String(error)}`
|
|
1329
2049
|
})
|
|
1330
2050
|
});
|
|
1331
|
-
|
|
1332
|
-
const body = yield* import_effect13.Effect.tryPromise({
|
|
1333
|
-
try: () => response.text(),
|
|
1334
|
-
catch: () => new DeploymentStatusError({ message: "Failed to read deployment status error" })
|
|
1335
|
-
});
|
|
1336
|
-
return yield* import_effect13.Effect.fail(new DeploymentStatusError({ message: `Failed to get deployment status: ${body}` }));
|
|
1337
|
-
}
|
|
1338
|
-
const json = yield* import_effect13.Effect.tryPromise({
|
|
1339
|
-
try: () => response.json(),
|
|
1340
|
-
catch: () => new DeploymentStatusError({ message: "Failed to parse deployment status response" })
|
|
1341
|
-
});
|
|
1342
|
-
const decoded = yield* import_effect13.Schema.decodeUnknown(DeploymentStatusResponse)(json).pipe(
|
|
1343
|
-
import_effect13.Effect.mapError(() => new DeploymentStatusError({ message: "Invalid deployment status response schema" }))
|
|
1344
|
-
);
|
|
1345
|
-
return decoded.status;
|
|
2051
|
+
return deployment.status;
|
|
1346
2052
|
});
|
|
1347
|
-
const getLogs =
|
|
1348
|
-
const
|
|
1349
|
-
const
|
|
1350
|
-
try: () =>
|
|
1351
|
-
method: "GET",
|
|
1352
|
-
headers: { "Content-Type": "application/json", ...authHeaders }
|
|
1353
|
-
}),
|
|
2053
|
+
const getLogs = import_effect21.Effect.fn("DeploymentApiService.getLogs")(function* (deploymentId, options) {
|
|
2054
|
+
const client = yield* getClient;
|
|
2055
|
+
const result = yield* import_effect21.Effect.tryPromise({
|
|
2056
|
+
try: () => client.deployments.getLogs(deploymentId, options),
|
|
1354
2057
|
catch: (error) => new DeploymentLogsFetchError({
|
|
1355
2058
|
message: `Failed to get logs: ${error instanceof Error ? error.message : String(error)}`
|
|
1356
2059
|
})
|
|
1357
2060
|
});
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
catch: () => new DeploymentLogsFetchError({ message: "Failed to parse logs response" })
|
|
2061
|
+
return result;
|
|
2062
|
+
});
|
|
2063
|
+
const getHostnames = import_effect21.Effect.fn("DeploymentApiService.getHostnames")(function* (deploymentId) {
|
|
2064
|
+
const client = yield* getClient;
|
|
2065
|
+
const result = yield* import_effect21.Effect.tryPromise({
|
|
2066
|
+
try: () => client.deployments.getHostnames(deploymentId),
|
|
2067
|
+
catch: (error) => new DeploymentHostnamesFetchError({
|
|
2068
|
+
message: `Failed to get hostnames: ${error instanceof Error ? error.message : String(error)}`
|
|
2069
|
+
})
|
|
1368
2070
|
});
|
|
1369
|
-
|
|
1370
|
-
import_effect13.Effect.mapError(() => new DeploymentLogsFetchError({ message: "Invalid logs response schema" }))
|
|
1371
|
-
);
|
|
1372
|
-
return decoded;
|
|
2071
|
+
return result.items;
|
|
1373
2072
|
});
|
|
1374
2073
|
return {
|
|
1375
2074
|
createDeployment,
|
|
@@ -1378,28 +2077,39 @@ var DeploymentApiService = class extends import_effect13.Effect.Service()("Deplo
|
|
|
1378
2077
|
uploadPart,
|
|
1379
2078
|
completeUpload,
|
|
1380
2079
|
getDeploymentStatus,
|
|
1381
|
-
getLogs
|
|
2080
|
+
getLogs,
|
|
2081
|
+
getHostnames
|
|
1382
2082
|
};
|
|
1383
2083
|
})
|
|
1384
2084
|
}) {
|
|
1385
2085
|
};
|
|
1386
2086
|
|
|
1387
2087
|
// src/commands/platform/deploy/index.ts
|
|
1388
|
-
var
|
|
2088
|
+
var appOption5 = import_cli11.Options.text("app").pipe(
|
|
2089
|
+
import_cli11.Options.withAlias("a"),
|
|
2090
|
+
import_cli11.Options.withDescription("Application ID to deploy to (overrides the linked application)"),
|
|
2091
|
+
import_cli11.Options.optional
|
|
2092
|
+
);
|
|
2093
|
+
var deployCommand = import_cli11.Command.make(
|
|
1389
2094
|
"deploy",
|
|
1390
|
-
{},
|
|
1391
|
-
() =>
|
|
2095
|
+
{ app: appOption5 },
|
|
2096
|
+
({ app }) => import_effect22.Effect.gen(function* () {
|
|
1392
2097
|
const projectConfig = yield* ProjectConfigService;
|
|
1393
2098
|
const deploymentApi = yield* DeploymentApiService;
|
|
1394
2099
|
const archiveService = yield* ArchiveService;
|
|
1395
|
-
const
|
|
2100
|
+
const projectLink = yield* ProjectLinkService;
|
|
2101
|
+
const pathService = yield* import_platform7.Path.Path;
|
|
1396
2102
|
const cwd = process.cwd();
|
|
1397
|
-
yield*
|
|
2103
|
+
const applicationId = yield* import_effect22.Option.match(app, {
|
|
2104
|
+
onSome: (id) => import_effect22.Effect.succeed(id),
|
|
2105
|
+
onNone: () => projectLink.resolve(cwd).pipe(import_effect22.Effect.map((link) => link.applicationId))
|
|
2106
|
+
});
|
|
2107
|
+
yield* import_effect22.Effect.log("Starting deploy command");
|
|
1398
2108
|
const { config } = yield* projectConfig.resolve(cwd);
|
|
1399
|
-
yield*
|
|
1400
|
-
const deploymentId = yield* deploymentApi.createDeployment(
|
|
1401
|
-
yield*
|
|
1402
|
-
yield*
|
|
2109
|
+
yield* import_effect22.Console.log("Creating deployment...");
|
|
2110
|
+
const deploymentId = yield* deploymentApi.createDeployment(applicationId);
|
|
2111
|
+
yield* import_effect22.Console.log(`Deployment ID: ${deploymentId}`);
|
|
2112
|
+
yield* import_effect22.Console.log("Creating archive...");
|
|
1403
2113
|
const archivePath = pathService.join(os2.tmpdir(), `project-${Date.now()}.zip`);
|
|
1404
2114
|
const archive = yield* archiveService.createZipArchive(config.userArchive?.rootOverwrite || cwd, archivePath, {
|
|
1405
2115
|
whitelist: config.userArchive?.fileWhitelist,
|
|
@@ -1407,60 +2117,62 @@ var deployCommand = import_cli5.Command.make(
|
|
|
1407
2117
|
useIgnoreFiles: false,
|
|
1408
2118
|
useManagedIgnore: false
|
|
1409
2119
|
});
|
|
1410
|
-
yield*
|
|
1411
|
-
yield*
|
|
2120
|
+
yield* import_effect22.Console.log(`Archive created (${(0, import_commons.formatFileSize)(archive.size)})`);
|
|
2121
|
+
yield* import_effect22.Console.log("Uploading archive...");
|
|
1412
2122
|
yield* uploadArchive(deploymentId, archivePath, archive.size);
|
|
1413
|
-
yield*
|
|
1414
|
-
yield*
|
|
2123
|
+
yield* import_effect22.Console.log("Upload complete.");
|
|
2124
|
+
yield* import_effect22.Console.log("The deployment pipeline is now being provisioned. This may take a few seconds.");
|
|
1415
2125
|
yield* pollDeployment(deploymentId);
|
|
1416
2126
|
}).pipe(
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
2127
|
+
import_effect22.Effect.catchTags({
|
|
2128
|
+
ProjectNotLinkedError: (err) => import_effect22.Console.error(err.message).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2129
|
+
ProjectLinkReadError: (err) => import_effect22.Console.error(err.message).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2130
|
+
ConfigNotFoundError: (err) => import_effect22.Console.error(err.message).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2131
|
+
ConfigParseError: (err) => import_effect22.Console.error(`Config parse error: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2132
|
+
ConfigValidationError: (err) => import_effect22.Effect.gen(function* () {
|
|
1421
2133
|
for (const e of err.errors) {
|
|
1422
|
-
yield*
|
|
2134
|
+
yield* import_effect22.Console.error(e);
|
|
1423
2135
|
}
|
|
1424
|
-
yield*
|
|
1425
|
-
}).pipe(
|
|
1426
|
-
DeploymentCreateError: (err) =>
|
|
1427
|
-
ArchiveCreateError: (err) =>
|
|
1428
|
-
UploadStartError: (err) =>
|
|
1429
|
-
UploadPartError: (err) =>
|
|
1430
|
-
UploadCompleteError: (err) =>
|
|
1431
|
-
PresignedUrlError: (err) =>
|
|
1432
|
-
DeploymentAuthError: (err) =>
|
|
1433
|
-
DeploymentFailedError: (err) =>
|
|
2136
|
+
yield* import_effect22.Console.error(err.message);
|
|
2137
|
+
}).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2138
|
+
DeploymentCreateError: (err) => import_effect22.Console.error(`Deployment creation failed: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2139
|
+
ArchiveCreateError: (err) => import_effect22.Console.error(`Archive creation failed: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2140
|
+
UploadStartError: (err) => import_effect22.Console.error(`Upload failed: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2141
|
+
UploadPartError: (err) => import_effect22.Console.error(`Upload failed: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2142
|
+
UploadCompleteError: (err) => import_effect22.Console.error(`Upload failed: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2143
|
+
PresignedUrlError: (err) => import_effect22.Console.error(`Upload failed: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2144
|
+
DeploymentAuthError: (err) => import_effect22.Console.error(`Authentication failed: ${err.message}`).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err))),
|
|
2145
|
+
DeploymentFailedError: (err) => import_effect22.Console.error(err.message).pipe(import_effect22.Effect.andThen(import_effect22.Effect.fail(err)))
|
|
1434
2146
|
})
|
|
1435
2147
|
)
|
|
1436
2148
|
);
|
|
1437
|
-
var uploadArchive = (deploymentId, archivePath, fileSize) =>
|
|
2149
|
+
var uploadArchive = (deploymentId, archivePath, fileSize) => import_effect22.Effect.gen(function* () {
|
|
1438
2150
|
const deploymentApi = yield* DeploymentApiService;
|
|
1439
|
-
const fs = yield*
|
|
2151
|
+
const fs = yield* import_platform7.FileSystem.FileSystem;
|
|
1440
2152
|
const uploadId = yield* deploymentApi.startMultipartUpload(deploymentId);
|
|
1441
2153
|
const FILE_CHUNK_SIZE = 10 * 1024 * 1024;
|
|
1442
2154
|
const numChunks = Math.ceil(fileSize / FILE_CHUNK_SIZE);
|
|
1443
|
-
yield*
|
|
1444
|
-
const parts = yield*
|
|
2155
|
+
yield* import_effect22.Effect.log("Starting multipart upload", { uploadId, numChunks, fileSize });
|
|
2156
|
+
const parts = yield* import_effect22.Effect.all(
|
|
1445
2157
|
Array.from({ length: numChunks }, (_, i) => {
|
|
1446
2158
|
const partNumber = i + 1;
|
|
1447
2159
|
const start = i * FILE_CHUNK_SIZE;
|
|
1448
2160
|
const bytesToRead = partNumber < numChunks ? FILE_CHUNK_SIZE : fileSize - start;
|
|
1449
|
-
return
|
|
2161
|
+
return import_effect22.Effect.gen(function* () {
|
|
1450
2162
|
const presignedUrl = yield* deploymentApi.getPresignedUrl(deploymentId, uploadId, partNumber);
|
|
1451
|
-
const chunkData = yield*
|
|
1452
|
-
|
|
2163
|
+
const chunkData = yield* import_effect22.Stream.runCollect(fs.stream(archivePath, { offset: start, bytesToRead })).pipe(
|
|
2164
|
+
import_effect22.Effect.map((chunks) => {
|
|
1453
2165
|
const arrays = Array.from(chunks);
|
|
1454
2166
|
return Buffer.concat(arrays);
|
|
1455
2167
|
}),
|
|
1456
|
-
|
|
2168
|
+
import_effect22.Effect.mapError(
|
|
1457
2169
|
(error) => new UploadPartError({
|
|
1458
2170
|
message: `Failed to read chunk ${partNumber}: ${String(error)}`,
|
|
1459
2171
|
partNumber
|
|
1460
2172
|
})
|
|
1461
2173
|
)
|
|
1462
2174
|
);
|
|
1463
|
-
yield*
|
|
2175
|
+
yield* import_effect22.Effect.log(`Uploading part ${partNumber}/${numChunks}`, { size: chunkData.length });
|
|
1464
2176
|
return yield* deploymentApi.uploadPart(presignedUrl, chunkData, partNumber);
|
|
1465
2177
|
});
|
|
1466
2178
|
}),
|
|
@@ -1468,20 +2180,20 @@ var uploadArchive = (deploymentId, archivePath, fileSize) => import_effect14.Eff
|
|
|
1468
2180
|
);
|
|
1469
2181
|
yield* deploymentApi.completeUpload(deploymentId, uploadId, parts);
|
|
1470
2182
|
});
|
|
1471
|
-
var pollDeployment = (deploymentId) =>
|
|
2183
|
+
var pollDeployment = (deploymentId) => import_effect22.Effect.gen(function* () {
|
|
1472
2184
|
const deploymentApi = yield* DeploymentApiService;
|
|
1473
2185
|
let lastStatus = "PENDING";
|
|
1474
2186
|
let logOffset = 0;
|
|
1475
|
-
yield*
|
|
1476
|
-
yield*
|
|
1477
|
-
|
|
1478
|
-
const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(
|
|
2187
|
+
yield* import_effect22.Console.log("Status: Pending");
|
|
2188
|
+
yield* import_effect22.Effect.repeat(
|
|
2189
|
+
import_effect22.Effect.gen(function* () {
|
|
2190
|
+
const newStatus = yield* deploymentApi.getDeploymentStatus(deploymentId).pipe(import_effect22.Effect.catchTag("DeploymentStatusError", () => import_effect22.Effect.succeed(lastStatus)));
|
|
1479
2191
|
if (newStatus !== lastStatus) {
|
|
1480
2192
|
lastStatus = newStatus;
|
|
1481
2193
|
const label = newStatus.charAt(0) + newStatus.slice(1).toLowerCase();
|
|
1482
|
-
yield*
|
|
2194
|
+
yield* import_effect22.Console.log(`Status: ${label}`);
|
|
1483
2195
|
}
|
|
1484
|
-
const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(
|
|
2196
|
+
const logsPage = yield* deploymentApi.getLogs(deploymentId, { offset: logOffset, limit: 100 }).pipe(import_effect22.Effect.catchTag("DeploymentLogsFetchError", () => import_effect22.Effect.succeed(null)));
|
|
1485
2197
|
if (logsPage) {
|
|
1486
2198
|
for (const logEntry of logsPage.items) {
|
|
1487
2199
|
logOffset++;
|
|
@@ -1489,79 +2201,100 @@ var pollDeployment = (deploymentId) => import_effect14.Effect.gen(function* () {
|
|
|
1489
2201
|
}
|
|
1490
2202
|
}
|
|
1491
2203
|
if (newStatus === "ACTIVE") {
|
|
1492
|
-
yield*
|
|
1493
|
-
|
|
2204
|
+
const hostnames = yield* deploymentApi.getHostnames(deploymentId).pipe(import_effect22.Effect.catchTag("DeploymentHostnamesFetchError", () => import_effect22.Effect.succeed([])));
|
|
2205
|
+
const active = hostnames.find((h) => h.active) ?? hostnames.at(0);
|
|
2206
|
+
if (active) {
|
|
2207
|
+
yield* import_effect22.Console.log(`Deployed to https://${active.hostname}`);
|
|
2208
|
+
} else {
|
|
2209
|
+
yield* import_effect22.Console.log("Deployment is live.");
|
|
2210
|
+
}
|
|
2211
|
+
return yield* import_effect22.Effect.fail("done");
|
|
1494
2212
|
}
|
|
1495
2213
|
if (newStatus === "FAILED") {
|
|
1496
|
-
return yield*
|
|
2214
|
+
return yield* import_effect22.Effect.fail(
|
|
1497
2215
|
new DeploymentFailedError({
|
|
1498
2216
|
message: "The deployment failed. Please check the logs for more information."
|
|
1499
2217
|
})
|
|
1500
2218
|
);
|
|
1501
2219
|
}
|
|
1502
2220
|
}),
|
|
1503
|
-
|
|
2221
|
+
import_effect22.Schedule.addDelay(import_effect22.Schedule.forever, () => import_effect22.Duration.seconds(1))
|
|
1504
2222
|
).pipe(
|
|
1505
|
-
|
|
1506
|
-
if (err === "done") return
|
|
1507
|
-
return
|
|
2223
|
+
import_effect22.Effect.catchAll((err) => {
|
|
2224
|
+
if (err === "done") return import_effect22.Effect.void;
|
|
2225
|
+
return import_effect22.Effect.fail(err);
|
|
1508
2226
|
})
|
|
1509
2227
|
);
|
|
1510
2228
|
});
|
|
1511
2229
|
var printLog = (logEntry) => {
|
|
1512
2230
|
switch (logEntry.type) {
|
|
1513
2231
|
case "ERROR":
|
|
1514
|
-
return
|
|
2232
|
+
return import_effect22.Console.error(logEntry.message);
|
|
1515
2233
|
case "WARN":
|
|
1516
|
-
return
|
|
2234
|
+
return import_effect22.Console.warn(logEntry.message);
|
|
1517
2235
|
default:
|
|
1518
|
-
return
|
|
2236
|
+
return import_effect22.Console.log(logEntry.message);
|
|
1519
2237
|
}
|
|
1520
2238
|
};
|
|
1521
2239
|
|
|
1522
2240
|
// src/commands/platform/index.ts
|
|
1523
|
-
var platformBase =
|
|
1524
|
-
var platformCommand = platformBase.pipe(
|
|
2241
|
+
var platformBase = import_cli12.Command.make("platform", {}, () => import_effect23.Effect.void);
|
|
2242
|
+
var platformCommand = platformBase.pipe(import_cli12.Command.withSubcommands([deployCommand]));
|
|
1525
2243
|
|
|
1526
2244
|
// src/commands/whoami/index.ts
|
|
1527
|
-
var
|
|
1528
|
-
var
|
|
1529
|
-
var whoamiCommand =
|
|
2245
|
+
var import_cli13 = require("@effect/cli");
|
|
2246
|
+
var import_effect24 = require("effect");
|
|
2247
|
+
var whoamiCommand = import_cli13.Command.make(
|
|
1530
2248
|
"whoami",
|
|
1531
2249
|
{},
|
|
1532
|
-
() =>
|
|
2250
|
+
() => import_effect24.Effect.gen(function* () {
|
|
1533
2251
|
const auth = yield* AuthService;
|
|
1534
2252
|
const info = yield* auth.getUserInfo;
|
|
1535
|
-
yield*
|
|
2253
|
+
yield* import_effect24.Console.log(JSON.stringify(info, null, 2));
|
|
1536
2254
|
}).pipe(
|
|
1537
|
-
|
|
1538
|
-
NotAuthenticatedError: () =>
|
|
1539
|
-
UserInfoFetchError: (err) =>
|
|
1540
|
-
OAuthDiscoveryError: (err) =>
|
|
2255
|
+
import_effect24.Effect.catchTags({
|
|
2256
|
+
NotAuthenticatedError: () => import_effect24.Console.log('You are not logged in. Run "gigadrive login" to authenticate.'),
|
|
2257
|
+
UserInfoFetchError: (err) => import_effect24.Console.error(`Failed to retrieve user info: ${err.message}`),
|
|
2258
|
+
OAuthDiscoveryError: (err) => import_effect24.Console.error(`Failed to retrieve user info: ${err.message}`)
|
|
1541
2259
|
})
|
|
1542
2260
|
)
|
|
1543
2261
|
);
|
|
1544
2262
|
|
|
1545
2263
|
// src/index.ts
|
|
1546
|
-
var gigadrive =
|
|
1547
|
-
|
|
2264
|
+
var gigadrive = import_cli14.Command.make("gigadrive", {}, () => import_effect25.Effect.void).pipe(
|
|
2265
|
+
import_cli14.Command.withSubcommands([
|
|
2266
|
+
loginCommand,
|
|
2267
|
+
logoutCommand,
|
|
2268
|
+
whoamiCommand,
|
|
2269
|
+
linkCommand,
|
|
2270
|
+
unlinkCommand,
|
|
2271
|
+
appsCommand,
|
|
2272
|
+
envCommand,
|
|
2273
|
+
deploymentsCommand,
|
|
2274
|
+
aiCommand,
|
|
2275
|
+
buildCommand,
|
|
2276
|
+
debugCommand,
|
|
2277
|
+
platformCommand
|
|
2278
|
+
])
|
|
1548
2279
|
);
|
|
1549
|
-
var cli =
|
|
2280
|
+
var cli = import_cli14.Command.run(gigadrive, {
|
|
1550
2281
|
name: "Gigadrive CLI",
|
|
1551
|
-
version:
|
|
2282
|
+
version: package_default.version
|
|
1552
2283
|
});
|
|
1553
|
-
var BaseServices =
|
|
2284
|
+
var BaseServices = import_effect25.Layer.mergeAll(
|
|
1554
2285
|
OAuthConfigService.Default,
|
|
1555
2286
|
AuthStorageService.Default,
|
|
1556
2287
|
PackageManagerService.Default,
|
|
1557
2288
|
ArchiveService.Default,
|
|
1558
2289
|
import_network_config2.NetworkConfigLive,
|
|
1559
|
-
ProjectConfigService.Default
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
var
|
|
1563
|
-
var
|
|
1564
|
-
|
|
2290
|
+
ProjectConfigService.Default,
|
|
2291
|
+
ProjectLinkService.Default
|
|
2292
|
+
).pipe(import_effect25.Layer.provideMerge(AuthService.Default));
|
|
2293
|
+
var ApiClientLive = import_effect25.Layer.provide(ApiClientService.Default, BaseServices);
|
|
2294
|
+
var DeploymentApiLive = import_effect25.Layer.provide(DeploymentApiService.Default, BaseServices);
|
|
2295
|
+
var ServicesLive = import_effect25.Layer.mergeAll(BaseServices, ApiClientLive, DeploymentApiLive);
|
|
2296
|
+
var AppLive = import_effect25.Layer.mergeAll(ServicesLive, import_effect25.Logger.minimumLogLevel(import_effect25.LogLevel.Info)).pipe(
|
|
2297
|
+
import_effect25.Layer.provideMerge(import_platform_node.NodeContext.layer)
|
|
1565
2298
|
);
|
|
1566
|
-
import_platform_node.NodeRuntime.runMain(
|
|
2299
|
+
import_platform_node.NodeRuntime.runMain(import_effect25.Effect.provide(cli(process.argv), AppLive));
|
|
1567
2300
|
//# sourceMappingURL=index.cjs.map
|