whoburnedmore 0.9.7 → 0.9.9
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 +123 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -167,11 +167,40 @@ async function devicePoll(deviceCode) {
|
|
|
167
167
|
}
|
|
168
168
|
return body;
|
|
169
169
|
}
|
|
170
|
+
async function refreshCliToken(anonKey) {
|
|
171
|
+
try {
|
|
172
|
+
const { status, body } = await post("/v1/auth/cli/refresh", { anonKey });
|
|
173
|
+
if (status === 200 && typeof body.token === "string" && body.token) {
|
|
174
|
+
return { token: body.token, handle: body.handle ?? "" };
|
|
175
|
+
}
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
async function bindDeviceKey(token, anonKey) {
|
|
181
|
+
try {
|
|
182
|
+
const { status } = await post(
|
|
183
|
+
"/v1/me/devices/bind",
|
|
184
|
+
{ anonKey },
|
|
185
|
+
token
|
|
186
|
+
);
|
|
187
|
+
return status === 200 || status === 409;
|
|
188
|
+
} catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
170
192
|
async function submit(token, payload) {
|
|
171
193
|
const { status, body } = await post("/v1/submit", payload, token);
|
|
172
194
|
if (status === 401) throw new UnauthorizedError();
|
|
173
195
|
if (status !== 200) {
|
|
174
196
|
const err = body;
|
|
197
|
+
if (status === 403 && err.error === "account blocked") {
|
|
198
|
+
const reason = err.reason ? `
|
|
199
|
+
Reason: ${err.reason}` : "";
|
|
200
|
+
const appeal = err.appealUrl ? `
|
|
201
|
+
If you think this is a mistake, appeal at: ${err.appealUrl}` : "";
|
|
202
|
+
throw new Error(`Your account is blocked.${reason}${appeal}`);
|
|
203
|
+
}
|
|
175
204
|
const details = err.details?.length ? `
|
|
176
205
|
- ${err.details.join("\n - ")}` : "";
|
|
177
206
|
throw new Error(`${err.error ?? `submit failed (HTTP ${status})`}${details}`);
|
|
@@ -260,6 +289,9 @@ function loadConfig(dir = defaultConfigDir()) {
|
|
|
260
289
|
if (typeof parsed.launchNotificationDeliveredAt === "number" && Number.isFinite(parsed.launchNotificationDeliveredAt)) {
|
|
261
290
|
config.launchNotificationDeliveredAt = parsed.launchNotificationDeliveredAt;
|
|
262
291
|
}
|
|
292
|
+
if (typeof parsed.deviceBoundAt === "number" && Number.isFinite(parsed.deviceBoundAt)) {
|
|
293
|
+
config.deviceBoundAt = parsed.deviceBoundAt;
|
|
294
|
+
}
|
|
263
295
|
return Object.keys(config).length > 0 ? config : null;
|
|
264
296
|
} catch {
|
|
265
297
|
return null;
|
|
@@ -295,6 +327,10 @@ function recordSync(dir = defaultConfigDir(), when = Date.now()) {
|
|
|
295
327
|
const config = loadConfig(dir) ?? {};
|
|
296
328
|
saveConfig(dir, { ...config, lastSyncAt: when });
|
|
297
329
|
}
|
|
330
|
+
function recordDeviceBound(dir = defaultConfigDir(), when = Date.now()) {
|
|
331
|
+
const config = loadConfig(dir) ?? {};
|
|
332
|
+
saveConfig(dir, { ...config, deviceBoundAt: when });
|
|
333
|
+
}
|
|
298
334
|
function saveAuth(dir = defaultConfigDir(), auth = { cliToken: "" }) {
|
|
299
335
|
const config = loadConfig(dir) ?? {};
|
|
300
336
|
saveConfig(dir, { ...config, cliToken: auth.cliToken, handle: auth.handle });
|
|
@@ -6944,13 +6980,40 @@ var RESERVED_SLUGS = /* @__PURE__ */ new Set([
|
|
|
6944
6980
|
"robots",
|
|
6945
6981
|
"sitemap"
|
|
6946
6982
|
]);
|
|
6983
|
+
var ORG_TEXT_BLOCKLIST = /* @__PURE__ */ new Set([
|
|
6984
|
+
"nigger",
|
|
6985
|
+
"nigga",
|
|
6986
|
+
"faggot",
|
|
6987
|
+
"retard",
|
|
6988
|
+
"rape",
|
|
6989
|
+
"rapist",
|
|
6990
|
+
"kike",
|
|
6991
|
+
"spic",
|
|
6992
|
+
"chink",
|
|
6993
|
+
"cunt"
|
|
6994
|
+
]);
|
|
6995
|
+
var ORG_TEXT_LEET = {
|
|
6996
|
+
"0": "o",
|
|
6997
|
+
"1": "i",
|
|
6998
|
+
"3": "e",
|
|
6999
|
+
"4": "a",
|
|
7000
|
+
"5": "s",
|
|
7001
|
+
"7": "t",
|
|
7002
|
+
"8": "b",
|
|
7003
|
+
"@": "a",
|
|
7004
|
+
"$": "s"
|
|
7005
|
+
};
|
|
7006
|
+
function isCleanOrgText(input) {
|
|
7007
|
+
const runs = String(input).toLowerCase().split(/[^a-z0-9@$]+/).map((run2) => run2.replace(/[0-9@$]/g, (c) => ORG_TEXT_LEET[c] ?? c).replace(/[^a-z]/g, ""));
|
|
7008
|
+
return !runs.some((run2) => run2.length > 0 && ORG_TEXT_BLOCKLIST.has(run2));
|
|
7009
|
+
}
|
|
6947
7010
|
var SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$/;
|
|
6948
7011
|
function isValidSlug(slug) {
|
|
6949
7012
|
return typeof slug === "string" && slug.length >= 2 && slug.length <= 32 && SLUG_RE.test(slug) && // Reject consecutive hyphens — the regex above permits "a--b", which makes
|
|
6950
7013
|
// for confusing subdomains and is never a deliberate slug.
|
|
6951
7014
|
!slug.includes("--") && !RESERVED_SLUGS.has(slug);
|
|
6952
7015
|
}
|
|
6953
|
-
var OrgSlug = external_exports.string().min(2).max(32).refine(isValidSlug, "invalid or reserved slug");
|
|
7016
|
+
var OrgSlug = external_exports.string().min(2).max(32).refine(isValidSlug, "invalid or reserved slug").refine(isCleanOrgText, "invalid or reserved slug");
|
|
6954
7017
|
var OrgWindow = external_exports.object({
|
|
6955
7018
|
startDate: DateString.nullable().optional(),
|
|
6956
7019
|
endDate: DateString.nullable().optional()
|
|
@@ -6994,11 +7057,21 @@ var OrgProvisionInput = external_exports.object({
|
|
|
6994
7057
|
*/
|
|
6995
7058
|
issueClaimLink: external_exports.boolean().optional()
|
|
6996
7059
|
});
|
|
7060
|
+
var OrgSelfServeInput = external_exports.object({
|
|
7061
|
+
slug: OrgSlug,
|
|
7062
|
+
name: external_exports.string().min(1).max(120).refine(isCleanOrgText, "name not allowed"),
|
|
7063
|
+
type: OrgType,
|
|
7064
|
+
description: external_exports.string().max(2e3).optional(),
|
|
7065
|
+
accentColor: HexColor.optional(),
|
|
7066
|
+
/** Who can view the board — defaults to the type's default when omitted. */
|
|
7067
|
+
boardVisibility: OrgBoardVisibility.optional(),
|
|
7068
|
+
/** Optional event window (mainly for hackathons). */
|
|
7069
|
+
window: OrgWindow.optional()
|
|
7070
|
+
});
|
|
6997
7071
|
var OrgSettingsInput = external_exports.object({
|
|
6998
7072
|
name: external_exports.string().min(1).max(120).optional(),
|
|
6999
7073
|
description: external_exports.string().max(2e3).nullable().optional(),
|
|
7000
7074
|
accentColor: HexColor.optional(),
|
|
7001
|
-
logoUrl: external_exports.string().url().max(500).nullable().optional(),
|
|
7002
7075
|
boardVisibility: OrgBoardVisibility.optional(),
|
|
7003
7076
|
window: OrgWindow.optional(),
|
|
7004
7077
|
joinPolicy: OrgJoinPolicy.partial().optional()
|
|
@@ -8243,6 +8316,12 @@ async function run(flags) {
|
|
|
8243
8316
|
const canSignIn = !flags.quiet && Boolean(process.stdout.isTTY);
|
|
8244
8317
|
if (cfg?.cliToken) {
|
|
8245
8318
|
await submitSignedIn(cfg.cliToken, payload, flags, canSignIn);
|
|
8319
|
+
return;
|
|
8320
|
+
}
|
|
8321
|
+
const healed = cfg?.anonKey ? await refreshCliToken(cfg.anonKey) : null;
|
|
8322
|
+
if (healed) {
|
|
8323
|
+
saveAuth(void 0, { cliToken: healed.token, handle: healed.handle });
|
|
8324
|
+
await submitSignedIn(healed.token, payload, flags, canSignIn);
|
|
8246
8325
|
} else if (canSignIn) {
|
|
8247
8326
|
const auth = await ensureSignedIn();
|
|
8248
8327
|
if (!auth) return;
|
|
@@ -8261,6 +8340,11 @@ async function run(flags) {
|
|
|
8261
8340
|
function sleep(ms) {
|
|
8262
8341
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8263
8342
|
}
|
|
8343
|
+
async function refreshCliTokenFromConfig() {
|
|
8344
|
+
const cfg = loadConfig();
|
|
8345
|
+
if (!cfg?.anonKey) return null;
|
|
8346
|
+
return refreshCliToken(cfg.anonKey);
|
|
8347
|
+
}
|
|
8264
8348
|
async function ensureSignedIn() {
|
|
8265
8349
|
const cfg = loadConfig();
|
|
8266
8350
|
if (cfg?.cliToken) return { token: cfg.cliToken, handle: cfg.handle ?? "" };
|
|
@@ -8300,16 +8384,25 @@ async function ensureSignedIn() {
|
|
|
8300
8384
|
return null;
|
|
8301
8385
|
}
|
|
8302
8386
|
async function submitSignedIn(token, payload, flags, interactive) {
|
|
8387
|
+
let activeToken = token;
|
|
8303
8388
|
let result;
|
|
8304
8389
|
try {
|
|
8305
8390
|
result = await submit(token, payload);
|
|
8306
8391
|
} catch (err) {
|
|
8307
8392
|
if (err instanceof UnauthorizedError) {
|
|
8308
|
-
|
|
8309
|
-
if (
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8393
|
+
const healed = await refreshCliTokenFromConfig();
|
|
8394
|
+
if (healed) {
|
|
8395
|
+
saveAuth(void 0, { cliToken: healed.token, handle: healed.handle });
|
|
8396
|
+
activeToken = healed.token;
|
|
8397
|
+
result = await submit(healed.token, payload);
|
|
8398
|
+
} else {
|
|
8399
|
+
clearAuth();
|
|
8400
|
+
if (!interactive) return;
|
|
8401
|
+
const auth = await ensureSignedIn();
|
|
8402
|
+
if (!auth) return;
|
|
8403
|
+
activeToken = auth.token;
|
|
8404
|
+
result = await submit(auth.token, payload);
|
|
8405
|
+
}
|
|
8313
8406
|
} else {
|
|
8314
8407
|
throw err;
|
|
8315
8408
|
}
|
|
@@ -8318,6 +8411,14 @@ async function submitSignedIn(token, payload, flags, interactive) {
|
|
|
8318
8411
|
recordSync();
|
|
8319
8412
|
} catch {
|
|
8320
8413
|
}
|
|
8414
|
+
try {
|
|
8415
|
+
const cfgNow = loadConfig();
|
|
8416
|
+
if (!cfgNow?.deviceBoundAt) {
|
|
8417
|
+
const key = ensureAnonKey();
|
|
8418
|
+
if (await bindDeviceKey(activeToken, key)) recordDeviceBound();
|
|
8419
|
+
}
|
|
8420
|
+
} catch {
|
|
8421
|
+
}
|
|
8321
8422
|
const baseUrl = result.orgBoardUrl ?? result.boardUrl ?? result.profileUrl;
|
|
8322
8423
|
if (!flags.quiet) {
|
|
8323
8424
|
console.log(
|
|
@@ -8346,6 +8447,20 @@ async function submitSignedIn(token, payload, flags, interactive) {
|
|
|
8346
8447
|
)
|
|
8347
8448
|
);
|
|
8348
8449
|
}
|
|
8450
|
+
if (result.quarantinedDates && result.quarantinedDates.length > 0) {
|
|
8451
|
+
const days = result.quarantinedDates.map((d) => sanitizeServerText(d)).join(", ");
|
|
8452
|
+
console.log();
|
|
8453
|
+
console.log(
|
|
8454
|
+
pc2.yellow(
|
|
8455
|
+
` \u26A0 These day(s) were held off the leaderboard as an anomaly: ${days}`
|
|
8456
|
+
)
|
|
8457
|
+
);
|
|
8458
|
+
console.log(
|
|
8459
|
+
pc2.dim(
|
|
8460
|
+
" Your data is kept, not deleted. Run `npx whoburnedmore verify` to get back on the board, or appeal at whoburnedmore.com/appeal to have these days reviewed and restored."
|
|
8461
|
+
)
|
|
8462
|
+
);
|
|
8463
|
+
}
|
|
8349
8464
|
if (isTrustedWebUrl(baseUrl)) {
|
|
8350
8465
|
console.log(pc2.dim(" Opening your dashboard in your browser\u2026"));
|
|
8351
8466
|
openBrowser(baseUrl);
|
|
@@ -8643,7 +8758,7 @@ function printHelp() {
|
|
|
8643
8758
|
${pc2.bold("usage")}
|
|
8644
8759
|
npx whoburnedmore sign in, burn + land on the public leaderboard, open your dashboard
|
|
8645
8760
|
npx whoburnedmore --board=CODE compare with friends \u2014 sign in and join their board
|
|
8646
|
-
npx whoburnedmore --org=SLUG
|
|
8761
|
+
npx whoburnedmore --org=SLUG --pass=CODE join your organization's board (companies/hackathons)
|
|
8647
8762
|
npx whoburnedmore --local build the dashboard on your machine and open it (offline)
|
|
8648
8763
|
npx whoburnedmore --dry-run print exactly what would be sent, send nothing
|
|
8649
8764
|
npx whoburnedmore --no-submit collect locally, send nothing (no dashboard)
|