@ttctl/core 0.0.0 → 0.1.0-rc.1
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/README.md +49 -9
- package/dist/__generated__/gateway.d.ts +4546 -0
- package/dist/__generated__/gateway.d.ts.map +1 -0
- package/dist/__generated__/gateway.js +9 -0
- package/dist/__generated__/gateway.js.map +1 -0
- package/dist/__generated__/talent-profile-zod-schemas.d.ts +1187 -0
- package/dist/__generated__/talent-profile-zod-schemas.d.ts.map +1 -0
- package/dist/__generated__/talent-profile-zod-schemas.js +1136 -0
- package/dist/__generated__/talent-profile-zod-schemas.js.map +1 -0
- package/dist/__generated__/talent-profile.d.ts +1397 -0
- package/dist/__generated__/talent-profile.d.ts.map +1 -0
- package/dist/__generated__/talent-profile.js +9 -0
- package/dist/__generated__/talent-profile.js.map +1 -0
- package/dist/__generated__/zod-schemas.d.ts +2895 -0
- package/dist/__generated__/zod-schemas.d.ts.map +1 -0
- package/dist/__generated__/zod-schemas.js +3121 -0
- package/dist/__generated__/zod-schemas.js.map +1 -0
- package/dist/__tests__/fixtures/profile/builders.d.ts +74 -0
- package/dist/__tests__/fixtures/profile/builders.d.ts.map +1 -0
- package/dist/__tests__/fixtures/profile/builders.js +196 -0
- package/dist/__tests__/fixtures/profile/builders.js.map +1 -0
- package/dist/__tests__/fixtures/profile/data.d.ts +39 -0
- package/dist/__tests__/fixtures/profile/data.d.ts.map +1 -0
- package/dist/__tests__/fixtures/profile/data.js +230 -0
- package/dist/__tests__/fixtures/profile/data.js.map +1 -0
- package/dist/__tests__/fixtures/profile/index.d.ts +9 -0
- package/dist/__tests__/fixtures/profile/index.d.ts.map +1 -0
- package/dist/__tests__/fixtures/profile/index.js +10 -0
- package/dist/__tests__/fixtures/profile/index.js.map +1 -0
- package/dist/__tests__/fixtures/profile/types.d.ts +53 -0
- package/dist/__tests__/fixtures/profile/types.d.ts.map +1 -0
- package/dist/__tests__/fixtures/profile/types.js +4 -0
- package/dist/__tests__/fixtures/profile/types.js.map +1 -0
- package/dist/auth/errors.d.ts +82 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/errors.js +68 -0
- package/dist/auth/errors.js.map +1 -0
- package/dist/auth.d.ts +192 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +294 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +212 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +349 -0
- package/dist/config.js.map +1 -0
- package/dist/configLock.d.ts +50 -0
- package/dist/configLock.d.ts.map +1 -0
- package/dist/configLock.js +88 -0
- package/dist/configLock.js.map +1 -0
- package/dist/configWriter.d.ts +97 -0
- package/dist/configWriter.d.ts.map +1 -0
- package/dist/configWriter.js +687 -0
- package/dist/configWriter.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/kill-switch.d.ts +161 -0
- package/dist/kill-switch.d.ts.map +1 -0
- package/dist/kill-switch.js +235 -0
- package/dist/kill-switch.js.map +1 -0
- package/dist/lib/date.d.ts +58 -0
- package/dist/lib/date.d.ts.map +1 -0
- package/dist/lib/date.js +104 -0
- package/dist/lib/date.js.map +1 -0
- package/dist/lib/diagnostic-log.d.ts +159 -0
- package/dist/lib/diagnostic-log.d.ts.map +1 -0
- package/dist/lib/diagnostic-log.js +186 -0
- package/dist/lib/diagnostic-log.js.map +1 -0
- package/dist/lib/package-version.d.ts +19 -0
- package/dist/lib/package-version.d.ts.map +1 -0
- package/dist/lib/package-version.js +38 -0
- package/dist/lib/package-version.js.map +1 -0
- package/dist/lib/redact.d.ts +153 -0
- package/dist/lib/redact.d.ts.map +1 -0
- package/dist/lib/redact.js +207 -0
- package/dist/lib/redact.js.map +1 -0
- package/dist/lib/text.d.ts +14 -0
- package/dist/lib/text.d.ts.map +1 -0
- package/dist/lib/text.js +21 -0
- package/dist/lib/text.js.map +1 -0
- package/dist/lib/wire-shape.d.ts +131 -0
- package/dist/lib/wire-shape.d.ts.map +1 -0
- package/dist/lib/wire-shape.js +376 -0
- package/dist/lib/wire-shape.js.map +1 -0
- package/dist/onepassword.d.ts +29 -0
- package/dist/onepassword.d.ts.map +1 -0
- package/dist/onepassword.js +112 -0
- package/dist/onepassword.js.map +1 -0
- package/dist/services/_shared/transport.d.ts +148 -0
- package/dist/services/_shared/transport.d.ts.map +1 -0
- package/dist/services/_shared/transport.js +102 -0
- package/dist/services/_shared/transport.js.map +1 -0
- package/dist/services/applications/index.d.ts +210 -0
- package/dist/services/applications/index.d.ts.map +1 -0
- package/dist/services/applications/index.js +240 -0
- package/dist/services/applications/index.js.map +1 -0
- package/dist/services/availability/index.d.ts +254 -0
- package/dist/services/availability/index.d.ts.map +1 -0
- package/dist/services/availability/index.js +310 -0
- package/dist/services/availability/index.js.map +1 -0
- package/dist/services/contracts/index.d.ts +132 -0
- package/dist/services/contracts/index.d.ts.map +1 -0
- package/dist/services/contracts/index.js +211 -0
- package/dist/services/contracts/index.js.map +1 -0
- package/dist/services/engagements/index.d.ts +504 -0
- package/dist/services/engagements/index.d.ts.map +1 -0
- package/dist/services/engagements/index.js +613 -0
- package/dist/services/engagements/index.js.map +1 -0
- package/dist/services/jobs/index.d.ts +490 -0
- package/dist/services/jobs/index.d.ts.map +1 -0
- package/dist/services/jobs/index.js +753 -0
- package/dist/services/jobs/index.js.map +1 -0
- package/dist/services/payments/index.d.ts +415 -0
- package/dist/services/payments/index.d.ts.map +1 -0
- package/dist/services/payments/index.js +636 -0
- package/dist/services/payments/index.js.map +1 -0
- package/dist/services/profile/__tests__/fixtures.d.ts +214 -0
- package/dist/services/profile/__tests__/fixtures.d.ts.map +1 -0
- package/dist/services/profile/__tests__/fixtures.js +176 -0
- package/dist/services/profile/__tests__/fixtures.js.map +1 -0
- package/dist/services/profile/basic/index.d.ts +390 -0
- package/dist/services/profile/basic/index.d.ts.map +1 -0
- package/dist/services/profile/basic/index.js +1007 -0
- package/dist/services/profile/basic/index.js.map +1 -0
- package/dist/services/profile/certifications/index.d.ts +74 -0
- package/dist/services/profile/certifications/index.d.ts.map +1 -0
- package/dist/services/profile/certifications/index.js +169 -0
- package/dist/services/profile/certifications/index.js.map +1 -0
- package/dist/services/profile/education/index.d.ts +73 -0
- package/dist/services/profile/education/index.d.ts.map +1 -0
- package/dist/services/profile/education/index.js +168 -0
- package/dist/services/profile/education/index.js.map +1 -0
- package/dist/services/profile/employment/index.d.ts +111 -0
- package/dist/services/profile/employment/index.d.ts.map +1 -0
- package/dist/services/profile/employment/index.js +202 -0
- package/dist/services/profile/employment/index.js.map +1 -0
- package/dist/services/profile/external/index.d.ts +219 -0
- package/dist/services/profile/external/index.d.ts.map +1 -0
- package/dist/services/profile/external/index.js +560 -0
- package/dist/services/profile/external/index.js.map +1 -0
- package/dist/services/profile/index.d.ts +24 -0
- package/dist/services/profile/index.d.ts.map +1 -0
- package/dist/services/profile/index.js +26 -0
- package/dist/services/profile/index.js.map +1 -0
- package/dist/services/profile/industries/index.d.ts +130 -0
- package/dist/services/profile/industries/index.d.ts.map +1 -0
- package/dist/services/profile/industries/index.js +292 -0
- package/dist/services/profile/industries/index.js.map +1 -0
- package/dist/services/profile/portfolio/index.d.ts +352 -0
- package/dist/services/profile/portfolio/index.d.ts.map +1 -0
- package/dist/services/profile/portfolio/index.js +833 -0
- package/dist/services/profile/portfolio/index.js.map +1 -0
- package/dist/services/profile/resume/index.d.ts +60 -0
- package/dist/services/profile/resume/index.d.ts.map +1 -0
- package/dist/services/profile/resume/index.js +212 -0
- package/dist/services/profile/resume/index.js.map +1 -0
- package/dist/services/profile/reviews/index.d.ts +137 -0
- package/dist/services/profile/reviews/index.d.ts.map +1 -0
- package/dist/services/profile/reviews/index.js +431 -0
- package/dist/services/profile/reviews/index.js.map +1 -0
- package/dist/services/profile/shared.d.ts +127 -0
- package/dist/services/profile/shared.d.ts.map +1 -0
- package/dist/services/profile/shared.js +155 -0
- package/dist/services/profile/shared.js.map +1 -0
- package/dist/services/profile/skills/index.d.ts +212 -0
- package/dist/services/profile/skills/index.d.ts.map +1 -0
- package/dist/services/profile/skills/index.js +461 -0
- package/dist/services/profile/skills/index.js.map +1 -0
- package/dist/services/profile/visas/index.d.ts +74 -0
- package/dist/services/profile/visas/index.d.ts.map +1 -0
- package/dist/services/profile/visas/index.js +306 -0
- package/dist/services/profile/visas/index.js.map +1 -0
- package/dist/services/timesheet/index.d.ts +326 -0
- package/dist/services/timesheet/index.d.ts.map +1 -0
- package/dist/services/timesheet/index.js +324 -0
- package/dist/services/timesheet/index.js.map +1 -0
- package/dist/services/translations.d.ts +79 -0
- package/dist/services/translations.d.ts.map +1 -0
- package/dist/services/translations.js +136 -0
- package/dist/services/translations.js.map +1 -0
- package/dist/transport-resilience.d.ts +136 -0
- package/dist/transport-resilience.d.ts.map +1 -0
- package/dist/transport-resilience.js +247 -0
- package/dist/transport-resilience.js.map +1 -0
- package/dist/transport.d.ts +408 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +691 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -12
- package/index.js +0 -7
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type { AuthCredentials } from "./config.js";
|
|
2
|
+
import type { Credentials } from "./types.js";
|
|
3
|
+
export type SignInErrorCode = "INVALID_CREDENTIALS" | "MFA_REQUIRED" | "NETWORK_ERROR" | "UNKNOWN";
|
|
4
|
+
export declare class SignInError extends Error {
|
|
5
|
+
readonly code: SignInErrorCode;
|
|
6
|
+
readonly name = "SignInError";
|
|
7
|
+
constructor(code: SignInErrorCode, message: string, options?: {
|
|
8
|
+
cause?: unknown;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Collapse the polymorphic credentials value into resolved credentials.
|
|
13
|
+
*
|
|
14
|
+
* Form A (string) → `op://[account/]vault/item` → resolved via `op` CLI
|
|
15
|
+
* Form B (object) → literal `{ username, password }` (username is an email
|
|
16
|
+
* per Toptal's `EmailPasswordSignIn` mutation contract;
|
|
17
|
+
* the YAML field is named `username` to match 1Password's
|
|
18
|
+
* USERNAME purpose semantics)
|
|
19
|
+
*
|
|
20
|
+
* Returns the internal `Credentials` shape `{ email, password }` — that's
|
|
21
|
+
* the GraphQL parameter name for the mutation. The username/email
|
|
22
|
+
* synonymy is documented and load-bearing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveCredentials(auth: AuthCredentials): Credentials;
|
|
25
|
+
/**
|
|
26
|
+
* Sign in to Toptal Talent via `EmailPasswordSignIn` GraphQL mutation in
|
|
27
|
+
* persisted-query mode against the mobile gateway and capture the session
|
|
28
|
+
* token from the response.
|
|
29
|
+
*
|
|
30
|
+
* Returns the captured token. The CLI persists it back to the same YAML
|
|
31
|
+
* config file (under `auth.token`) via `persistAuthToken` so subsequent
|
|
32
|
+
* invocations can authenticate via `Authorization: Token token=<X>`
|
|
33
|
+
* without re-signing-in.
|
|
34
|
+
*
|
|
35
|
+
* The next authenticated call (e.g. `auth status`) is the de-facto session
|
|
36
|
+
* verifier — we do NOT issue a redundant Viewer probe inside `signIn` itself.
|
|
37
|
+
*
|
|
38
|
+
* See `hq/engineering/adr/ADR-005-auth-model.md` for the cross-surface
|
|
39
|
+
* auth model and `research/notes/02-auth-and-clients.md` for the empirical
|
|
40
|
+
* evidence behind it.
|
|
41
|
+
*
|
|
42
|
+
* Throws `SignInError("UNKNOWN", ...)` if the gateway reports `success: true`
|
|
43
|
+
* but does not return a token — that response shape is malformed and the
|
|
44
|
+
* caller has nothing useful to persist.
|
|
45
|
+
*/
|
|
46
|
+
export declare function signIn(credentials: Credentials): Promise<{
|
|
47
|
+
token: string;
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* Result of a session-validity probe. Three terminal shapes:
|
|
51
|
+
*
|
|
52
|
+
* - `valid` — `Viewer` query returned 2xx with an email; the session is
|
|
53
|
+
* active and bound to that account.
|
|
54
|
+
* - `invalid` — no token persisted, OR the gateway responded with a
|
|
55
|
+
* non-2xx status, OR the response payload lacks `viewer.viewerRole.email`.
|
|
56
|
+
* `reason` carries a stable machine-readable code so the CLI can pick the
|
|
57
|
+
* right user-facing message without re-classifying the failure.
|
|
58
|
+
* - `unreachable` — the transport itself rejected (DNS failure, connect
|
|
59
|
+
* refused, TLS handshake timeout, etc.); the gateway was never reached.
|
|
60
|
+
* This is distinguished from `invalid` so the CLI can exit 2 (transient,
|
|
61
|
+
* retryable) rather than 1 (auth problem, action required).
|
|
62
|
+
*/
|
|
63
|
+
export type AuthStatusResult = {
|
|
64
|
+
status: "valid";
|
|
65
|
+
email: string;
|
|
66
|
+
} | {
|
|
67
|
+
status: "invalid";
|
|
68
|
+
reason: AuthInvalidReason;
|
|
69
|
+
} | {
|
|
70
|
+
status: "unreachable";
|
|
71
|
+
reason: string;
|
|
72
|
+
};
|
|
73
|
+
export type AuthInvalidReason = "no-session" | "session-expired" | "no-email-in-response" | "unexpected-status";
|
|
74
|
+
/**
|
|
75
|
+
* Probe whether the persisted session token is currently valid.
|
|
76
|
+
*
|
|
77
|
+
* Issues a minimal full-doc `Viewer` query against the mobile gateway,
|
|
78
|
+
* authenticated with `Authorization: Token token=<X>`. The cataloged
|
|
79
|
+
* persisted `Viewer` query in `research/graphql/gateway/operations/mobile/Viewer.graphql`
|
|
80
|
+
* does not return `viewerRole.email`, so we can't use APQ here — see
|
|
81
|
+
* `VIEWER_VERIFY_QUERY` doc.
|
|
82
|
+
*
|
|
83
|
+
* Pass `null` (or an empty string) when no token has been persisted yet;
|
|
84
|
+
* the function short-circuits to `invalid/no-session` without touching the
|
|
85
|
+
* network. CLI consumers pass `config.auth.token ?? null` from the
|
|
86
|
+
* already-loaded `TtctlConfig` (no separate token file to read).
|
|
87
|
+
*
|
|
88
|
+
* Never throws on auth or network failure; classifies into the three
|
|
89
|
+
* `AuthStatusResult` shapes so CLI consumers can map cleanly to exit codes
|
|
90
|
+
* and output messages without re-parsing exceptions.
|
|
91
|
+
*/
|
|
92
|
+
export declare function getAuthStatus(token: string | null): Promise<AuthStatusResult>;
|
|
93
|
+
/**
|
|
94
|
+
* Stable machine-readable reason codes returned alongside `SignOutResult`'s
|
|
95
|
+
* `invalid` and `unreachable` branches. The CLI / E2E teardown render
|
|
96
|
+
* user-facing messages from these — keep the code stable, fold UX shifts
|
|
97
|
+
* into the renderer.
|
|
98
|
+
*/
|
|
99
|
+
export type SignOutInvalidReason = "no-session" | "session-expired" | "graphql-auth-error";
|
|
100
|
+
export type SignOutUnreachableReason = {
|
|
101
|
+
kind: "transport";
|
|
102
|
+
reason: string;
|
|
103
|
+
} | {
|
|
104
|
+
kind: "http-status";
|
|
105
|
+
status: number;
|
|
106
|
+
} | {
|
|
107
|
+
kind: "graphql-error";
|
|
108
|
+
message: string;
|
|
109
|
+
} | {
|
|
110
|
+
kind: "payload-missing";
|
|
111
|
+
} | {
|
|
112
|
+
kind: "success-false";
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Result of a `signOut(token)` call. Three terminal shapes mirror
|
|
116
|
+
* `AuthStatusResult`'s discriminator so call-sites can pattern-match
|
|
117
|
+
* uniformly:
|
|
118
|
+
*
|
|
119
|
+
* - `logged-out` — talent-profile responded 2xx and
|
|
120
|
+
* `data.logOut.success === true`. The `LogOut` mutation flow on the
|
|
121
|
+
* `talent_profile/graphql` surface completed; the server acknowledged
|
|
122
|
+
* the signal. **This status name is deliberate** — see the
|
|
123
|
+
* "Bearer-invalidation scope" note below. The status does NOT claim
|
|
124
|
+
* the captured bearer was revoked for downstream mobile-gateway
|
|
125
|
+
* traffic; empirical evidence (issue #180 live discovery, 2026-05-12)
|
|
126
|
+
* shows it is NOT. The status only claims the LogOut mutation itself
|
|
127
|
+
* was processed.
|
|
128
|
+
* - `invalid` — the bearer was ALREADY invalid (401/403 or a GraphQL
|
|
129
|
+
* auth-revoke code). Functionally equivalent to "already revoked" from
|
|
130
|
+
* the security standpoint — the caller's intent (kill the bearer) is
|
|
131
|
+
* satisfied. CLI / teardown should still proceed to clear the local copy.
|
|
132
|
+
* - `unreachable` — could not reach the server or could not confirm
|
|
133
|
+
* mutation processing. The LogOut signal was not delivered. Caller
|
|
134
|
+
* MUST fall through to local clear (per CLI UX recommendation) and
|
|
135
|
+
* rely on the 24-72h aging-out as the load-bearing revocation defense.
|
|
136
|
+
*
|
|
137
|
+
* **Bearer-invalidation scope** (empirical, 2026-05-12; investigation
|
|
138
|
+
* captured in `.tmp/180-delayed-probe-report.json`): The `LogOut` mutation
|
|
139
|
+
* on `talent_profile/graphql` succeeds (`data.logOut.success === true`)
|
|
140
|
+
* but does NOT propagate to bearer invalidation for subsequent
|
|
141
|
+
* `mobile-gateway` calls. Probed across t=0/30/60/180/300s; the bearer
|
|
142
|
+
* remained `{ status: "valid" }` against `getAuthStatus` for the entire
|
|
143
|
+
* 5-minute window. The 24-72h natural aging-out (documented in CLAUDE.md
|
|
144
|
+
* § Auth Model) is the load-bearing revocation defense. `signOut()` is
|
|
145
|
+
* defense-in-depth: audit log + web-session/cookie cleanup on the
|
|
146
|
+
* talent_profile side + forward-compatible call site if Toptal ever wires
|
|
147
|
+
* up server-side bearer revocation.
|
|
148
|
+
*
|
|
149
|
+
* Never throws — every failure is classified into one of the three shapes.
|
|
150
|
+
* This matches `getAuthStatus`'s contract so the call-sites that branch on
|
|
151
|
+
* `result.status` look the same on both paths.
|
|
152
|
+
*/
|
|
153
|
+
export type SignOutResult = {
|
|
154
|
+
status: "logged-out";
|
|
155
|
+
} | {
|
|
156
|
+
status: "invalid";
|
|
157
|
+
reason: SignOutInvalidReason;
|
|
158
|
+
} | {
|
|
159
|
+
status: "unreachable";
|
|
160
|
+
reason: SignOutUnreachableReason;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Issue the `LogOut` mutation server-side against the Cloudflare-protected
|
|
164
|
+
* `talent_profile/graphql` surface (defense-in-depth audit-log signal +
|
|
165
|
+
* web-session/cookie cleanup; does NOT revoke the captured bearer for
|
|
166
|
+
* downstream mobile-gateway calls per empirical scope — see CLAUDE.md §
|
|
167
|
+
* Auth Model and the `SignOutResult` type docblock above). Authenticates
|
|
168
|
+
* with `Authorization: Token token=<X>` (same bearer that `signIn`
|
|
169
|
+
* captured — see ADR-005).
|
|
170
|
+
*
|
|
171
|
+
* Pass `null` or an empty string when there's no token to log out; the
|
|
172
|
+
* function short-circuits to `invalid/no-session` without touching the
|
|
173
|
+
* network. CLI / teardown call sites that already check for token absence
|
|
174
|
+
* before invoking this are still safe — the defensive short-circuit just
|
|
175
|
+
* removes one decision from the call site.
|
|
176
|
+
*
|
|
177
|
+
* **Never throws.** Every transport, HTTP, GraphQL-level, or wire-shape
|
|
178
|
+
* failure is classified into one of the three `SignOutResult` shapes so
|
|
179
|
+
* call sites can branch on `result.status` without try/catch. The CLI
|
|
180
|
+
* `runAuthSignOut` and `runGlobalTeardown` rely on this contract to keep
|
|
181
|
+
* the local-clear path unconditional (the bearer aging out in 24-72h is
|
|
182
|
+
* the second-line defense if server-side revocation cannot be confirmed).
|
|
183
|
+
*
|
|
184
|
+
* Schema/contract status: the operation document and `LogOutPayload` field
|
|
185
|
+
* shapes are INFERRED — `Unknown` in the SDL. The live wire format is
|
|
186
|
+
* verified by `packages/e2e/src/97-auth-signout-server-side.e2e.test.ts`
|
|
187
|
+
* (TTCTL_E2E=1 gate). If the live response surfaces fields not yet
|
|
188
|
+
* declared here, expand the inline `LogOutPayload` interface — codegen
|
|
189
|
+
* wiring would produce `unknown`-typed fields and is not currently useful.
|
|
190
|
+
*/
|
|
191
|
+
export declare function signOut(token: string | null): Promise<SignOutResult>;
|
|
192
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAKnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAsD9C,MAAM,MAAM,eAAe,GAAG,qBAAqB,GAAG,cAAc,GAAG,eAAe,GAAG,SAAS,CAAC;AAEnG,qBAAa,WAAY,SAAQ,KAAK;aAGlB,IAAI,EAAE,eAAe;IAFvC,SAAkB,IAAI,iBAAiB;gBAErB,IAAI,EAAE,eAAe,EACrC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAIhC;AA+BD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,CAKrE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAcjF;AA4CD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,MAAM,MAAM,iBAAiB,GACzB,YAAY,GACZ,iBAAiB,GACjB,sBAAsB,GACtB,mBAAmB,CAAC;AAExB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgCnF;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC5B,YAAY,GACZ,iBAAiB,GACjB,oBAAoB,CAAC;AAEzB,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,GACxB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,wBAAwB,CAAA;CAAE,CAAC;AAwBhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAiE1E"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { resolveOnePasswordReference } from "./onepassword.js";
|
|
4
|
+
import { isAuthRevokedExtensionCode } from "./services/profile/shared.js";
|
|
5
|
+
import { impersonatedTransport, stockTransport } from "./transport.js";
|
|
6
|
+
/**
|
|
7
|
+
* Persisted-query SHA-256 hash for the `EmailPasswordSignIn` mutation. Sourced
|
|
8
|
+
* from `research/graphql/derived/operations/gateway-mobile.json` (operation extracted from the mobile
|
|
9
|
+
* APK at `jadx/sources/fn/t3.java`). Hardcoded because the synthesized SDL has
|
|
10
|
+
* no client-side queries to feed Apollo APQ codegen — operations live in the
|
|
11
|
+
* research workspace, not in this repo. Re-extract and bump if the gateway
|
|
12
|
+
* starts rejecting this hash; track via the operation extraction strategy
|
|
13
|
+
* (see `research/notes` ADR-004).
|
|
14
|
+
*/
|
|
15
|
+
const EMAIL_PASSWORD_SIGNIN_HASH = "bd8e859a9f0a5c462ceb2ac736648068fa5bcdd874a8a49a460824dd0c5aef51";
|
|
16
|
+
/**
|
|
17
|
+
* Minimal full-doc Viewer query used to verify a session is live and bound to
|
|
18
|
+
* the expected user. The cataloged persisted `Viewer` query does not return
|
|
19
|
+
* `viewerRole.email`, so we cannot use APQ here. The mobile gateway accepts
|
|
20
|
+
* full-doc queries for non-mutation traffic, which is why this works without
|
|
21
|
+
* a published persisted hash.
|
|
22
|
+
*/
|
|
23
|
+
const VIEWER_VERIFY_QUERY = "query ViewerVerify { viewer { id viewerRole { email } } }";
|
|
24
|
+
/**
|
|
25
|
+
* Full-document `LogOut` mutation string. Mirrors
|
|
26
|
+
* `research/graphql/talent_profile/operations/LogOut.graphql` exactly — the
|
|
27
|
+
* talent_profile surface does not publish a persisted-query catalog, so
|
|
28
|
+
* every operation is sent as a full document (same pattern as
|
|
29
|
+
* `UPDATE_BASIC_INFO_MUTATION` in `services/profile/basic/index.ts`).
|
|
30
|
+
*
|
|
31
|
+
* Wire format: `{ operationName: "LogOut", query, variables: { input: {} } }`
|
|
32
|
+
* — `LogOutInput` is Pattern 7 (trivial empty input, per
|
|
33
|
+
* `research/notes/10-mutation-input-patterns.md`).
|
|
34
|
+
*
|
|
35
|
+
* Schema/contract status: INFERRED. `LogOutPayload` fields are typed as
|
|
36
|
+
* `Unknown` in the synthesized SDL — the actual wire shape is observed only
|
|
37
|
+
* via the live integration test in `packages/e2e/src/97-auth-signout-
|
|
38
|
+
* server-side.e2e.test.ts`. The selection set here is what the bundle-
|
|
39
|
+
* extracted document selects; if a future capture reveals additional
|
|
40
|
+
* fields the live API returns, expand the inline `LogOutPayload` interface
|
|
41
|
+
* (no codegen wiring needed — `Unknown` would map to `unknown` and provide
|
|
42
|
+
* no narrowing).
|
|
43
|
+
*/
|
|
44
|
+
const LOG_OUT_MUTATION = `mutation LogOut($input: LogOutInput!) {
|
|
45
|
+
logOut(input: $input) {
|
|
46
|
+
returnTo
|
|
47
|
+
errors {
|
|
48
|
+
key
|
|
49
|
+
message
|
|
50
|
+
}
|
|
51
|
+
notice
|
|
52
|
+
success
|
|
53
|
+
}
|
|
54
|
+
}`;
|
|
55
|
+
export class SignInError extends Error {
|
|
56
|
+
code;
|
|
57
|
+
name = "SignInError";
|
|
58
|
+
constructor(code, message, options) {
|
|
59
|
+
super(message, options);
|
|
60
|
+
this.code = code;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Collapse the polymorphic credentials value into resolved credentials.
|
|
65
|
+
*
|
|
66
|
+
* Form A (string) → `op://[account/]vault/item` → resolved via `op` CLI
|
|
67
|
+
* Form B (object) → literal `{ username, password }` (username is an email
|
|
68
|
+
* per Toptal's `EmailPasswordSignIn` mutation contract;
|
|
69
|
+
* the YAML field is named `username` to match 1Password's
|
|
70
|
+
* USERNAME purpose semantics)
|
|
71
|
+
*
|
|
72
|
+
* Returns the internal `Credentials` shape `{ email, password }` — that's
|
|
73
|
+
* the GraphQL parameter name for the mutation. The username/email
|
|
74
|
+
* synonymy is documented and load-bearing.
|
|
75
|
+
*/
|
|
76
|
+
export function resolveCredentials(auth) {
|
|
77
|
+
if (typeof auth === "string") {
|
|
78
|
+
return resolveOnePasswordReference(auth);
|
|
79
|
+
}
|
|
80
|
+
return { email: auth.username, password: auth.password };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Sign in to Toptal Talent via `EmailPasswordSignIn` GraphQL mutation in
|
|
84
|
+
* persisted-query mode against the mobile gateway and capture the session
|
|
85
|
+
* token from the response.
|
|
86
|
+
*
|
|
87
|
+
* Returns the captured token. The CLI persists it back to the same YAML
|
|
88
|
+
* config file (under `auth.token`) via `persistAuthToken` so subsequent
|
|
89
|
+
* invocations can authenticate via `Authorization: Token token=<X>`
|
|
90
|
+
* without re-signing-in.
|
|
91
|
+
*
|
|
92
|
+
* The next authenticated call (e.g. `auth status`) is the de-facto session
|
|
93
|
+
* verifier — we do NOT issue a redundant Viewer probe inside `signIn` itself.
|
|
94
|
+
*
|
|
95
|
+
* See `hq/engineering/adr/ADR-005-auth-model.md` for the cross-surface
|
|
96
|
+
* auth model and `research/notes/02-auth-and-clients.md` for the empirical
|
|
97
|
+
* evidence behind it.
|
|
98
|
+
*
|
|
99
|
+
* Throws `SignInError("UNKNOWN", ...)` if the gateway reports `success: true`
|
|
100
|
+
* but does not return a token — that response shape is malformed and the
|
|
101
|
+
* caller has nothing useful to persist.
|
|
102
|
+
*/
|
|
103
|
+
export async function signIn(credentials) {
|
|
104
|
+
const signInResponse = await postSignIn(credentials);
|
|
105
|
+
const payload = extractPayload(signInResponse.body);
|
|
106
|
+
if (!payload?.success) {
|
|
107
|
+
throw mapSignInError(payload);
|
|
108
|
+
}
|
|
109
|
+
const token = payload.token;
|
|
110
|
+
if (typeof token !== "string" || token === "") {
|
|
111
|
+
throw new SignInError("UNKNOWN", "Sign-in succeeded but no token was returned");
|
|
112
|
+
}
|
|
113
|
+
return { token };
|
|
114
|
+
}
|
|
115
|
+
async function postSignIn(credentials) {
|
|
116
|
+
try {
|
|
117
|
+
return await stockTransport({
|
|
118
|
+
surface: "mobile-gateway",
|
|
119
|
+
body: {
|
|
120
|
+
operationName: "EmailPasswordSignIn",
|
|
121
|
+
variables: { email: credentials.email, password: credentials.password },
|
|
122
|
+
extensions: {
|
|
123
|
+
persistedQuery: { version: 1, sha256Hash: EMAIL_PASSWORD_SIGNIN_HASH },
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
throw new SignInError("NETWORK_ERROR", `Sign-in request failed: ${err.message}`, { cause: err });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function extractPayload(body) {
|
|
133
|
+
if (!body || typeof body !== "object")
|
|
134
|
+
return null;
|
|
135
|
+
const response = body;
|
|
136
|
+
return response.data?.auth?.signIn ?? null;
|
|
137
|
+
}
|
|
138
|
+
function mapSignInError(payload) {
|
|
139
|
+
if (!payload) {
|
|
140
|
+
return new SignInError("UNKNOWN", "Sign-in failed: empty or malformed response body");
|
|
141
|
+
}
|
|
142
|
+
const errors = payload.errors ?? [];
|
|
143
|
+
for (const err of errors) {
|
|
144
|
+
const code = (err.code ?? "").toUpperCase();
|
|
145
|
+
if (code === "INVALID_CREDENTIALS" || code === "INVALID_EMAIL_OR_PASSWORD") {
|
|
146
|
+
return new SignInError("INVALID_CREDENTIALS", err.message ?? "Invalid email or password");
|
|
147
|
+
}
|
|
148
|
+
if (code === "MFA_REQUIRED" || code === "OTP_REQUIRED" || code === "TWO_FACTOR_REQUIRED") {
|
|
149
|
+
return new SignInError("MFA_REQUIRED", err.message ?? "Multi-factor authentication required");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const first = errors[0];
|
|
153
|
+
const message = first?.message ?? "Sign-in failed for an unknown reason";
|
|
154
|
+
return new SignInError("UNKNOWN", message);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Probe whether the persisted session token is currently valid.
|
|
158
|
+
*
|
|
159
|
+
* Issues a minimal full-doc `Viewer` query against the mobile gateway,
|
|
160
|
+
* authenticated with `Authorization: Token token=<X>`. The cataloged
|
|
161
|
+
* persisted `Viewer` query in `research/graphql/gateway/operations/mobile/Viewer.graphql`
|
|
162
|
+
* does not return `viewerRole.email`, so we can't use APQ here — see
|
|
163
|
+
* `VIEWER_VERIFY_QUERY` doc.
|
|
164
|
+
*
|
|
165
|
+
* Pass `null` (or an empty string) when no token has been persisted yet;
|
|
166
|
+
* the function short-circuits to `invalid/no-session` without touching the
|
|
167
|
+
* network. CLI consumers pass `config.auth.token ?? null` from the
|
|
168
|
+
* already-loaded `TtctlConfig` (no separate token file to read).
|
|
169
|
+
*
|
|
170
|
+
* Never throws on auth or network failure; classifies into the three
|
|
171
|
+
* `AuthStatusResult` shapes so CLI consumers can map cleanly to exit codes
|
|
172
|
+
* and output messages without re-parsing exceptions.
|
|
173
|
+
*/
|
|
174
|
+
export async function getAuthStatus(token) {
|
|
175
|
+
if (token === null || token === "") {
|
|
176
|
+
return { status: "invalid", reason: "no-session" };
|
|
177
|
+
}
|
|
178
|
+
let res;
|
|
179
|
+
try {
|
|
180
|
+
res = await stockTransport({
|
|
181
|
+
surface: "mobile-gateway",
|
|
182
|
+
authToken: token,
|
|
183
|
+
body: {
|
|
184
|
+
operationName: "ViewerVerify",
|
|
185
|
+
query: VIEWER_VERIFY_QUERY,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
return { status: "unreachable", reason: err.message };
|
|
191
|
+
}
|
|
192
|
+
if (res.status === 401 || res.status === 403) {
|
|
193
|
+
return { status: "invalid", reason: "session-expired" };
|
|
194
|
+
}
|
|
195
|
+
if (res.status < 200 || res.status >= 300) {
|
|
196
|
+
return { status: "invalid", reason: "unexpected-status" };
|
|
197
|
+
}
|
|
198
|
+
const body = res.body;
|
|
199
|
+
const email = body?.data?.viewer?.viewerRole?.email;
|
|
200
|
+
if (!email) {
|
|
201
|
+
return { status: "invalid", reason: "no-email-in-response" };
|
|
202
|
+
}
|
|
203
|
+
return { status: "valid", email };
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Issue the `LogOut` mutation server-side against the Cloudflare-protected
|
|
207
|
+
* `talent_profile/graphql` surface (defense-in-depth audit-log signal +
|
|
208
|
+
* web-session/cookie cleanup; does NOT revoke the captured bearer for
|
|
209
|
+
* downstream mobile-gateway calls per empirical scope — see CLAUDE.md §
|
|
210
|
+
* Auth Model and the `SignOutResult` type docblock above). Authenticates
|
|
211
|
+
* with `Authorization: Token token=<X>` (same bearer that `signIn`
|
|
212
|
+
* captured — see ADR-005).
|
|
213
|
+
*
|
|
214
|
+
* Pass `null` or an empty string when there's no token to log out; the
|
|
215
|
+
* function short-circuits to `invalid/no-session` without touching the
|
|
216
|
+
* network. CLI / teardown call sites that already check for token absence
|
|
217
|
+
* before invoking this are still safe — the defensive short-circuit just
|
|
218
|
+
* removes one decision from the call site.
|
|
219
|
+
*
|
|
220
|
+
* **Never throws.** Every transport, HTTP, GraphQL-level, or wire-shape
|
|
221
|
+
* failure is classified into one of the three `SignOutResult` shapes so
|
|
222
|
+
* call sites can branch on `result.status` without try/catch. The CLI
|
|
223
|
+
* `runAuthSignOut` and `runGlobalTeardown` rely on this contract to keep
|
|
224
|
+
* the local-clear path unconditional (the bearer aging out in 24-72h is
|
|
225
|
+
* the second-line defense if server-side revocation cannot be confirmed).
|
|
226
|
+
*
|
|
227
|
+
* Schema/contract status: the operation document and `LogOutPayload` field
|
|
228
|
+
* shapes are INFERRED — `Unknown` in the SDL. The live wire format is
|
|
229
|
+
* verified by `packages/e2e/src/97-auth-signout-server-side.e2e.test.ts`
|
|
230
|
+
* (TTCTL_E2E=1 gate). If the live response surfaces fields not yet
|
|
231
|
+
* declared here, expand the inline `LogOutPayload` interface — codegen
|
|
232
|
+
* wiring would produce `unknown`-typed fields and is not currently useful.
|
|
233
|
+
*/
|
|
234
|
+
export async function signOut(token) {
|
|
235
|
+
if (token === null || token === "") {
|
|
236
|
+
return { status: "invalid", reason: "no-session" };
|
|
237
|
+
}
|
|
238
|
+
let res;
|
|
239
|
+
try {
|
|
240
|
+
res = await impersonatedTransport({
|
|
241
|
+
surface: "talent-profile",
|
|
242
|
+
authToken: token,
|
|
243
|
+
body: {
|
|
244
|
+
operationName: "LogOut",
|
|
245
|
+
query: LOG_OUT_MUTATION,
|
|
246
|
+
variables: { input: {} },
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
return {
|
|
252
|
+
status: "unreachable",
|
|
253
|
+
reason: { kind: "transport", reason: err.message },
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (res.status === 401 || res.status === 403) {
|
|
257
|
+
return { status: "invalid", reason: "session-expired" };
|
|
258
|
+
}
|
|
259
|
+
if (res.status < 200 || res.status >= 300) {
|
|
260
|
+
return {
|
|
261
|
+
status: "unreachable",
|
|
262
|
+
reason: { kind: "http-status", status: res.status },
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const body = res.body;
|
|
266
|
+
// Top-level GraphQL errors[] — talent_profile surface conventionally
|
|
267
|
+
// surfaces auth-revoke states here (UNAUTHENTICATED / UNAUTHORIZED /
|
|
268
|
+
// AUTHENTICATION_REQUIRED). Treat those as "bearer already invalid"
|
|
269
|
+
// (the user's intent is satisfied); any other top-level error is
|
|
270
|
+
// unreachable (we cannot confirm revocation).
|
|
271
|
+
if (body && Array.isArray(body.errors) && body.errors.length > 0) {
|
|
272
|
+
const first = body.errors[0];
|
|
273
|
+
if (isAuthRevokedExtensionCode(first?.extensions?.code)) {
|
|
274
|
+
return { status: "invalid", reason: "graphql-auth-error" };
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
status: "unreachable",
|
|
278
|
+
reason: { kind: "graphql-error", message: first?.message ?? "GraphQL error" },
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const payload = body?.data?.logOut;
|
|
282
|
+
if (!payload) {
|
|
283
|
+
return { status: "unreachable", reason: { kind: "payload-missing" } };
|
|
284
|
+
}
|
|
285
|
+
if (payload.success === true) {
|
|
286
|
+
return { status: "logged-out" };
|
|
287
|
+
}
|
|
288
|
+
// success: false / null / undefined — server received the mutation but
|
|
289
|
+
// did not acknowledge the LogOut flow as processed. We don't know whether
|
|
290
|
+
// the LogOut signal was actually delivered to the audit log / session
|
|
291
|
+
// store; classify as unreachable so callers fall through to local clear.
|
|
292
|
+
return { status: "unreachable", reason: { kind: "success-false" } };
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|