chofex-cli 0.1.146 → 0.1.148
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 +165 -53
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -58828,6 +58828,39 @@ var ChallengeCatalogSchema = exports_Schema.Struct({
|
|
|
58828
58828
|
});
|
|
58829
58829
|
|
|
58830
58830
|
// ../../packages/registration-contract/src/index.ts
|
|
58831
|
+
var campaignAttributionHandoffHeader = "x-chofex-campaign-attribution";
|
|
58832
|
+
var eventUuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
58833
|
+
function campaignAttributionHandoffValue(handoff) {
|
|
58834
|
+
if (!eventUuidPattern.test(handoff.landingId))
|
|
58835
|
+
return;
|
|
58836
|
+
if (!Number.isSafeInteger(handoff.capturedAt) || handoff.capturedAt < 0)
|
|
58837
|
+
return;
|
|
58838
|
+
return `${handoff.landingId}.${handoff.capturedAt}`;
|
|
58839
|
+
}
|
|
58840
|
+
function campaignAttributionHandoffFromValue(value3) {
|
|
58841
|
+
if (!value3)
|
|
58842
|
+
return;
|
|
58843
|
+
const separator = value3.lastIndexOf(".");
|
|
58844
|
+
if (separator < 0)
|
|
58845
|
+
return;
|
|
58846
|
+
const landingId = value3.slice(0, separator);
|
|
58847
|
+
const capturedAt = Number(value3.slice(separator + 1));
|
|
58848
|
+
const handoff = { capturedAt, landingId };
|
|
58849
|
+
if (campaignAttributionHandoffValue(handoff) !== value3)
|
|
58850
|
+
return;
|
|
58851
|
+
return handoff;
|
|
58852
|
+
}
|
|
58853
|
+
function campaignAttributionFromOAuthState(expectedState, returnedState) {
|
|
58854
|
+
if (returnedState === expectedState)
|
|
58855
|
+
return { valid: true };
|
|
58856
|
+
const prefix = `${expectedState}.`;
|
|
58857
|
+
if (!returnedState?.startsWith(prefix))
|
|
58858
|
+
return { valid: false };
|
|
58859
|
+
const handoff = campaignAttributionHandoffFromValue(returnedState.slice(prefix.length));
|
|
58860
|
+
if (!handoff)
|
|
58861
|
+
return { valid: false };
|
|
58862
|
+
return { valid: true, handoff };
|
|
58863
|
+
}
|
|
58831
58864
|
var nonBlank = (maximum) => exports_Schema.Trim.pipe(exports_Schema.check(exports_Schema.isMinLength(1), exports_Schema.isMaxLength(maximum)));
|
|
58832
58865
|
var optionalText = (maximum) => exports_Schema.optional(nonBlank(maximum));
|
|
58833
58866
|
var nullableOptionalText = (maximum) => exports_Schema.optional(exports_Schema.NullOr(nonBlank(maximum)));
|
|
@@ -59140,11 +59173,13 @@ import { createServer } from "node:http";
|
|
|
59140
59173
|
|
|
59141
59174
|
// src/config.ts
|
|
59142
59175
|
var oauthIssuer = process.env.CHOFEX_OAUTH_ISSUER ?? "https://clerk.hacktheandes.com";
|
|
59176
|
+
var publicSiteUrl = process.env.CHOFEX_PUBLIC_SITE_URL ?? "https://hacktheandes.com";
|
|
59143
59177
|
var config = {
|
|
59144
59178
|
apiUrl: process.env.CHOFEX_API_URL ?? "https://hacktheandes.com",
|
|
59145
|
-
publicSiteUrl
|
|
59179
|
+
publicSiteUrl,
|
|
59146
59180
|
oauthClientId: process.env.CHOFEX_OAUTH_CLIENT_ID ?? "HddO78wKpq5PFIEl",
|
|
59147
59181
|
authorizationUrl: `${oauthIssuer}/oauth/authorize`,
|
|
59182
|
+
authorizationBridgeUrl: `${publicSiteUrl}/api/v1/oauth/authorize`,
|
|
59148
59183
|
tokenUrl: `${oauthIssuer}/oauth/token`,
|
|
59149
59184
|
revocationUrl: `${oauthIssuer}/oauth/token/revoke`
|
|
59150
59185
|
};
|
|
@@ -59304,7 +59339,7 @@ var tokenEndpointError = (status, body) => {
|
|
|
59304
59339
|
const detail = description ? `: ${description}` : "";
|
|
59305
59340
|
return new Error(`Clerk OAuth token endpoint returned ${status}${detail}`);
|
|
59306
59341
|
};
|
|
59307
|
-
var credentialsFromToken = (body, previousRefreshToken) => {
|
|
59342
|
+
var credentialsFromToken = (body, previousRefreshToken, campaignAttribution) => {
|
|
59308
59343
|
if (typeof body.access_token !== "string") {
|
|
59309
59344
|
let detail = "";
|
|
59310
59345
|
if (typeof body.error_description === "string") {
|
|
@@ -59322,6 +59357,7 @@ var credentialsFromToken = (body, previousRefreshToken) => {
|
|
|
59322
59357
|
}
|
|
59323
59358
|
return {
|
|
59324
59359
|
accessToken: body.access_token,
|
|
59360
|
+
campaignAttribution,
|
|
59325
59361
|
refreshToken,
|
|
59326
59362
|
expiresAt
|
|
59327
59363
|
};
|
|
@@ -59360,20 +59396,26 @@ var refresh = async (credentials) => {
|
|
|
59360
59396
|
refresh_token: credentials.refreshToken,
|
|
59361
59397
|
client_id: config.oauthClientId
|
|
59362
59398
|
});
|
|
59363
|
-
const updated = credentialsFromToken(body, credentials.refreshToken);
|
|
59399
|
+
const updated = credentialsFromToken(body, credentials.refreshToken, credentials.campaignAttribution);
|
|
59364
59400
|
await saveCredentials(updated);
|
|
59365
59401
|
return updated;
|
|
59366
59402
|
};
|
|
59367
|
-
var
|
|
59368
|
-
if (process.env.CHOFEX_TOKEN)
|
|
59369
|
-
return process.env.CHOFEX_TOKEN;
|
|
59403
|
+
var authentication = async (forceRefresh = false) => {
|
|
59404
|
+
if (process.env.CHOFEX_TOKEN) {
|
|
59405
|
+
return { accessToken: process.env.CHOFEX_TOKEN };
|
|
59406
|
+
}
|
|
59370
59407
|
const credentials = await readCredentials();
|
|
59371
59408
|
if (!credentials)
|
|
59372
59409
|
throw new Error("Not logged in. Run `chofex login`.");
|
|
59373
59410
|
if (forceRefresh || credentials.expiresAt !== undefined && credentials.expiresAt <= Date.now() + 30000) {
|
|
59374
|
-
return
|
|
59411
|
+
return await refresh(credentials);
|
|
59375
59412
|
}
|
|
59376
|
-
return credentials
|
|
59413
|
+
return credentials;
|
|
59414
|
+
};
|
|
59415
|
+
var bridgedAuthorizationUrl = (bridgeUrl, authorizationUrl) => {
|
|
59416
|
+
const bridge = new URL(bridgeUrl);
|
|
59417
|
+
bridge.search = new URL(authorizationUrl).search;
|
|
59418
|
+
return bridge.toString();
|
|
59377
59419
|
};
|
|
59378
59420
|
var browserCommand = (url2, platform = process.platform) => {
|
|
59379
59421
|
if (platform === "darwin")
|
|
@@ -59412,7 +59454,8 @@ var login = async () => {
|
|
|
59412
59454
|
}
|
|
59413
59455
|
const error2 = url2.searchParams.get("error");
|
|
59414
59456
|
const authorizationCode = url2.searchParams.get("code");
|
|
59415
|
-
|
|
59457
|
+
const attributionState = campaignAttributionFromOAuthState(state, url2.searchParams.get("state"));
|
|
59458
|
+
if (!attributionState.valid || error2 || !authorizationCode) {
|
|
59416
59459
|
response.writeHead(400, { "content-type": "text/plain" }).end("Chofex login failed. You can close this window.");
|
|
59417
59460
|
let message = "Invalid OAuth callback";
|
|
59418
59461
|
if (error2)
|
|
@@ -59421,7 +59464,10 @@ var login = async () => {
|
|
|
59421
59464
|
return;
|
|
59422
59465
|
}
|
|
59423
59466
|
response.writeHead(200, { "content-type": "text/plain" }).end("Chofex login complete. You can close this window.");
|
|
59424
|
-
finish(
|
|
59467
|
+
finish({
|
|
59468
|
+
authorizationCode,
|
|
59469
|
+
campaignAttribution: attributionState.handoff
|
|
59470
|
+
});
|
|
59425
59471
|
});
|
|
59426
59472
|
await new Promise((resolve4, reject) => {
|
|
59427
59473
|
server.once("error", reject);
|
|
@@ -59448,23 +59494,26 @@ var login = async () => {
|
|
|
59448
59494
|
server.close();
|
|
59449
59495
|
throw error2;
|
|
59450
59496
|
}
|
|
59497
|
+
const browserUrl = bridgedAuthorizationUrl(config.authorizationBridgeUrl, authorizationUrl.toString());
|
|
59451
59498
|
console.error(`Sign in here (waiting up to five minutes):
|
|
59452
59499
|
|
|
59453
|
-
${
|
|
59500
|
+
${browserUrl}
|
|
59454
59501
|
|
|
59455
59502
|
If the browser did not open automatically, open that URL yourself.`);
|
|
59456
|
-
openBrowser(
|
|
59503
|
+
openBrowser(browserUrl);
|
|
59457
59504
|
const timeout3 = setTimeout(() => fail11(new Error("Login timed out after five minutes")), 300000);
|
|
59458
59505
|
try {
|
|
59459
|
-
const
|
|
59506
|
+
const callback4 = await code;
|
|
59460
59507
|
const body = await tokenRequest({
|
|
59461
59508
|
grant_type: "authorization_code",
|
|
59462
59509
|
client_id: config.oauthClientId,
|
|
59463
|
-
code: authorizationCode,
|
|
59510
|
+
code: callback4.authorizationCode,
|
|
59464
59511
|
redirect_uri: redirectUri,
|
|
59465
59512
|
code_verifier: verifier
|
|
59466
59513
|
});
|
|
59467
|
-
|
|
59514
|
+
const credentials = credentialsFromToken(body, undefined, callback4.campaignAttribution);
|
|
59515
|
+
await saveCredentials(credentials);
|
|
59516
|
+
return credentials.accessToken;
|
|
59468
59517
|
} finally {
|
|
59469
59518
|
clearTimeout(timeout3);
|
|
59470
59519
|
server.close();
|
|
@@ -59535,20 +59584,27 @@ var exitCodeFor = (error2) => {
|
|
|
59535
59584
|
|
|
59536
59585
|
// src/api-client.ts
|
|
59537
59586
|
var endpoint = (apiUrl, path4) => `${apiUrl.replace(/\/$/, "")}${path4}`;
|
|
59538
|
-
var
|
|
59539
|
-
if (suppliedToken)
|
|
59540
|
-
return exports_Effect.succeed(suppliedToken);
|
|
59587
|
+
var resolveAuthentication = (suppliedToken, campaignAttribution, forceRefresh = false) => {
|
|
59588
|
+
if (suppliedToken) {
|
|
59589
|
+
return exports_Effect.succeed({ accessToken: suppliedToken, campaignAttribution });
|
|
59590
|
+
}
|
|
59541
59591
|
return exports_Effect.tryPromise({
|
|
59542
|
-
try: () =>
|
|
59592
|
+
try: () => authentication(forceRefresh),
|
|
59543
59593
|
catch: (error2) => cliError("AUTHENTICATION_REQUIRED", String(error2), false)
|
|
59544
59594
|
});
|
|
59545
59595
|
};
|
|
59546
|
-
var sendRequest = (options, path4, init,
|
|
59596
|
+
var sendRequest = (options, path4, init, credentials) => exports_Effect.tryPromise({
|
|
59547
59597
|
try: () => {
|
|
59548
59598
|
const headers = new Headers(init.headers);
|
|
59549
59599
|
headers.set("accept", "application/json");
|
|
59550
|
-
if (
|
|
59551
|
-
headers.set("authorization", `Bearer ${
|
|
59600
|
+
if (credentials) {
|
|
59601
|
+
headers.set("authorization", `Bearer ${credentials.accessToken}`);
|
|
59602
|
+
if (credentials.campaignAttribution) {
|
|
59603
|
+
const handoff = campaignAttributionHandoffValue(credentials.campaignAttribution);
|
|
59604
|
+
if (handoff)
|
|
59605
|
+
headers.set(campaignAttributionHandoffHeader, handoff);
|
|
59606
|
+
}
|
|
59607
|
+
}
|
|
59552
59608
|
headers.set("x-request-id", crypto.randomUUID());
|
|
59553
59609
|
if (init.body !== undefined) {
|
|
59554
59610
|
headers.set("content-type", "application/json");
|
|
@@ -59577,11 +59633,11 @@ var decodeHttpBody = exports_Effect.fn("decodeHttpBody")(function* (response, de
|
|
|
59577
59633
|
});
|
|
59578
59634
|
var request3 = exports_Effect.fn("apiRequest")(function* (options, path4, init, decodeResponse) {
|
|
59579
59635
|
const suppliedToken = options.token ?? process.env.CHOFEX_TOKEN;
|
|
59580
|
-
let
|
|
59581
|
-
let response = yield* sendRequest(options, path4, init,
|
|
59636
|
+
let credentials = yield* resolveAuthentication(suppliedToken, options.campaignAttribution);
|
|
59637
|
+
let response = yield* sendRequest(options, path4, init, credentials);
|
|
59582
59638
|
if (response.status === 401 && !suppliedToken) {
|
|
59583
|
-
|
|
59584
|
-
response = yield* sendRequest(options, path4, init,
|
|
59639
|
+
credentials = yield* resolveAuthentication(undefined, undefined, true);
|
|
59640
|
+
response = yield* sendRequest(options, path4, init, credentials);
|
|
59585
59641
|
}
|
|
59586
59642
|
return yield* decodeHttpBody(response, decodeResponse);
|
|
59587
59643
|
});
|
|
@@ -62460,7 +62516,7 @@ var uploadPicture = exports_Effect.fn("uploadPicture")(function* (options, path4
|
|
|
62460
62516
|
import { spawn as spawn3 } from "node:child_process";
|
|
62461
62517
|
import { mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
|
|
62462
62518
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
62463
|
-
import { join as join3 } from "node:path";
|
|
62519
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
62464
62520
|
var cliPackageName = "chofex-cli";
|
|
62465
62521
|
var upgradeVersion = "latest";
|
|
62466
62522
|
var npmUpgradeArguments = (cacheDirectory) => [
|
|
@@ -62471,31 +62527,81 @@ var npmUpgradeArguments = (cacheDirectory) => [
|
|
|
62471
62527
|
"--prefer-online",
|
|
62472
62528
|
`--cache=${cacheDirectory}`
|
|
62473
62529
|
];
|
|
62474
|
-
var
|
|
62475
|
-
const
|
|
62530
|
+
var runProcess = (executable, arguments_, input) => new Promise((resolve4, reject) => {
|
|
62531
|
+
const stdin = input === undefined ? "ignore" : "pipe";
|
|
62476
62532
|
const child = spawn3(executable, arguments_, {
|
|
62477
|
-
stdio: [
|
|
62533
|
+
stdio: [stdin, "ignore", "pipe"]
|
|
62478
62534
|
});
|
|
62479
62535
|
let stderr = "";
|
|
62480
|
-
child.stderr
|
|
62481
|
-
|
|
62536
|
+
const stderrStream = child.stderr;
|
|
62537
|
+
if (stderrStream === null) {
|
|
62538
|
+
child.kill();
|
|
62539
|
+
reject(new Error(`Could not capture stderr from ${executable}`));
|
|
62540
|
+
return;
|
|
62541
|
+
}
|
|
62542
|
+
stderrStream.setEncoding("utf8");
|
|
62543
|
+
stderrStream.on("data", (chunk) => {
|
|
62482
62544
|
stderr += chunk;
|
|
62483
62545
|
});
|
|
62484
62546
|
child.on("error", reject);
|
|
62485
62547
|
child.on("close", (exitCode) => {
|
|
62486
62548
|
resolve4({ exitCode: exitCode ?? 1, stderr: stderr.trim() });
|
|
62487
62549
|
});
|
|
62550
|
+
if (input !== undefined) {
|
|
62551
|
+
const stdinStream = child.stdin;
|
|
62552
|
+
if (stdinStream === null) {
|
|
62553
|
+
child.kill();
|
|
62554
|
+
reject(new Error(`Could not send input to ${executable}`));
|
|
62555
|
+
return;
|
|
62556
|
+
}
|
|
62557
|
+
stdinStream.end(input);
|
|
62558
|
+
}
|
|
62488
62559
|
});
|
|
62489
|
-
var
|
|
62560
|
+
var runNpm = (arguments_) => {
|
|
62561
|
+
const executable = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
62562
|
+
return runProcess(executable, arguments_);
|
|
62563
|
+
};
|
|
62564
|
+
var installerUrl = "https://hacktheandes.com/install";
|
|
62565
|
+
var runInstaller = async (installDirectory) => {
|
|
62566
|
+
const response = await fetch(installerUrl);
|
|
62567
|
+
if (!response.ok) {
|
|
62568
|
+
throw new Error(`installer download returned HTTP ${response.status}`);
|
|
62569
|
+
}
|
|
62570
|
+
const script = await response.text();
|
|
62571
|
+
const arguments_ = [
|
|
62572
|
+
"-s",
|
|
62573
|
+
"--",
|
|
62574
|
+
"--install-dir",
|
|
62575
|
+
installDirectory,
|
|
62576
|
+
"--no-modify-path"
|
|
62577
|
+
];
|
|
62578
|
+
if (process.platform === "win32") {
|
|
62579
|
+
arguments_.push("--defer-until-pid", String(process.pid));
|
|
62580
|
+
}
|
|
62581
|
+
return runProcess("bash", arguments_, script);
|
|
62582
|
+
};
|
|
62583
|
+
var isStandaloneExecutable = () => typeof Bun !== "undefined" && Bun.isStandaloneExecutable;
|
|
62584
|
+
var assertSuccessful = (result3, program) => {
|
|
62585
|
+
if (result3.exitCode === 0)
|
|
62586
|
+
return;
|
|
62587
|
+
let detail = "";
|
|
62588
|
+
if (result3.stderr)
|
|
62589
|
+
detail = `: ${result3.stderr}`;
|
|
62590
|
+
throw new Error(`${program} exited with code ${result3.exitCode}${detail}`);
|
|
62591
|
+
};
|
|
62592
|
+
var upgradeCli = async (options = {}) => {
|
|
62593
|
+
const standalone = options.standalone ?? isStandaloneExecutable();
|
|
62594
|
+
if (standalone) {
|
|
62595
|
+
const runner2 = options.installerRunner ?? runInstaller;
|
|
62596
|
+
const result3 = await runner2(dirname2(process.execPath));
|
|
62597
|
+
assertSuccessful(result3, "installer");
|
|
62598
|
+
return;
|
|
62599
|
+
}
|
|
62600
|
+
const runner = options.npmRunner ?? runNpm;
|
|
62490
62601
|
const cacheDirectory = await mkdtemp2(join3(tmpdir2(), "chofex-npm-cache-"));
|
|
62491
62602
|
try {
|
|
62492
62603
|
const result3 = await runner(npmUpgradeArguments(cacheDirectory));
|
|
62493
|
-
|
|
62494
|
-
return;
|
|
62495
|
-
let detail = "";
|
|
62496
|
-
if (result3.stderr)
|
|
62497
|
-
detail = `: ${result3.stderr}`;
|
|
62498
|
-
throw new Error(`npm exited with code ${result3.exitCode}${detail}`);
|
|
62604
|
+
assertSuccessful(result3, "npm");
|
|
62499
62605
|
} finally {
|
|
62500
62606
|
await rm2(cacheDirectory, { recursive: true, force: true });
|
|
62501
62607
|
}
|
|
@@ -62633,17 +62739,18 @@ var confirmCommand = exports_Command.make("confirm", {
|
|
|
62633
62739
|
]));
|
|
62634
62740
|
var loginCommand = exports_Command.make("login", {}, exports_Effect.fn("loginCommand")(function* () {
|
|
62635
62741
|
const options = yield* root;
|
|
62636
|
-
const operation = exports_Effect.
|
|
62637
|
-
|
|
62638
|
-
|
|
62639
|
-
|
|
62640
|
-
|
|
62641
|
-
|
|
62642
|
-
|
|
62643
|
-
|
|
62644
|
-
|
|
62645
|
-
|
|
62646
|
-
|
|
62742
|
+
const operation = exports_Effect.gen(function* () {
|
|
62743
|
+
const token = yield* exports_Effect.tryPromise({
|
|
62744
|
+
try: () => login(),
|
|
62745
|
+
catch: (error2) => cliError("LOGIN_FAILED", String(error2))
|
|
62746
|
+
});
|
|
62747
|
+
yield* getCurrentUser({ apiUrl: options.apiUrl, token }).pipe(exports_Effect.catch(() => exports_Effect.succeed(undefined)));
|
|
62748
|
+
return {
|
|
62749
|
+
version: 1,
|
|
62750
|
+
ok: true,
|
|
62751
|
+
requestId: crypto.randomUUID(),
|
|
62752
|
+
data: { authenticated: true }
|
|
62753
|
+
};
|
|
62647
62754
|
});
|
|
62648
62755
|
yield* execute(options.output, operation, () => "Signed in successfully.");
|
|
62649
62756
|
})).pipe(exports_Command.withDescription("Sign in through Clerk OAuth in your browser"));
|
|
@@ -62693,7 +62800,7 @@ var makeUpgradeCommand = (name) => exports_Command.make(name, {}, exports_Effect
|
|
|
62693
62800
|
}
|
|
62694
62801
|
};
|
|
62695
62802
|
},
|
|
62696
|
-
catch: (error2) => cliError("UPGRADE_FAILED", `
|
|
62803
|
+
catch: (error2) => cliError("UPGRADE_FAILED", `Could not update ${cliPackageName}`, false, String(error2))
|
|
62697
62804
|
});
|
|
62698
62805
|
yield* execute(options.output, operation, () => `Updated ${cliPackageName} to the ${upgradeVersion} version.`);
|
|
62699
62806
|
})).pipe(exports_Command.withDescription("Update chofex-cli to the latest version"));
|
|
@@ -62929,8 +63036,13 @@ ${shortcuts.flatMap((line) => wrap(line, width)).join(`
|
|
|
62929
63036
|
};
|
|
62930
63037
|
|
|
62931
63038
|
// src/index.ts
|
|
62932
|
-
var
|
|
62933
|
-
|
|
63039
|
+
var readCliVersion = () => {
|
|
63040
|
+
if (typeof CHOFEX_VERSION !== "undefined")
|
|
63041
|
+
return CHOFEX_VERSION;
|
|
63042
|
+
const packageMetadata = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
63043
|
+
return packageMetadata.version;
|
|
63044
|
+
};
|
|
63045
|
+
var cliVersion = readCliVersion();
|
|
62934
63046
|
var arguments_ = process.argv.slice(2);
|
|
62935
63047
|
var jsonOutputRequested = (arguments_2) => {
|
|
62936
63048
|
if (arguments_2.includes("--output=json"))
|