@clef-sh/cloud 0.1.18-beta.85

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.js ADDED
@@ -0,0 +1,522 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ CLOUD_DEFAULT_ENDPOINT: () => CLOUD_DEFAULT_ENDPOINT,
34
+ CloudApiError: () => CloudApiError,
35
+ CloudArtifactClient: () => CloudArtifactClient,
36
+ CloudClient: () => CloudClient,
37
+ CloudPackClient: () => CloudPackClient,
38
+ createCloudSopsClient: () => createCloudSopsClient,
39
+ initiateDeviceFlow: () => initiateDeviceFlow,
40
+ pollDeviceFlow: () => pollDeviceFlow,
41
+ readCloudCredentials: () => readCloudCredentials,
42
+ refreshAccessToken: () => refreshAccessToken,
43
+ resetKeyserviceResolution: () => resetKeyserviceResolution,
44
+ resolveAccessToken: () => resolveAccessToken,
45
+ resolveKeyservicePath: () => resolveKeyservicePath,
46
+ spawnKeyservice: () => spawnKeyservice,
47
+ writeCloudCredentials: () => writeCloudCredentials
48
+ });
49
+ module.exports = __toCommonJS(index_exports);
50
+
51
+ // src/keyservice.ts
52
+ var import_child_process = require("child_process");
53
+ var readline = __toESM(require("readline"));
54
+ var PORT_REGEX = /^PORT=(\d+)$/;
55
+ var STARTUP_TIMEOUT_MS = 5e3;
56
+ var SHUTDOWN_TIMEOUT_MS = 3e3;
57
+ async function spawnKeyservice(options) {
58
+ const args = ["--addr", "127.0.0.1:0"];
59
+ if (options.endpoint) {
60
+ args.push("--endpoint", options.endpoint);
61
+ }
62
+ const child = (0, import_child_process.spawn)(options.binaryPath, args, {
63
+ stdio: ["ignore", "pipe", "pipe"],
64
+ env: { ...process.env, CLEF_CLOUD_TOKEN: options.token }
65
+ });
66
+ const port = await readPort(child);
67
+ const addr = `tcp://127.0.0.1:${port}`;
68
+ return {
69
+ addr,
70
+ kill: () => killGracefully(child)
71
+ };
72
+ }
73
+ function readPort(child) {
74
+ return new Promise((resolve, reject) => {
75
+ let settled = false;
76
+ const rl = readline.createInterface({ input: child.stdout });
77
+ function settle() {
78
+ clearTimeout(timer);
79
+ rl.close();
80
+ }
81
+ const timer = setTimeout(() => {
82
+ if (!settled) {
83
+ settled = true;
84
+ settle();
85
+ child.kill("SIGKILL");
86
+ reject(new Error("Keyservice did not start within 5 seconds."));
87
+ }
88
+ }, STARTUP_TIMEOUT_MS);
89
+ rl.on("line", (line) => {
90
+ const match = PORT_REGEX.exec(line);
91
+ if (match && !settled) {
92
+ settled = true;
93
+ settle();
94
+ resolve(parseInt(match[1], 10));
95
+ }
96
+ });
97
+ child.on("error", (err) => {
98
+ if (!settled) {
99
+ settled = true;
100
+ settle();
101
+ reject(new Error(`Failed to start keyservice: ${err.message}`));
102
+ }
103
+ });
104
+ child.on("exit", (code) => {
105
+ if (!settled) {
106
+ settled = true;
107
+ settle();
108
+ reject(new Error(`Keyservice exited unexpectedly with code ${code}.`));
109
+ }
110
+ });
111
+ });
112
+ }
113
+ function killGracefully(child) {
114
+ return new Promise((resolve) => {
115
+ if (child.exitCode !== null) {
116
+ resolve();
117
+ return;
118
+ }
119
+ const timer = setTimeout(() => {
120
+ child.kill("SIGKILL");
121
+ }, SHUTDOWN_TIMEOUT_MS);
122
+ child.on("exit", () => {
123
+ clearTimeout(timer);
124
+ resolve();
125
+ });
126
+ child.kill("SIGTERM");
127
+ });
128
+ }
129
+
130
+ // src/resolver.ts
131
+ var fs2 = __toESM(require("fs"));
132
+ var path2 = __toESM(require("path"));
133
+
134
+ // src/bundled.ts
135
+ var fs = __toESM(require("fs"));
136
+ var path = __toESM(require("path"));
137
+ function tryBundledKeyservice() {
138
+ const platform = process.platform;
139
+ const arch = process.arch;
140
+ const archName = arch === "x64" ? "x64" : arch === "arm64" ? "arm64" : null;
141
+ if (!archName) return null;
142
+ const platformName = platform === "darwin" ? "darwin" : platform === "linux" ? "linux" : platform === "win32" ? "win32" : null;
143
+ if (!platformName) return null;
144
+ const packageName = `@clef-sh/keyservice-${platformName}-${archName}`;
145
+ const binName = platform === "win32" ? "clef-keyservice.exe" : "clef-keyservice";
146
+ try {
147
+ const packageMain = require.resolve(`${packageName}/package.json`);
148
+ const packageDir = path.dirname(packageMain);
149
+ const binPath = path.join(packageDir, "bin", binName);
150
+ return fs.existsSync(binPath) ? binPath : null;
151
+ } catch {
152
+ return null;
153
+ }
154
+ }
155
+
156
+ // src/resolver.ts
157
+ function validateKeyservicePath(candidate) {
158
+ if (!path2.isAbsolute(candidate)) {
159
+ throw new Error(`CLEF_KEYSERVICE_PATH must be an absolute path, got '${candidate}'.`);
160
+ }
161
+ const segments = candidate.split(/[/\\]/);
162
+ if (segments.includes("..")) {
163
+ throw new Error(
164
+ `CLEF_KEYSERVICE_PATH contains '..' path segments ('${candidate}'). Use an absolute path without directory traversal.`
165
+ );
166
+ }
167
+ }
168
+ var cached;
169
+ function resolveKeyservicePath() {
170
+ if (cached) return cached;
171
+ const envPath = process.env.CLEF_KEYSERVICE_PATH?.trim();
172
+ if (envPath) {
173
+ validateKeyservicePath(envPath);
174
+ if (!fs2.existsSync(envPath)) {
175
+ throw new Error(`CLEF_KEYSERVICE_PATH points to '${envPath}' but the file does not exist.`);
176
+ }
177
+ cached = { path: envPath, source: "env" };
178
+ return cached;
179
+ }
180
+ const bundledPath = tryBundledKeyservice();
181
+ if (bundledPath) {
182
+ cached = { path: bundledPath, source: "bundled" };
183
+ return cached;
184
+ }
185
+ cached = { path: "clef-keyservice", source: "system" };
186
+ return cached;
187
+ }
188
+ function resetKeyserviceResolution() {
189
+ cached = void 0;
190
+ }
191
+
192
+ // src/credentials.ts
193
+ var fs3 = __toESM(require("fs"));
194
+ var path3 = __toESM(require("path"));
195
+ var os = __toESM(require("os"));
196
+ var YAML = __toESM(require("yaml"));
197
+
198
+ // src/constants.ts
199
+ var CLOUD_DEFAULT_ENDPOINT = "https://api.clef.sh";
200
+
201
+ // src/credentials.ts
202
+ var CREDENTIALS_FILENAME = "credentials.yaml";
203
+ function readCloudCredentials() {
204
+ const credPath = path3.join(os.homedir(), ".clef", CREDENTIALS_FILENAME);
205
+ let raw;
206
+ try {
207
+ raw = YAML.parse(fs3.readFileSync(credPath, "utf-8"));
208
+ } catch {
209
+ return null;
210
+ }
211
+ if (!raw || typeof raw !== "object") return null;
212
+ const obj = raw;
213
+ const refreshToken = typeof obj.refreshToken === "string" ? obj.refreshToken : "";
214
+ const accessToken = typeof obj.accessToken === "string" ? obj.accessToken : void 0;
215
+ const accessTokenExpiry = typeof obj.accessTokenExpiry === "number" ? obj.accessTokenExpiry : void 0;
216
+ const endpoint = typeof obj.endpoint === "string" ? obj.endpoint : CLOUD_DEFAULT_ENDPOINT;
217
+ const cognitoDomain = typeof obj.cognitoDomain === "string" ? obj.cognitoDomain : void 0;
218
+ const clientId = typeof obj.clientId === "string" ? obj.clientId : void 0;
219
+ if (!refreshToken && endpoint === CLOUD_DEFAULT_ENDPOINT) return null;
220
+ return { refreshToken, accessToken, accessTokenExpiry, endpoint, cognitoDomain, clientId };
221
+ }
222
+ function writeCloudCredentials(credentials) {
223
+ const clefDir = path3.join(os.homedir(), ".clef");
224
+ fs3.mkdirSync(clefDir, { recursive: true, mode: 448 });
225
+ const credPath = path3.join(clefDir, CREDENTIALS_FILENAME);
226
+ const content = Object.fromEntries(
227
+ Object.entries(credentials).filter(([, v]) => v !== void 0)
228
+ );
229
+ fs3.writeFileSync(credPath, YAML.stringify(content), { mode: 384 });
230
+ }
231
+
232
+ // src/device-flow.ts
233
+ async function initiateDeviceFlow(endpoint, options) {
234
+ const base = endpoint ?? CLOUD_DEFAULT_ENDPOINT;
235
+ const payload = {
236
+ clientType: "cli",
237
+ clientVersion: options.clientVersion,
238
+ repoName: options.repoName,
239
+ flow: options.flow
240
+ };
241
+ if (options.environment) {
242
+ payload.environment = options.environment;
243
+ }
244
+ let res;
245
+ try {
246
+ res = await fetch(`${base}/api/v1/device/init`, {
247
+ method: "POST",
248
+ headers: { "Content-Type": "application/json" },
249
+ body: JSON.stringify(payload)
250
+ });
251
+ } catch (err) {
252
+ const cause = err instanceof Error ? err.cause : void 0;
253
+ const reason = cause instanceof Error ? cause.message : err instanceof Error ? err.message : String(err);
254
+ throw new Error(`Could not reach Clef Cloud at ${base}: ${reason}`);
255
+ }
256
+ if (!res.ok) {
257
+ const body = await res.text().catch(() => "");
258
+ throw new Error(`Device flow init failed (${res.status}): ${body}`);
259
+ }
260
+ const json = await res.json();
261
+ const session = json.data ?? json;
262
+ if (session.pollUrl && !session.pollUrl.startsWith("http")) {
263
+ session.pollUrl = `${base}${session.pollUrl}`;
264
+ }
265
+ return session;
266
+ }
267
+ async function pollDeviceFlow(pollUrl) {
268
+ let res;
269
+ try {
270
+ res = await fetch(pollUrl);
271
+ } catch (err) {
272
+ const cause = err instanceof Error ? err.cause : void 0;
273
+ const reason = cause instanceof Error ? cause.message : err instanceof Error ? err.message : String(err);
274
+ throw new Error(`Could not reach Clef Cloud poll endpoint: ${reason}`);
275
+ }
276
+ if (!res.ok) {
277
+ const body = await res.text().catch(() => "");
278
+ throw new Error(`Device flow poll failed (${res.status}): ${body}`);
279
+ }
280
+ const json = await res.json();
281
+ return json.data ?? json;
282
+ }
283
+
284
+ // src/pack-client.ts
285
+ var fs4 = __toESM(require("fs"));
286
+ var path4 = __toESM(require("path"));
287
+ var import_core = require("@clef-sh/core");
288
+ var CloudPackClient = class {
289
+ endpoint;
290
+ constructor(endpoint) {
291
+ this.endpoint = endpoint ?? CLOUD_DEFAULT_ENDPOINT;
292
+ }
293
+ async pack(token, config) {
294
+ const matrixManager = new import_core.MatrixManager();
295
+ const cells = matrixManager.resolveMatrix(config.manifest, config.repoRoot).filter((c) => c.environment === config.environment && c.exists);
296
+ const formData = new FormData();
297
+ const configJson = JSON.stringify({
298
+ identity: config.identity,
299
+ environment: config.environment,
300
+ ...config.ttl ? { ttl: config.ttl } : {}
301
+ });
302
+ formData.append("config", new Blob([configJson], { type: "application/json" }));
303
+ const manifestPath = path4.join(config.repoRoot, "clef.yaml");
304
+ const manifestContent = fs4.readFileSync(manifestPath, "utf-8");
305
+ formData.append("manifest", new Blob([manifestContent], { type: "text/yaml" }));
306
+ for (const cell of cells) {
307
+ const relPath = path4.relative(config.repoRoot, cell.filePath);
308
+ const content = fs4.readFileSync(cell.filePath, "utf-8");
309
+ formData.append(`files`, new Blob([content], { type: "text/yaml" }), relPath);
310
+ }
311
+ const res = await fetch(`${this.endpoint}/api/v1/cloud/pack`, {
312
+ method: "POST",
313
+ headers: { Authorization: `Bearer ${token}` },
314
+ body: formData
315
+ });
316
+ if (!res.ok) {
317
+ const body = await res.text().catch(() => "");
318
+ throw new Error(`Cloud pack failed (${res.status}): ${body}`);
319
+ }
320
+ return await res.json();
321
+ }
322
+ };
323
+ var CloudArtifactClient = class {
324
+ endpoint;
325
+ constructor(endpoint) {
326
+ this.endpoint = endpoint ?? CLOUD_DEFAULT_ENDPOINT;
327
+ }
328
+ async upload(token, config) {
329
+ const res = await fetch(
330
+ `${this.endpoint}/api/v1/cloud/artifacts/${config.identity}/${config.environment}`,
331
+ {
332
+ method: "PUT",
333
+ headers: {
334
+ Authorization: `Bearer ${token}`,
335
+ "Content-Type": "application/json"
336
+ },
337
+ body: config.artifactJson
338
+ }
339
+ );
340
+ if (!res.ok) {
341
+ const body = await res.text().catch(() => "");
342
+ throw new Error(`Artifact upload failed (${res.status}): ${body}`);
343
+ }
344
+ }
345
+ };
346
+
347
+ // src/token-refresh.ts
348
+ async function refreshAccessToken(config) {
349
+ const url = `${config.cognitoDomain}/oauth2/token`;
350
+ const body = new URLSearchParams({
351
+ grant_type: "refresh_token",
352
+ client_id: config.clientId,
353
+ refresh_token: config.refreshToken
354
+ });
355
+ const res = await fetch(url, {
356
+ method: "POST",
357
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
358
+ body: body.toString()
359
+ });
360
+ if (!res.ok) {
361
+ const text = await res.text().catch(() => "");
362
+ if (res.status === 400 && text.includes("invalid_grant")) {
363
+ throw new Error(
364
+ "Refresh token expired or revoked. Run 'clef cloud login' to re-authenticate."
365
+ );
366
+ }
367
+ throw new Error(`Token refresh failed (${res.status}): ${text}`);
368
+ }
369
+ const data = await res.json();
370
+ return {
371
+ accessToken: data.access_token,
372
+ idToken: data.id_token,
373
+ expiresIn: data.expires_in
374
+ };
375
+ }
376
+
377
+ // src/sops.ts
378
+ async function resolveAccessToken() {
379
+ const clefToken = process.env.CLEF_TOKEN;
380
+ if (clefToken) {
381
+ const creds2 = readCloudCredentials();
382
+ return { accessToken: clefToken, endpoint: creds2?.endpoint };
383
+ }
384
+ const creds = readCloudCredentials();
385
+ const refreshToken = process.env.CLEF_CLOUD_REFRESH_TOKEN ?? creds?.refreshToken;
386
+ if (!refreshToken) {
387
+ throw new Error("Not authenticated. Run 'clef cloud login' to connect to Clef Cloud.");
388
+ }
389
+ if (creds?.accessToken && creds?.accessTokenExpiry && Date.now() < creds.accessTokenExpiry - 6e4) {
390
+ return { accessToken: creds.accessToken, endpoint: creds?.endpoint };
391
+ }
392
+ if (!creds?.cognitoDomain || !creds?.clientId) {
393
+ throw new Error("Missing Cognito configuration. Run 'clef cloud login' to re-authenticate.");
394
+ }
395
+ const result = await refreshAccessToken({
396
+ cognitoDomain: creds.cognitoDomain,
397
+ clientId: creds.clientId,
398
+ refreshToken
399
+ });
400
+ writeCloudCredentials({
401
+ ...creds,
402
+ refreshToken,
403
+ accessToken: result.accessToken,
404
+ accessTokenExpiry: Date.now() + result.expiresIn * 1e3
405
+ });
406
+ return { accessToken: result.accessToken, endpoint: creds?.endpoint };
407
+ }
408
+ async function createCloudSopsClient(repoRoot, runner, createSopsClient) {
409
+ const { accessToken, endpoint } = await resolveAccessToken();
410
+ const binaryPath = resolveKeyservicePath().path;
411
+ const handle = await spawnKeyservice({
412
+ binaryPath,
413
+ token: accessToken,
414
+ endpoint
415
+ });
416
+ const client = await createSopsClient(repoRoot, runner, handle.addr);
417
+ return {
418
+ client,
419
+ cleanup: () => handle.kill()
420
+ };
421
+ }
422
+
423
+ // src/types.ts
424
+ var CloudApiError = class extends Error {
425
+ constructor(message, statusCode, fix) {
426
+ super(message);
427
+ this.statusCode = statusCode;
428
+ this.fix = fix;
429
+ this.name = "CloudApiError";
430
+ }
431
+ statusCode;
432
+ fix;
433
+ };
434
+
435
+ // src/report-client.ts
436
+ var DEFAULT_RETRY_DELAY_MS = 1e3;
437
+ var CloudClient = class {
438
+ retryDelayMs;
439
+ constructor(options) {
440
+ this.retryDelayMs = options?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
441
+ }
442
+ async fetchIntegration(apiUrl, apiKey, integrationId) {
443
+ const url = `${apiUrl}/api/v1/integrations/${encodeURIComponent(integrationId)}`;
444
+ return this.request("GET", url, apiKey);
445
+ }
446
+ async submitReport(apiUrl, apiKey, report) {
447
+ const url = `${apiUrl}/api/v1/reports`;
448
+ return this.request("POST", url, apiKey, report);
449
+ }
450
+ async submitBatchReports(apiUrl, apiKey, batch) {
451
+ const url = `${apiUrl}/api/v1/reports/batch`;
452
+ return this.request("POST", url, apiKey, batch);
453
+ }
454
+ async request(method, url, apiKey, body) {
455
+ const headers = {
456
+ Authorization: `Bearer ${apiKey}`,
457
+ "Content-Type": "application/json"
458
+ };
459
+ const init = {
460
+ method,
461
+ headers,
462
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
463
+ };
464
+ let response;
465
+ try {
466
+ response = await fetch(url, init);
467
+ } catch {
468
+ await this.delay(this.retryDelayMs);
469
+ try {
470
+ response = await fetch(url, init);
471
+ } catch (retryErr) {
472
+ throw new CloudApiError(
473
+ `Network error contacting Clef Cloud: ${retryErr.message}`,
474
+ 0,
475
+ "Check your network connection and CLEF_API_URL."
476
+ );
477
+ }
478
+ }
479
+ if (response.ok) {
480
+ return await response.json();
481
+ }
482
+ if (response.status >= 500 && response.status < 600) {
483
+ await this.delay(this.retryDelayMs);
484
+ const retryResponse = await fetch(url, init);
485
+ if (retryResponse.ok) {
486
+ return await retryResponse.json();
487
+ }
488
+ throw this.buildError(retryResponse);
489
+ }
490
+ throw this.buildError(response);
491
+ }
492
+ buildError(response) {
493
+ const hint = response.status === 401 || response.status === 403 ? "Check your API token (--api-token or CLEF_API_TOKEN)." : response.status === 404 ? "Check your cloud.integrationId in clef.yaml." : void 0;
494
+ return new CloudApiError(
495
+ `Clef Cloud API returned ${response.status} ${response.statusText}`,
496
+ response.status,
497
+ hint
498
+ );
499
+ }
500
+ delay(ms) {
501
+ return new Promise((resolve) => setTimeout(resolve, ms));
502
+ }
503
+ };
504
+ // Annotate the CommonJS export names for ESM import in node:
505
+ 0 && (module.exports = {
506
+ CLOUD_DEFAULT_ENDPOINT,
507
+ CloudApiError,
508
+ CloudArtifactClient,
509
+ CloudClient,
510
+ CloudPackClient,
511
+ createCloudSopsClient,
512
+ initiateDeviceFlow,
513
+ pollDeviceFlow,
514
+ readCloudCredentials,
515
+ refreshAccessToken,
516
+ resetKeyserviceResolution,
517
+ resolveAccessToken,
518
+ resolveKeyservicePath,
519
+ spawnKeyservice,
520
+ writeCloudCredentials
521
+ });
522
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/keyservice.ts", "../src/resolver.ts", "../src/bundled.ts", "../src/credentials.ts", "../src/constants.ts", "../src/device-flow.ts", "../src/pack-client.ts", "../src/token-refresh.ts", "../src/sops.ts", "../src/types.ts", "../src/report-client.ts"],
4
+ "sourcesContent": ["/**\n * @clef-sh/cloud \u2014 Clef Cloud integration.\n *\n * Managed KMS backend, device-flow authentication, artifact hosting,\n * and keyservice sidecar management. Requires @clef-sh/core as a peer.\n *\n * This package is optional \u2014 the core Clef CLI works without it.\n * Install it to enable `clef cloud init` and the Cloud encryption backend.\n */\n\nexport type { ClefCloudCredentials } from \"./types\";\nexport { spawnKeyservice } from \"./keyservice\";\nexport type { KeyserviceHandle } from \"./keyservice\";\nexport { resolveKeyservicePath, resetKeyserviceResolution } from \"./resolver\";\nexport type { KeyserviceResolution, KeyserviceSource } from \"./resolver\";\nexport { readCloudCredentials, writeCloudCredentials } from \"./credentials\";\nexport { initiateDeviceFlow, pollDeviceFlow } from \"./device-flow\";\nexport type { DeviceSession, DevicePollResult, DeviceFlowType } from \"./device-flow\";\nexport { CloudPackClient, CloudArtifactClient } from \"./pack-client\";\nexport type { RemotePackConfig, RemotePackResult } from \"./pack-client\";\nexport { CLOUD_DEFAULT_ENDPOINT } from \"./constants\";\nexport { refreshAccessToken } from \"./token-refresh\";\nexport type { TokenRefreshConfig, TokenRefreshResult } from \"./token-refresh\";\nexport { createCloudSopsClient, resolveAccessToken } from \"./sops\";\nexport type { CloudSopsResult, CreateSopsClientFn } from \"./sops\";\nexport { CloudClient } from \"./report-client\";\nexport type {\n CloudApiReport,\n CloudBatchPayload,\n CloudBatchResponse,\n CloudIntegrationResponse,\n CloudReportResponse,\n CloudReportSummary,\n CloudReportDrift,\n CloudReportCell,\n CloudCellHealthStatus,\n CloudPolicyResult,\n CloudCIContext,\n} from \"./types\";\nexport { CloudApiError } from \"./types\";\n", "/**\n * Manages the clef-keyservice sidecar lifecycle: spawn, port discovery, graceful shutdown.\n *\n * The keyservice binary is a localhost gRPC server that proxies KMS encrypt/decrypt\n * operations to the Cloud API. The CLI spawns it per command and kills it when done.\n */\nimport { spawn, type ChildProcess } from \"child_process\";\nimport * as readline from \"readline\";\n\nexport interface KeyserviceHandle {\n /** Address for SOPS --keyservice flag, e.g. \"tcp://127.0.0.1:12345\". */\n addr: string;\n /** Gracefully stop the keyservice process. */\n kill(): Promise<void>;\n}\n\nconst PORT_REGEX = /^PORT=(\\d+)$/;\nconst STARTUP_TIMEOUT_MS = 5000;\nconst SHUTDOWN_TIMEOUT_MS = 3000;\n\n/**\n * Spawn a clef-keyservice sidecar process and wait for it to report its port.\n *\n * @param options.binaryPath - Absolute path to the clef-keyservice binary.\n * @param options.token - Cloud bearer token for API authentication.\n * @param options.endpoint - Optional Cloud API endpoint override.\n * @returns A handle with the keyservice address and a kill function.\n */\nexport async function spawnKeyservice(options: {\n binaryPath: string;\n token: string;\n endpoint?: string;\n}): Promise<KeyserviceHandle> {\n const args = [\"--addr\", \"127.0.0.1:0\"];\n if (options.endpoint) {\n args.push(\"--endpoint\", options.endpoint);\n }\n\n // Token passed via env var \u2014 CLI args are visible in /proc/<pid>/cmdline\n const child = spawn(options.binaryPath, args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, CLEF_CLOUD_TOKEN: options.token },\n });\n\n const port = await readPort(child);\n const addr = `tcp://127.0.0.1:${port}`;\n\n return {\n addr,\n kill: () => killGracefully(child),\n };\n}\n\nfunction readPort(child: ChildProcess): Promise<number> {\n return new Promise((resolve, reject) => {\n let settled = false;\n\n const rl = readline.createInterface({ input: child.stdout! });\n\n function settle() {\n clearTimeout(timer);\n rl.close();\n }\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n settle();\n child.kill(\"SIGKILL\");\n reject(new Error(\"Keyservice did not start within 5 seconds.\"));\n }\n }, STARTUP_TIMEOUT_MS);\n\n rl.on(\"line\", (line) => {\n const match = PORT_REGEX.exec(line);\n if (match && !settled) {\n settled = true;\n settle();\n resolve(parseInt(match[1], 10));\n }\n });\n\n child.on(\"error\", (err) => {\n if (!settled) {\n settled = true;\n settle();\n reject(new Error(`Failed to start keyservice: ${err.message}`));\n }\n });\n\n child.on(\"exit\", (code) => {\n if (!settled) {\n settled = true;\n settle();\n reject(new Error(`Keyservice exited unexpectedly with code ${code}.`));\n }\n });\n });\n}\n\nfunction killGracefully(child: ChildProcess): Promise<void> {\n return new Promise((resolve) => {\n if (child.exitCode !== null) {\n resolve();\n return;\n }\n const timer = setTimeout(() => {\n child.kill(\"SIGKILL\");\n }, SHUTDOWN_TIMEOUT_MS);\n child.on(\"exit\", () => {\n clearTimeout(timer);\n resolve();\n });\n child.kill(\"SIGTERM\");\n });\n}\n", "/**\n * Resolves the path to the `clef-keyservice` binary using a three-tier resolution chain:\n *\n * 1. `CLEF_KEYSERVICE_PATH` environment variable (explicit user override)\n * 2. Bundled platform-specific package (`@clef-sh/keyservice-{os}-{arch}`)\n * 3. System PATH fallback (bare `\"clef-keyservice\"` command name)\n *\n * Mirrors the resolution pattern in sops/resolver.ts.\n */\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { tryBundledKeyservice } from \"./bundled\";\n\nfunction validateKeyservicePath(candidate: string): void {\n if (!path.isAbsolute(candidate)) {\n throw new Error(`CLEF_KEYSERVICE_PATH must be an absolute path, got '${candidate}'.`);\n }\n const segments = candidate.split(/[/\\\\]/);\n if (segments.includes(\"..\")) {\n throw new Error(\n `CLEF_KEYSERVICE_PATH contains '..' path segments ('${candidate}'). ` +\n \"Use an absolute path without directory traversal.\",\n );\n }\n}\n\nexport type KeyserviceSource = \"env\" | \"bundled\" | \"system\";\n\nexport interface KeyserviceResolution {\n /** Absolute path to the keyservice binary, or \"clef-keyservice\" for system PATH fallback. */\n path: string;\n /** How the binary was located. */\n source: KeyserviceSource;\n}\n\nlet cached: KeyserviceResolution | undefined;\n\n/**\n * Resolve the clef-keyservice binary path.\n *\n * Resolution order:\n * 1. `CLEF_KEYSERVICE_PATH` env var \u2014 explicit override, used as-is\n * 2. Bundled `@clef-sh/keyservice-{platform}-{arch}` package\n * 3. System PATH fallback \u2014 returns bare `\"clef-keyservice\"`\n *\n * The result is cached module-wide. Call {@link resetKeyserviceResolution} in tests\n * to clear the cache.\n */\nexport function resolveKeyservicePath(): KeyserviceResolution {\n if (cached) return cached;\n\n // 1. Explicit environment override\n const envPath = process.env.CLEF_KEYSERVICE_PATH?.trim();\n if (envPath) {\n validateKeyservicePath(envPath);\n if (!fs.existsSync(envPath)) {\n throw new Error(`CLEF_KEYSERVICE_PATH points to '${envPath}' but the file does not exist.`);\n }\n cached = { path: envPath, source: \"env\" };\n return cached;\n }\n\n // 2. Bundled platform package\n const bundledPath = tryBundledKeyservice();\n if (bundledPath) {\n cached = { path: bundledPath, source: \"bundled\" };\n return cached;\n }\n\n // 3. System PATH fallback\n cached = { path: \"clef-keyservice\", source: \"system\" };\n return cached;\n}\n\n/**\n * Clear the cached resolution. Only intended for use in tests.\n */\nexport function resetKeyserviceResolution(): void {\n cached = undefined;\n}\n", "/**\n * Locates the bundled clef-keyservice binary from the platform-specific npm package.\n * Mirrors sops/bundled.ts \u2014 extracted for testability.\n */\nimport * as fs from \"fs\";\nimport * as path from \"path\";\n\n/**\n * Try to locate the bundled keyservice binary from the platform-specific npm package.\n * Returns the resolved path or null if the package is not installed.\n */\nexport function tryBundledKeyservice(): string | null {\n const platform = process.platform;\n const arch = process.arch;\n\n const archName = arch === \"x64\" ? \"x64\" : arch === \"arm64\" ? \"arm64\" : null;\n if (!archName) return null;\n\n const platformName =\n platform === \"darwin\"\n ? \"darwin\"\n : platform === \"linux\"\n ? \"linux\"\n : platform === \"win32\"\n ? \"win32\"\n : null;\n if (!platformName) return null;\n\n const packageName = `@clef-sh/keyservice-${platformName}-${archName}`;\n const binName = platform === \"win32\" ? \"clef-keyservice.exe\" : \"clef-keyservice\";\n\n try {\n const packageMain = require.resolve(`${packageName}/package.json`);\n const packageDir = path.dirname(packageMain);\n const binPath = path.join(packageDir, \"bin\", binName);\n return fs.existsSync(binPath) ? binPath : null;\n } catch {\n return null;\n }\n}\n", "import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport * as YAML from \"yaml\";\nimport type { ClefCloudCredentials } from \"./types\";\nimport { CLOUD_DEFAULT_ENDPOINT } from \"./constants\";\n\nconst CREDENTIALS_FILENAME = \"credentials.yaml\";\n\n/**\n * Read Cloud credentials from ~/.clef/credentials.yaml.\n * Returns null if the file does not exist or is malformed.\n */\nexport function readCloudCredentials(): ClefCloudCredentials | null {\n const credPath = path.join(os.homedir(), \".clef\", CREDENTIALS_FILENAME);\n\n let raw: unknown;\n try {\n raw = YAML.parse(fs.readFileSync(credPath, \"utf-8\"));\n } catch {\n return null;\n }\n\n if (!raw || typeof raw !== \"object\") return null;\n const obj = raw as Record<string, unknown>;\n\n const refreshToken = typeof obj.refreshToken === \"string\" ? obj.refreshToken : \"\";\n const accessToken = typeof obj.accessToken === \"string\" ? obj.accessToken : undefined;\n const accessTokenExpiry =\n typeof obj.accessTokenExpiry === \"number\" ? obj.accessTokenExpiry : undefined;\n const endpoint = typeof obj.endpoint === \"string\" ? obj.endpoint : CLOUD_DEFAULT_ENDPOINT;\n const cognitoDomain = typeof obj.cognitoDomain === \"string\" ? obj.cognitoDomain : undefined;\n const clientId = typeof obj.clientId === \"string\" ? obj.clientId : undefined;\n\n if (!refreshToken && endpoint === CLOUD_DEFAULT_ENDPOINT) return null;\n\n return { refreshToken, accessToken, accessTokenExpiry, endpoint, cognitoDomain, clientId };\n}\n\n/**\n * Write Cloud credentials to ~/.clef/credentials.yaml.\n * Creates ~/.clef/ with mode 0700 if it doesn't exist.\n * File is written with mode 0600 (owner read/write only).\n */\nexport function writeCloudCredentials(credentials: ClefCloudCredentials): void {\n const clefDir = path.join(os.homedir(), \".clef\");\n fs.mkdirSync(clefDir, { recursive: true, mode: 0o700 });\n const credPath = path.join(clefDir, CREDENTIALS_FILENAME);\n\n const content = Object.fromEntries(\n Object.entries(credentials).filter(([, v]) => v !== undefined),\n );\n\n fs.writeFileSync(credPath, YAML.stringify(content), { mode: 0o600 });\n}\n", "export const CLOUD_DEFAULT_ENDPOINT = \"https://api.clef.sh\";\n", "/**\n * Device flow client for Clef Cloud authentication.\n *\n * The CLI initiates a device flow session, opens the browser to the login URL,\n * and polls until the user completes auth + payment. Same pattern as\n * `gh auth login` and Claude Code.\n */\nimport { CLOUD_DEFAULT_ENDPOINT } from \"./constants\";\n\nexport interface DeviceSession {\n sessionId: string;\n loginUrl: string;\n pollUrl: string;\n /** Session lifetime in seconds. */\n expiresIn: number;\n}\n\nexport type DeviceFlowType = \"login\" | \"setup\";\n\nexport interface DevicePollResult {\n status: \"pending\" | \"awaiting_payment\" | \"complete\" | \"cancelled\" | \"expired\";\n /** Cognito refresh token. Present when status is \"complete\". */\n token?: string;\n /** Cognito access token. Present when status is \"complete\". */\n accessToken?: string;\n /** Access token lifetime in seconds. Present alongside accessToken. */\n accessTokenExpiresIn?: number;\n /** Present when status is \"complete\". */\n integrationId?: string;\n /** Present when status is \"complete\". */\n keyId?: string;\n /** Cognito OAuth2 domain URL for token refresh. Present when status is \"complete\". */\n cognitoDomain?: string;\n /** CLI Cognito app client ID. Present when status is \"complete\". */\n clientId?: string;\n}\n\n/**\n * Initiate a device flow session with the Cloud API.\n *\n * @param endpoint - Cloud API base URL. Defaults to https://api.clef.sh.\n * @param options - Session metadata carried into the browser flow.\n * @returns The session with a login URL to open in the browser.\n */\nexport async function initiateDeviceFlow(\n endpoint: string | undefined,\n options: {\n repoName: string;\n environment?: string;\n clientVersion: string;\n flow: DeviceFlowType;\n },\n): Promise<DeviceSession> {\n const base = endpoint ?? CLOUD_DEFAULT_ENDPOINT;\n const payload: Record<string, string> = {\n clientType: \"cli\",\n clientVersion: options.clientVersion,\n repoName: options.repoName,\n flow: options.flow,\n };\n if (options.environment) {\n payload.environment = options.environment;\n }\n let res: Response;\n try {\n res = await fetch(`${base}/api/v1/device/init`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n });\n } catch (err) {\n const cause = err instanceof Error ? (err as Error & { cause?: unknown }).cause : undefined;\n const reason =\n cause instanceof Error ? cause.message : err instanceof Error ? err.message : String(err);\n throw new Error(`Could not reach Clef Cloud at ${base}: ${reason}`);\n }\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Device flow init failed (${res.status}): ${body}`);\n }\n\n const json = await res.json();\n // Support both { data: { ... } } (saas API) and flat { ... } formats\n const session = (json.data ?? json) as DeviceSession;\n\n // The API may return a relative pollUrl \u2014 resolve it against the base\n if (session.pollUrl && !session.pollUrl.startsWith(\"http\")) {\n session.pollUrl = `${base}${session.pollUrl}`;\n }\n\n return session;\n}\n\n/**\n * Poll a device flow session for completion.\n *\n * @param pollUrl - The full poll URL returned by {@link initiateDeviceFlow}.\n * @returns The current session state.\n */\nexport async function pollDeviceFlow(pollUrl: string): Promise<DevicePollResult> {\n let res: Response;\n try {\n res = await fetch(pollUrl);\n } catch (err) {\n const cause = err instanceof Error ? (err as Error & { cause?: unknown }).cause : undefined;\n const reason =\n cause instanceof Error ? cause.message : err instanceof Error ? err.message : String(err);\n throw new Error(`Could not reach Clef Cloud poll endpoint: ${reason}`);\n }\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Device flow poll failed (${res.status}): ${body}`);\n }\n\n const json = await res.json();\n return (json.data ?? json) as DevicePollResult;\n}\n", "/**\n * HTTP client for the Cloud pack endpoint.\n *\n * Used by `clef pack --remote` to send encrypted files to Cloud for packing.\n */\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { ClefManifest, MatrixCell } from \"@clef-sh/core\";\nimport { MatrixManager } from \"@clef-sh/core\";\nimport { CLOUD_DEFAULT_ENDPOINT } from \"./constants\";\n\nexport interface RemotePackConfig {\n identity: string;\n environment: string;\n manifest: ClefManifest;\n repoRoot: string;\n ttl?: number;\n}\n\nexport interface RemotePackResult {\n revision: string;\n artifactSize: number;\n identity: string;\n environment: string;\n}\n\nexport class CloudPackClient {\n private readonly endpoint: string;\n\n constructor(endpoint?: string) {\n this.endpoint = endpoint ?? CLOUD_DEFAULT_ENDPOINT;\n }\n\n async pack(token: string, config: RemotePackConfig): Promise<RemotePackResult> {\n const matrixManager = new MatrixManager();\n const cells = matrixManager\n .resolveMatrix(config.manifest, config.repoRoot)\n .filter((c: MatrixCell) => c.environment === config.environment && c.exists);\n\n const formData = new FormData();\n\n const configJson = JSON.stringify({\n identity: config.identity,\n environment: config.environment,\n ...(config.ttl ? { ttl: config.ttl } : {}),\n });\n formData.append(\"config\", new Blob([configJson], { type: \"application/json\" }));\n\n const manifestPath = path.join(config.repoRoot, \"clef.yaml\");\n const manifestContent = fs.readFileSync(manifestPath, \"utf-8\");\n formData.append(\"manifest\", new Blob([manifestContent], { type: \"text/yaml\" }));\n\n for (const cell of cells) {\n const relPath = path.relative(config.repoRoot, cell.filePath);\n const content = fs.readFileSync(cell.filePath, \"utf-8\");\n formData.append(`files`, new Blob([content], { type: \"text/yaml\" }), relPath);\n }\n\n const res = await fetch(`${this.endpoint}/api/v1/cloud/pack`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}` },\n body: formData,\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Cloud pack failed (${res.status}): ${body}`);\n }\n\n return (await res.json()) as RemotePackResult;\n }\n}\n\n/**\n * HTTP client for uploading a locally-packed artifact to Cloud.\n *\n * Used by `clef pack --push`.\n */\nexport class CloudArtifactClient {\n private readonly endpoint: string;\n\n constructor(endpoint?: string) {\n this.endpoint = endpoint ?? CLOUD_DEFAULT_ENDPOINT;\n }\n\n async upload(\n token: string,\n config: { identity: string; environment: string; artifactJson: string },\n ): Promise<void> {\n const res = await fetch(\n `${this.endpoint}/api/v1/cloud/artifacts/${config.identity}/${config.environment}`,\n {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: config.artifactJson,\n },\n );\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Artifact upload failed (${res.status}): ${body}`);\n }\n }\n}\n", "/**\n * Cognito token refresh via the OAuth2 token endpoint.\n *\n * Uses plain HTTP \u2014 no AWS SDK dependency. The Cognito token endpoint\n * accepts refresh tokens and returns fresh access tokens.\n */\n\nexport interface TokenRefreshConfig {\n cognitoDomain: string;\n clientId: string;\n refreshToken: string;\n}\n\nexport interface TokenRefreshResult {\n accessToken: string;\n idToken: string;\n expiresIn: number;\n}\n\n/**\n * Refresh a Cognito access token using a refresh token.\n *\n * Calls the Cognito OAuth2 token endpoint directly:\n * POST https://<domain>.auth.<region>.amazoncognito.com/oauth2/token\n *\n * @returns Fresh access token, ID token, and expiry (seconds).\n * @throws If the refresh token is expired or invalid.\n */\nexport async function refreshAccessToken(config: TokenRefreshConfig): Promise<TokenRefreshResult> {\n const url = `${config.cognitoDomain}/oauth2/token`;\n\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n client_id: config.clientId,\n refresh_token: config.refreshToken,\n });\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n if (res.status === 400 && text.includes(\"invalid_grant\")) {\n throw new Error(\n \"Refresh token expired or revoked. Run 'clef cloud login' to re-authenticate.\",\n );\n }\n throw new Error(`Token refresh failed (${res.status}): ${text}`);\n }\n\n const data = (await res.json()) as {\n access_token: string;\n id_token: string;\n expires_in: number;\n token_type: string;\n };\n\n return {\n accessToken: data.access_token,\n idToken: data.id_token,\n expiresIn: data.expires_in,\n };\n}\n", "/**\n * Cloud-aware SopsClient factory.\n *\n * Spawns the keyservice sidecar and creates a SopsClient with the keyservice\n * address for cloud backend decrypt/encrypt operations.\n */\nimport { SopsClient, SubprocessRunner } from \"@clef-sh/core\";\nimport { readCloudCredentials, writeCloudCredentials } from \"./credentials\";\nimport { resolveKeyservicePath } from \"./resolver\";\nimport { spawnKeyservice } from \"./keyservice\";\nimport { refreshAccessToken } from \"./token-refresh\";\n\nexport interface CloudSopsResult {\n client: SopsClient;\n cleanup: () => Promise<void>;\n}\n\nexport type CreateSopsClientFn = (\n repoRoot: string,\n runner: SubprocessRunner,\n keyserviceAddr?: string,\n) => Promise<SopsClient>;\n\n/**\n * Resolve a fresh Cognito access token.\n *\n * Priority:\n * 1. CLEF_CLOUD_REFRESH_TOKEN env var (CI)\n * 2. ~/.clef/credentials.yaml refreshToken (interactive)\n *\n * If a cached access token exists and hasn't expired, returns it.\n * Otherwise refreshes via the Cognito token endpoint.\n */\nexport async function resolveAccessToken(): Promise<{ accessToken: string; endpoint?: string }> {\n // Service account token \u2014 used in CI, no refresh needed\n const clefToken = process.env.CLEF_TOKEN;\n if (clefToken) {\n const creds = readCloudCredentials();\n return { accessToken: clefToken, endpoint: creds?.endpoint };\n }\n\n const creds = readCloudCredentials();\n const refreshToken = process.env.CLEF_CLOUD_REFRESH_TOKEN ?? creds?.refreshToken;\n\n if (!refreshToken) {\n throw new Error(\"Not authenticated. Run 'clef cloud login' to connect to Clef Cloud.\");\n }\n\n // Return cached access token if still valid (before checking Cognito config)\n if (\n creds?.accessToken &&\n creds?.accessTokenExpiry &&\n Date.now() < creds.accessTokenExpiry - 60000\n ) {\n return { accessToken: creds.accessToken, endpoint: creds?.endpoint };\n }\n\n if (!creds?.cognitoDomain || !creds?.clientId) {\n throw new Error(\"Missing Cognito configuration. Run 'clef cloud login' to re-authenticate.\");\n }\n\n const result = await refreshAccessToken({\n cognitoDomain: creds.cognitoDomain,\n clientId: creds.clientId,\n refreshToken,\n });\n\n writeCloudCredentials({\n ...creds,\n refreshToken,\n accessToken: result.accessToken,\n accessTokenExpiry: Date.now() + result.expiresIn * 1000,\n });\n\n return { accessToken: result.accessToken, endpoint: creds?.endpoint };\n}\n\n/**\n * Create a SopsClient backed by the cloud keyservice sidecar.\n *\n * @param repoRoot - Repository root directory.\n * @param runner - Subprocess runner for SOPS invocations.\n * @param createSopsClient - Factory function from the CLI to create a SopsClient\n * (handles age credential resolution).\n */\nexport async function createCloudSopsClient(\n repoRoot: string,\n runner: SubprocessRunner,\n createSopsClient: CreateSopsClientFn,\n): Promise<CloudSopsResult> {\n const { accessToken, endpoint } = await resolveAccessToken();\n\n const binaryPath = resolveKeyservicePath().path;\n const handle = await spawnKeyservice({\n binaryPath,\n token: accessToken,\n endpoint,\n });\n\n const client = await createSopsClient(repoRoot, runner, handle.addr);\n return {\n client,\n cleanup: () => handle.kill(),\n };\n}\n", "/** User-scoped Cloud credentials stored in ~/.clef/credentials.yaml. */\nexport interface ClefCloudCredentials {\n /** Cognito refresh token \u2014 long-lived, auto-refreshed to get access tokens. */\n refreshToken: string;\n /** Cached Cognito access token \u2014 short-lived, refreshed as needed. */\n accessToken?: string;\n /** Epoch ms when the cached access token expires. */\n accessTokenExpiry?: number;\n /** Cloud API endpoint override. Defaults to https://api.clef.sh. */\n endpoint?: string;\n /** Cognito OAuth2 domain for token refresh (e.g. https://clefcloud-123.auth.us-east-1.amazoncognito.com). */\n cognitoDomain?: string;\n /** Cognito CLI app client ID. */\n clientId?: string;\n}\n\n// \u2500\u2500 Cloud report types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Health status for a single matrix cell in a cloud report. */\nexport type CloudCellHealthStatus = \"healthy\" | \"warning\" | \"critical\" | \"unknown\";\n\n/** A single cell summary sent to the Cloud API. */\nexport interface CloudReportCell {\n namespace: string;\n environment: string;\n healthStatus: CloudCellHealthStatus;\n description: string;\n}\n\n/** Summary section of a cloud API report. */\nexport interface CloudReportSummary {\n filesScanned: number;\n namespaces: string[];\n environments: string[];\n cells: CloudReportCell[];\n violations: number;\n passed: boolean;\n}\n\n/** Drift entry for a single namespace in a cloud report. */\nexport interface CloudReportDrift {\n namespace: string;\n isDrifted: boolean;\n driftCount: number;\n}\n\n/** A single policy result in a cloud report. */\nexport interface CloudPolicyResult {\n ruleId: string;\n ruleName: string;\n passed: boolean;\n severity: string;\n message: string;\n scope?: { namespace?: string; environment?: string };\n}\n\n/** CI context attached to cloud reports when collectCIContext is enabled. */\nexport interface CloudCIContext {\n provider: string;\n pipelineUrl?: string;\n trigger?: string;\n}\n\n/** The report payload sent to the Cloud API. */\nexport interface CloudApiReport {\n commitSha: string;\n branch: string;\n commitTimestamp: number;\n cliVersion: string;\n summary: CloudReportSummary;\n drift: CloudReportDrift[];\n policyResults: CloudPolicyResult[];\n ciContext?: CloudCIContext;\n}\n\n/** Batch payload for backfill submissions (max 500, oldest\u2192newest). */\nexport interface CloudBatchPayload {\n reports: CloudApiReport[];\n}\n\n/** Response from GET /api/v1/integrations/:integrationId. */\nexport interface CloudIntegrationResponse {\n lastCommitSha: string | null;\n config: {\n collectCIContext: boolean;\n };\n}\n\n/** Response from POST /api/v1/reports. */\nexport interface CloudReportResponse {\n id: string;\n commitSha: string;\n}\n\n/** Response from POST /api/v1/reports/batch. */\nexport interface CloudBatchResponse {\n accepted: number;\n reportIds: string[];\n}\n\n/** Thrown when a Cloud API request fails. */\nexport class CloudApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly fix?: string,\n ) {\n super(message);\n this.name = \"CloudApiError\";\n }\n}\n", "import {\n CloudApiError,\n type CloudApiReport,\n type CloudBatchPayload,\n type CloudBatchResponse,\n type CloudIntegrationResponse,\n type CloudReportResponse,\n} from \"./types\";\n\nconst DEFAULT_RETRY_DELAY_MS = 1000;\n\n/**\n * HTTP client for the Clef Cloud API.\n * Uses native `fetch()` (Node 18+). Retries once on 5xx or network errors.\n */\nexport class CloudClient {\n private readonly retryDelayMs: number;\n\n constructor(options?: { retryDelayMs?: number }) {\n this.retryDelayMs = options?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;\n }\n async fetchIntegration(\n apiUrl: string,\n apiKey: string,\n integrationId: string,\n ): Promise<CloudIntegrationResponse> {\n const url = `${apiUrl}/api/v1/integrations/${encodeURIComponent(integrationId)}`;\n return this.request<CloudIntegrationResponse>(\"GET\", url, apiKey);\n }\n\n async submitReport(\n apiUrl: string,\n apiKey: string,\n report: CloudApiReport,\n ): Promise<CloudReportResponse> {\n const url = `${apiUrl}/api/v1/reports`;\n return this.request<CloudReportResponse>(\"POST\", url, apiKey, report);\n }\n\n async submitBatchReports(\n apiUrl: string,\n apiKey: string,\n batch: CloudBatchPayload,\n ): Promise<CloudBatchResponse> {\n const url = `${apiUrl}/api/v1/reports/batch`;\n return this.request<CloudBatchResponse>(\"POST\", url, apiKey, batch);\n }\n\n private async request<T>(\n method: string,\n url: string,\n apiKey: string,\n body?: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetch(url, init);\n } catch {\n // Network error \u2014 retry once\n await this.delay(this.retryDelayMs);\n try {\n response = await fetch(url, init);\n } catch (retryErr) {\n throw new CloudApiError(\n `Network error contacting Clef Cloud: ${(retryErr as Error).message}`,\n 0,\n \"Check your network connection and CLEF_API_URL.\",\n );\n }\n }\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n // 5xx \u2014 retry once\n if (response.status >= 500 && response.status < 600) {\n await this.delay(this.retryDelayMs);\n const retryResponse = await fetch(url, init);\n if (retryResponse.ok) {\n return (await retryResponse.json()) as T;\n }\n throw this.buildError(retryResponse);\n }\n\n // 4xx \u2014 do not retry\n throw this.buildError(response);\n }\n\n private buildError(response: Response): CloudApiError {\n const hint =\n response.status === 401 || response.status === 403\n ? \"Check your API token (--api-token or CLEF_API_TOKEN).\"\n : response.status === 404\n ? \"Check your cloud.integrationId in clef.yaml.\"\n : undefined;\n\n return new CloudApiError(\n `Clef Cloud API returned ${response.status} ${response.statusText}`,\n response.status,\n hint,\n );\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["fs", "path", "fs", "path", "fs", "path", "creds"]
7
+ }