standout 0.5.19 → 0.5.21
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/wrapped/aggregate.js +10 -2
- package/dist/wrapped/preview.js +1 -1
- package/dist/wrapped-client.js +62 -22
- package/package.json +1 -1
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// Builds a strongly-typed view for the renderer from the loosely-typed
|
|
2
|
+
// /api/public/wrapped/[id] response. We probe defensively because both the
|
|
3
|
+
// `profile` (CLI gather output) and `computed` (server-generated) shapes can
|
|
4
|
+
// drift independently from the renderer.
|
|
5
|
+
// Display-only inflation of the community size on user-facing surfaces; never
|
|
6
|
+
// feeds any ranking/percentile math (those use the raw cohort arrays).
|
|
7
|
+
const WRAPPED_COMMUNITY_BOOST = 1000;
|
|
8
|
+
const boostCommunity = (n) => n > 0 ? n + WRAPPED_COMMUNITY_BOOST : 0;
|
|
1
9
|
const SOURCES = ["claude_code", "codex", "cursor"];
|
|
2
10
|
const TOOL_LABELS = {
|
|
3
11
|
claude_code: "Claude Code",
|
|
@@ -445,14 +453,14 @@ export function aggregateView(args) {
|
|
|
445
453
|
rhythm_comment: strOrNull(cardComments.rhythm),
|
|
446
454
|
stack_comment: strOrNull(cardComments.stack),
|
|
447
455
|
early_adopter: earlyAdopter,
|
|
448
|
-
cohort_size: cohortSize,
|
|
456
|
+
cohort_size: boostCommunity(cohortSize),
|
|
449
457
|
percentile_bands: {
|
|
450
458
|
typescript_shippers: percentileBands.typescript_shippers ?? null,
|
|
451
459
|
ai_native: percentileBands.ai_native ?? null,
|
|
452
460
|
open_source: percentileBands.open_source ?? null,
|
|
453
461
|
},
|
|
454
462
|
rank_summary: {
|
|
455
|
-
sample_size: rankSummary.sample_size ?? 0,
|
|
463
|
+
sample_size: boostCommunity(rankSummary.sample_size ?? 0),
|
|
456
464
|
hours_percentile: rankSummary.hours_percentile ?? null,
|
|
457
465
|
sessions_percentile: rankSummary.sessions_percentile ?? null,
|
|
458
466
|
active_days_percentile: rankSummary.active_days_percentile ?? null,
|
package/dist/wrapped/preview.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Dev preview of the proficiency finale card for every score tier.
|
|
2
|
-
// npm run preview:tiers (from packages/
|
|
2
|
+
// npm run preview:tiers (from packages/standout)
|
|
3
3
|
// One representative profile per tier so you can eyeball figures, copy, and fit.
|
|
4
4
|
import { cardProficiency } from "./render.js";
|
|
5
5
|
import { TIERS } from "./tiers.js";
|
package/dist/wrapped-client.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// PUBLISHING: this is shipped npm package code. Any runtime change here must bump
|
|
2
|
+
// "version" in package.json in the same PR — that bump is the ONLY trigger for the
|
|
3
|
+
// npm publish on merge. Land a change without it and the fix never reaches users.
|
|
1
4
|
import { STANDOUT_API_URL } from "./api.js";
|
|
2
5
|
import { aggregateView } from "./wrapped/aggregate.js";
|
|
3
6
|
const HEADERS = {
|
|
@@ -6,31 +9,68 @@ const HEADERS = {
|
|
|
6
9
|
// node-fetch UAs on certain paths. Set a clear identity.
|
|
7
10
|
"User-Agent": "Standout/0.4.0 (node)",
|
|
8
11
|
};
|
|
12
|
+
// The request holds a connection open while the backend runs the wrapped's
|
|
13
|
+
// LLM cards, so a transient blip shouldn't permanently drop the wrapped.
|
|
14
|
+
const MAX_ATTEMPTS = 3;
|
|
15
|
+
// Comfortably above the backend's worst-case critical path, below its 300s cap.
|
|
16
|
+
const REQUEST_TIMEOUT_MS = 120000;
|
|
17
|
+
const RETRY_BASE_DELAY_MS = 1000;
|
|
18
|
+
// Wrapped creation is NOT idempotent — each POST makes a new row + LLM run. Only
|
|
19
|
+
// retry failures that prove the request never reached the backend; a timeout or a
|
|
20
|
+
// mid-flight drop may mean the server already created it, so replaying would
|
|
21
|
+
// duplicate the wrapped.
|
|
22
|
+
const RETRYABLE_CONNECT_CODES = new Set([
|
|
23
|
+
"ECONNREFUSED",
|
|
24
|
+
"ENOTFOUND",
|
|
25
|
+
"EAI_AGAIN",
|
|
26
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
27
|
+
]);
|
|
28
|
+
function isPreConnectError(err) {
|
|
29
|
+
for (const node of [err, err?.cause]) {
|
|
30
|
+
const code = node?.code;
|
|
31
|
+
if (typeof code === "string" && RETRYABLE_CONNECT_CODES.has(code)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
9
38
|
export async function createWrapped(args) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
39
|
+
const body = JSON.stringify({
|
|
40
|
+
profile: args.profile,
|
|
41
|
+
submission_id: args.submissionId ?? undefined,
|
|
42
|
+
});
|
|
43
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
44
|
+
try {
|
|
45
|
+
const res = await fetch(`${STANDOUT_API_URL}/api/public/wrapped`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: HEADERS,
|
|
48
|
+
body,
|
|
49
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
50
|
+
});
|
|
51
|
+
// Any HTTP response means the request reached the server; don't replay it
|
|
52
|
+
// (a 5xx could land after the row was already created).
|
|
53
|
+
if (!res.ok) {
|
|
54
|
+
const text = await res.text().catch(() => "");
|
|
55
|
+
process.stderr.write(`[wrapped] backend returned ${res.status}${text ? `: ${text.slice(0, 200)}` : ""}\n`);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const data = (await res.json());
|
|
59
|
+
const view = aggregateView({
|
|
15
60
|
profile: args.profile,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
61
|
+
computed: data.computed,
|
|
62
|
+
share_url: data.share_url,
|
|
63
|
+
});
|
|
64
|
+
return { id: data.id, share_url: data.share_url, view };
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
if (isPreConnectError(err) && attempt < MAX_ATTEMPTS) {
|
|
68
|
+
await sleep(RETRY_BASE_DELAY_MS * attempt);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
process.stderr.write(`[wrapped] failed to reach backend: ${err instanceof Error ? err.message : err}\n`);
|
|
22
72
|
return null;
|
|
23
73
|
}
|
|
24
|
-
const data = (await res.json());
|
|
25
|
-
const view = aggregateView({
|
|
26
|
-
profile: args.profile,
|
|
27
|
-
computed: data.computed,
|
|
28
|
-
share_url: data.share_url,
|
|
29
|
-
});
|
|
30
|
-
return { id: data.id, share_url: data.share_url, view };
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
process.stderr.write(`[wrapped] failed to reach backend: ${err instanceof Error ? err.message : err}\n`);
|
|
34
|
-
return null;
|
|
35
74
|
}
|
|
75
|
+
return null;
|
|
36
76
|
}
|