@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
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import type { ProfileShowQuery } from "../../../__generated__/gateway.js";
|
|
2
|
+
import type { DryRunPreview } from "../../../transport.js";
|
|
3
|
+
/**
|
|
4
|
+
* Profile-domain error codes. The `'UNAUTHENTICATED'` member was retired
|
|
5
|
+
* under issue #77 — auth-revoked failures now throw `AuthRevokedError`
|
|
6
|
+
* (cross-cutting `TtctlError` subclass) so the CLI / MCP surfaces can apply
|
|
7
|
+
* a uniform "Run `ttctl auth signin`" recovery hint regardless of which
|
|
8
|
+
* service raised the failure.
|
|
9
|
+
*/
|
|
10
|
+
export type ProfileErrorCode = "NO_VIEWER" | "GRAPHQL_ERROR" | "NETWORK_ERROR" | "USER_ERROR" | "VALIDATION_ERROR" | "WIRE_SHAPE_ERROR" | "UNKNOWN";
|
|
11
|
+
export declare class ProfileError extends Error {
|
|
12
|
+
readonly code: ProfileErrorCode;
|
|
13
|
+
readonly name = "ProfileError";
|
|
14
|
+
constructor(code: ProfileErrorCode, message: string, options?: {
|
|
15
|
+
cause?: unknown;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Fetch the signed-in user's profile from the mobile-gateway GraphQL
|
|
20
|
+
* surface (`https://www.toptal.com/gateway/graphql/talent/graphql`).
|
|
21
|
+
*
|
|
22
|
+
* Authenticates via `Authorization: Token token=<token>` (the canonical
|
|
23
|
+
* Toptal auth mechanism — see `hq/engineering/adr/ADR-005-auth-model.md`).
|
|
24
|
+
* The mobile-gateway is plain HTTPS — no Cloudflare, no TLS impersonation
|
|
25
|
+
* required (empirically validated in `research/notes/13-getviewer-empirical-shape.md`).
|
|
26
|
+
*
|
|
27
|
+
* The returned shape is profile-comprehensive: identity (email, fullName,
|
|
28
|
+
* phoneNumber, photo), role (allocatedHours, hiredHours, availability,
|
|
29
|
+
* specializations, vertical, hourlyRate, timeZone, permissions, contact
|
|
30
|
+
* fields), profile sub-object (id, fullName, city, photo, skillSets), and
|
|
31
|
+
* operational metadata (codeOfConduct/termsOfService acceptance state,
|
|
32
|
+
* hireMeBanner, lastAllocatedHoursChangeRequest, rateInsight). Caller may
|
|
33
|
+
* project as needed for display.
|
|
34
|
+
*
|
|
35
|
+
* Note: `Profile.about` (bio) and `Profile.quote` (headline) are NOT on
|
|
36
|
+
* mobile-gateway's `Profile` type. They are write-side fields surfaced by
|
|
37
|
+
* `set()`'s response payload via the talent-profile surface. If a
|
|
38
|
+
* read-side bio/headline display becomes needed, that requires a follow-up
|
|
39
|
+
* issue to add a second talent-profile call.
|
|
40
|
+
*
|
|
41
|
+
* Errors:
|
|
42
|
+
* - `AuthRevokedError` when the surface returns 401, OR the GraphQL
|
|
43
|
+
* response carries `extensions.code` matching `isAuthRevokedExtensionCode`
|
|
44
|
+
* (`'UNAUTHENTICATED'`, `'AUTHENTICATION_REQUIRED'`, or `'UNAUTHORIZED'`
|
|
45
|
+
* — see `services/profile/shared.ts` for per-code surface attribution and
|
|
46
|
+
* empirical history; #89 added `'UNAUTHORIZED'` for mobile-gateway).
|
|
47
|
+
* Caller-agnostic — the CLI / MCP surfaces render `error.recovery`
|
|
48
|
+
* verbatim ("Run `ttctl auth signin` to re-authenticate.").
|
|
49
|
+
* - `ProfileError` with code `NO_VIEWER` when the response is 200 but
|
|
50
|
+
* `data.viewer` is `null` (the API contract says this means the token
|
|
51
|
+
* does not bind to a viewer).
|
|
52
|
+
* - `ProfileError` with code `GRAPHQL_ERROR` when the response carries a
|
|
53
|
+
* non-empty `errors` array (other than auth-revoked).
|
|
54
|
+
* - `ProfileError` with code `NETWORK_ERROR` when the transport itself
|
|
55
|
+
* throws (DNS, connection reset, etc).
|
|
56
|
+
*/
|
|
57
|
+
export declare function show(token: string): Promise<ProfileShowQuery>;
|
|
58
|
+
/**
|
|
59
|
+
* One language entry on `Profile.languages.nodes` — identifier + display
|
|
60
|
+
* name. The talent_profile schema types `languages` as `Unknown` (the
|
|
61
|
+
* synthesized SDL marks anything the generator couldn't resolve), so the
|
|
62
|
+
* runtime contract is the source of truth: nodes are objects with
|
|
63
|
+
* non-empty string `id` and `name`. Empty / null entries are filtered
|
|
64
|
+
* out by {@link getBasicInfo} before the caller sees them.
|
|
65
|
+
*/
|
|
66
|
+
export interface ProfileLanguage {
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Read-side projection of the `talent_profile`-only profile fields that
|
|
72
|
+
* complement {@link show}. Returned by {@link getBasicInfo}.
|
|
73
|
+
*
|
|
74
|
+
* Naming: `bio` and `headline` are the user-facing CLI flag names exposed
|
|
75
|
+
* by `set()`'s {@link ProfileUpdate}, mapped to the GraphQL
|
|
76
|
+
* `Profile.about` / `Profile.quote` fields. We surface them as `bio` /
|
|
77
|
+
* `headline` here so the read and write surfaces use the same vocabulary
|
|
78
|
+
* — callers don't need to know the wire-side names to render the value
|
|
79
|
+
* the user typed.
|
|
80
|
+
*
|
|
81
|
+
* `null` indicates the user hasn't set the field (or the server didn't
|
|
82
|
+
* return it). `languages` is an array — empty when none are set, never
|
|
83
|
+
* `null` (the empty-collection convention agreed in the #124 audit's
|
|
84
|
+
* null-rendering recommendation).
|
|
85
|
+
*/
|
|
86
|
+
export interface BasicInfo {
|
|
87
|
+
/** Echoes the talent_profile-side `Profile.id` (matches `show()`'s `viewerRole.profileId`). */
|
|
88
|
+
profileId: string;
|
|
89
|
+
/** The long-form bio (`Profile.about`). `null` when unset. */
|
|
90
|
+
bio: string | null;
|
|
91
|
+
/** The short tagline (`Profile.quote`). `null` when unset. */
|
|
92
|
+
headline: string | null;
|
|
93
|
+
/** User-declared languages. Empty array when none. */
|
|
94
|
+
languages: ProfileLanguage[];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Fetch the read-side `talent_profile`-only basic-info fields that
|
|
98
|
+
* complement {@link show} — `bio` (→ `Profile.about`), `headline` (→
|
|
99
|
+
* `Profile.quote`), and `languages`.
|
|
100
|
+
*
|
|
101
|
+
* Routed against `https://www.toptal.com/api/talent_profile/graphql` via
|
|
102
|
+
* {@link impersonatedTransport} (Cloudflare-protected; Chrome TLS
|
|
103
|
+
* fingerprint required). Internally calls {@link show} first to obtain
|
|
104
|
+
* the `profileId` required by the `profile(id: ID!)` field — same
|
|
105
|
+
* pattern as {@link photoShow}.
|
|
106
|
+
*
|
|
107
|
+
* Returns a typed {@link BasicInfo} projection — `null` for fields the
|
|
108
|
+
* user hasn't set, an empty array for `languages` when none.
|
|
109
|
+
*
|
|
110
|
+
* Errors:
|
|
111
|
+
* - `Cf403Error` propagates from the talent-profile transport.
|
|
112
|
+
* - `AuthRevokedError` on token expiry (HTTP 401, or any GraphQL
|
|
113
|
+
* `extensions.code` matching `isAuthRevokedExtensionCode`).
|
|
114
|
+
* - `ProfileError` with code `NO_VIEWER` when no viewer is bound.
|
|
115
|
+
* - `ProfileError` with code `USER_ERROR` when the profile id doesn't
|
|
116
|
+
* resolve (server returns `data.profile === null`).
|
|
117
|
+
* - `ProfileError` with code `GRAPHQL_ERROR` on top-level GraphQL errors
|
|
118
|
+
* (other than auth-revoked).
|
|
119
|
+
* - `ProfileError` with code `NETWORK_ERROR` on transport-level throws.
|
|
120
|
+
* - `ProfileError` with code `UNKNOWN` on unexpected non-2xx statuses or
|
|
121
|
+
* missing `data` field.
|
|
122
|
+
*/
|
|
123
|
+
export declare function getBasicInfo(token: string): Promise<BasicInfo>;
|
|
124
|
+
/**
|
|
125
|
+
* Subset of profile fields editable via the wave-0 MVP write-path. `bio` and
|
|
126
|
+
* `headline` are the user-facing flag names exposed by the CLI; they map to
|
|
127
|
+
* the GraphQL fields `about` and `quote` respectively (the field names used
|
|
128
|
+
* by the talent_profile surface — see the response selection in
|
|
129
|
+
* `research/graphql/talent_profile/operations/UPDATE_BASIC_INFO.graphql`).
|
|
130
|
+
*
|
|
131
|
+
* Both fields are optional. The caller is responsible for ensuring at least
|
|
132
|
+
* one is supplied — `set()` rejects an empty object with a
|
|
133
|
+
* `VALIDATION_ERROR`.
|
|
134
|
+
*/
|
|
135
|
+
export interface ProfileUpdate {
|
|
136
|
+
bio?: string;
|
|
137
|
+
headline?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Result of a successful `set()` call. Mirrors the GraphQL field
|
|
141
|
+
* names so callers see `about`/`quote` rather than the CLI flag names — the
|
|
142
|
+
* mapping back to user-facing `bio`/`headline` is a presentation concern
|
|
143
|
+
* handled at the CLI layer.
|
|
144
|
+
*/
|
|
145
|
+
export interface UpdateProfileResult {
|
|
146
|
+
profile: {
|
|
147
|
+
id: string;
|
|
148
|
+
about: string | null;
|
|
149
|
+
quote: string | null;
|
|
150
|
+
};
|
|
151
|
+
notice: string | null;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Options accepted by {@link set}. Today carries only `dryRun` (#52);
|
|
155
|
+
* a `confirm`-style anti-fat-finger gate is planned for `timesheet
|
|
156
|
+
* submit` (#13) and will follow the same option-object shape so callers
|
|
157
|
+
* can opt in additively without API churn.
|
|
158
|
+
*/
|
|
159
|
+
export interface SetOptions {
|
|
160
|
+
/**
|
|
161
|
+
* When `true`, {@link set} short-circuits before any transport call,
|
|
162
|
+
* returning a {@link DryRunPreview}-bearing outcome ({@link
|
|
163
|
+
* SetOutcomePreview}) instead of executing the mutation. Default:
|
|
164
|
+
* `false` — normal apply-the-mutation path.
|
|
165
|
+
*
|
|
166
|
+
* The preview is built with placeholder substitutions for fields that
|
|
167
|
+
* would normally be resolved via sibling reads (e.g. `profileId`,
|
|
168
|
+
* which {@link set} fetches from `show()` in the apply path). Neither
|
|
169
|
+
* the read transport nor the write transport is invoked when `dryRun`
|
|
170
|
+
* is true — the AC for issue #52 is "transport never called" and the
|
|
171
|
+
* helper honors it for both directions of network I/O.
|
|
172
|
+
*/
|
|
173
|
+
dryRun?: boolean;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Placeholder string substituted for fields that the apply-path would
|
|
177
|
+
* normally resolve via a sibling read (e.g. `profileId` from `show()`).
|
|
178
|
+
* Surfaced verbatim in the dry-run preview's variables payload so
|
|
179
|
+
* downstream consumers can see the request structure without TTCtl
|
|
180
|
+
* having fired any network I/O.
|
|
181
|
+
*
|
|
182
|
+
* Public (re-exported via `index.ts`) so MCP / future CLI tooling can
|
|
183
|
+
* recognize the placeholder when surfacing the preview.
|
|
184
|
+
*/
|
|
185
|
+
export declare const DRY_RUN_PROFILE_ID_PLACEHOLDER: "<resolved at send-time from session token>";
|
|
186
|
+
/**
|
|
187
|
+
* Discriminated outcome of a {@link set} call when the apply-path
|
|
188
|
+
* succeeded — the server-confirmed payload normalised to {@link
|
|
189
|
+
* UpdateProfileResult}. Identical to the pre-#52 return type wrapped in
|
|
190
|
+
* a `{ kind: "applied" }` discriminator.
|
|
191
|
+
*/
|
|
192
|
+
export interface SetOutcomeApplied {
|
|
193
|
+
kind: "applied";
|
|
194
|
+
result: UpdateProfileResult;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Discriminated outcome of a {@link set} call invoked with
|
|
198
|
+
* `dryRun: true` — the structured preview of the request that WOULD have
|
|
199
|
+
* been sent. No transport (read or write) was invoked along this path.
|
|
200
|
+
*/
|
|
201
|
+
export interface SetOutcomePreview {
|
|
202
|
+
kind: "preview";
|
|
203
|
+
preview: DryRunPreview;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Discriminated-union return type for {@link set}. Apply-path callers
|
|
207
|
+
* branch on `outcome.kind === "applied"`; dry-run callers branch on
|
|
208
|
+
* `"preview"`. The pre-#52 surface returned `UpdateProfileResult`
|
|
209
|
+
* directly — that surface no longer exists. Pre-1.0 (`0.0.0`) the
|
|
210
|
+
* breaking change is acceptable per CLAUDE.md's "single-step migration"
|
|
211
|
+
* stance for the programmatic API.
|
|
212
|
+
*/
|
|
213
|
+
export type SetOutcome = SetOutcomeApplied | SetOutcomePreview;
|
|
214
|
+
/**
|
|
215
|
+
* Update a subset of the signed-in user's basic-info fields (currently
|
|
216
|
+
* `bio` → `about` and `headline` → `quote`) via the Cloudflare-protected
|
|
217
|
+
* `talent_profile/graphql` surface.
|
|
218
|
+
*
|
|
219
|
+
* Authenticates via `Authorization: Token token=<token>` (the canonical
|
|
220
|
+
* Toptal auth mechanism). Cookies are NOT load-bearing — Chrome TLS
|
|
221
|
+
* impersonation alone passes Cloudflare. Internally calls `show()`
|
|
222
|
+
* (against mobile-gateway) first to obtain the `profileId` required by the
|
|
223
|
+
* mutation input, then issues the typed `UpdateBasicInfo` mutation against
|
|
224
|
+
* talent-profile via `impersonatedTransport`. Returns the server-confirmed
|
|
225
|
+
* updated values wrapped in a {@link SetOutcomeApplied} discriminator.
|
|
226
|
+
*
|
|
227
|
+
* Dry-run path (issue #52): when invoked with `options.dryRun === true`,
|
|
228
|
+
* builds a {@link DryRunPreview} of the WRITE request without invoking
|
|
229
|
+
* any transport (read OR write) and returns it wrapped in {@link
|
|
230
|
+
* SetOutcomePreview}. The preview substitutes a placeholder string
|
|
231
|
+
* ({@link DRY_RUN_PROFILE_ID_PLACEHOLDER}) for `profileId` because the
|
|
232
|
+
* apply-path resolves it via `show()` (a stock-transport read call) and
|
|
233
|
+
* the dry-run AC requires zero transport invocations. The bearer token
|
|
234
|
+
* is redacted in the preview's `headers.authorization` per the security
|
|
235
|
+
* contract documented on {@link DryRunPreview}.
|
|
236
|
+
*
|
|
237
|
+
* Errors:
|
|
238
|
+
* - `ProfileError` with code `VALIDATION_ERROR` when neither `bio` nor
|
|
239
|
+
* `headline` is supplied — the contract requires at least one. Fires
|
|
240
|
+
* in BOTH the apply-path and the dry-run path.
|
|
241
|
+
* - `Cf403Error` propagates from the talent-profile transport when
|
|
242
|
+
* Cloudflare returns 403. Apply-path only.
|
|
243
|
+
* - `AuthRevokedError` on token expiry (HTTP 401, or any GraphQL
|
|
244
|
+
* `extensions.code` matching `isAuthRevokedExtensionCode` — currently
|
|
245
|
+
* `'UNAUTHENTICATED'`, `'AUTHENTICATION_REQUIRED'`, or `'UNAUTHORIZED'`).
|
|
246
|
+
* Apply-path only.
|
|
247
|
+
* - `ProfileError` with code `NO_VIEWER` when no viewer is bound.
|
|
248
|
+
* Apply-path only — dry-run skips the read entirely.
|
|
249
|
+
* - `ProfileError` with code `USER_ERROR` when the mutation returns a
|
|
250
|
+
* non-empty `errors` array (validation failures from the server, e.g., a
|
|
251
|
+
* bio that exceeds the platform's length limit). Apply-path only.
|
|
252
|
+
* - `ProfileError` with code `GRAPHQL_ERROR` on top-level GraphQL errors.
|
|
253
|
+
* Apply-path only.
|
|
254
|
+
* - `ProfileError` with code `NETWORK_ERROR` on transport-level throws.
|
|
255
|
+
* Apply-path only.
|
|
256
|
+
*/
|
|
257
|
+
export declare function set(token: string, changes: ProfileUpdate, options?: SetOptions): Promise<SetOutcome>;
|
|
258
|
+
/**
|
|
259
|
+
* `UpdatePhotoInput` shape, derived from the bundle-extracted
|
|
260
|
+
* `UploadProfilePhoto` mutation (`research/graphql/talent_profile/
|
|
261
|
+
* operations/UploadProfilePhoto.graphql`) and Pattern-1-aligned per
|
|
262
|
+
* `research/notes/10-mutation-input-patterns.md` (`{profileId, transformation,
|
|
263
|
+
* file}`).
|
|
264
|
+
*
|
|
265
|
+
* `file` is `null` in the JSON `operations` payload — the actual file
|
|
266
|
+
* binary travels in a separate `0` form field per the multipart-upload
|
|
267
|
+
* spec; the JSON placeholder is mapped onto it via the `map` form field.
|
|
268
|
+
*
|
|
269
|
+
* `transformation` carries the crop rectangle the server uses to render
|
|
270
|
+
* the small/cropped variants; we default to "no crop" (a 0,0 to width,height
|
|
271
|
+
* rectangle) when the caller doesn't supply one — server falls back to
|
|
272
|
+
* its own auto-crop heuristic in that case.
|
|
273
|
+
*/
|
|
274
|
+
interface PhotoTransformationInput {
|
|
275
|
+
cropped: {
|
|
276
|
+
x: number;
|
|
277
|
+
y: number;
|
|
278
|
+
width: number;
|
|
279
|
+
height: number;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Photo URLs as exposed to consumers — mirrors the `Photo` selection set
|
|
284
|
+
* we ask for on the talent_profile surface. `transformations.cropped` is
|
|
285
|
+
* the server-recommended crop rectangle for the `small` variant; consumers
|
|
286
|
+
* typically use `default` for in-CLI display and `original` for export.
|
|
287
|
+
*/
|
|
288
|
+
export interface PhotoUrl {
|
|
289
|
+
default: string | null;
|
|
290
|
+
original: string | null;
|
|
291
|
+
small: string | null;
|
|
292
|
+
cropped: {
|
|
293
|
+
x: number;
|
|
294
|
+
y: number;
|
|
295
|
+
width: number;
|
|
296
|
+
height: number;
|
|
297
|
+
} | null;
|
|
298
|
+
isResolutionSatisfied: boolean;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Fetch the URLs of the signed-in user's profile photo (default / original
|
|
302
|
+
* / small variants plus the server's recommended crop rectangle and the
|
|
303
|
+
* "is the resolution satisfactory?" boolean from `profileReadiness`).
|
|
304
|
+
*
|
|
305
|
+
* Routed against `talent_profile/graphql` via `impersonatedTransport`
|
|
306
|
+
* (Cloudflare-protected) because the mobile gateway exposes only a single
|
|
307
|
+
* flat URL on `Profile.photo` — not the variant shape we surface.
|
|
308
|
+
*
|
|
309
|
+
* Internally calls `show()` first to get the `profileId` (same pattern
|
|
310
|
+
* as `set()` — the talent-profile surface keys `profile(id: ID!)` rather
|
|
311
|
+
* than resolving from the auth token), then fires the typed query.
|
|
312
|
+
*
|
|
313
|
+
* Errors:
|
|
314
|
+
* - `Cf403Error` propagates from the talent-profile transport.
|
|
315
|
+
* - `AuthRevokedError` on token expiry (HTTP 401, or any auth-revoked
|
|
316
|
+
* `extensions.code` — see `isAuthRevokedExtensionCode` in
|
|
317
|
+
* `services/profile/shared.ts`).
|
|
318
|
+
* - `ProfileError` `NO_VIEWER` when no viewer is bound.
|
|
319
|
+
* - `ProfileError` `GRAPHQL_ERROR` on top-level GraphQL errors.
|
|
320
|
+
* - `ProfileError` `NETWORK_ERROR` on transport-level throws.
|
|
321
|
+
* - `ProfileError` `USER_ERROR` when the profile id doesn't resolve
|
|
322
|
+
* (server returns `data.profile === null`).
|
|
323
|
+
*/
|
|
324
|
+
export declare function photoShow(token: string): Promise<PhotoUrl>;
|
|
325
|
+
/**
|
|
326
|
+
* Photo upload input. The caller supplies either a path to an image file
|
|
327
|
+
* (string) or an in-memory buffer. When a path is given, the helper reads
|
|
328
|
+
* the file via `node:fs/promises` and infers content-type from the
|
|
329
|
+
* extension. When a buffer is given, the caller may supply
|
|
330
|
+
* `contentType` and `filename` to control the multipart parts (defaults
|
|
331
|
+
* to `image/jpeg` and `photo.jpg`).
|
|
332
|
+
*
|
|
333
|
+
* `transformation` is optional: when omitted, the helper sends a default
|
|
334
|
+
* (no-crop) rectangle and lets the server's auto-crop heuristic pick.
|
|
335
|
+
*/
|
|
336
|
+
export interface PhotoUploadInput {
|
|
337
|
+
file: Buffer | string;
|
|
338
|
+
filename?: string;
|
|
339
|
+
contentType?: string;
|
|
340
|
+
transformation?: PhotoTransformationInput;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Upload a new profile photo. Implements the GraphQL multipart-upload
|
|
344
|
+
* spec — the request body is a `multipart/form-data` envelope with three
|
|
345
|
+
* named parts (`operations`, `map`, and the file payload at field `0`),
|
|
346
|
+
* NOT the JSON envelope every other operation in this module uses. The
|
|
347
|
+
* transport hand-rolls a `node-wreq` fetch call rather than going through
|
|
348
|
+
* `impersonatedTransport()` because that helper hardcodes
|
|
349
|
+
* `Content-Type: application/json`; both transports use the same Chrome
|
|
350
|
+
* TLS profile so Cloudflare treats them uniformly.
|
|
351
|
+
*
|
|
352
|
+
* `input.file` accepts either a path string or a Buffer. Path strings
|
|
353
|
+
* are read with `node:fs/promises` and the content-type is inferred from
|
|
354
|
+
* the extension; Buffer callers may override `contentType` / `filename`.
|
|
355
|
+
*
|
|
356
|
+
* Errors:
|
|
357
|
+
* - `Cf403Error` propagates from the multipart transport call.
|
|
358
|
+
* - `AuthRevokedError` on token expiry (HTTP 401, or auth-revoked
|
|
359
|
+
* `extensions.code` on the GraphQL response).
|
|
360
|
+
* - `ProfileError` `VALIDATION_ERROR` when `input.file` is empty / missing.
|
|
361
|
+
* - `ProfileError` `NO_VIEWER` when no viewer is bound.
|
|
362
|
+
* - `ProfileError` `USER_ERROR` when the mutation returns user errors
|
|
363
|
+
* (e.g., resolution too low, file format unsupported).
|
|
364
|
+
* - Standard transport-error path.
|
|
365
|
+
*/
|
|
366
|
+
export declare function photoUpload(token: string, input: PhotoUploadInput): Promise<PhotoUrl>;
|
|
367
|
+
type MultipartFetchImpl = (url: string, init: {
|
|
368
|
+
method: string;
|
|
369
|
+
headers: Record<string, string>;
|
|
370
|
+
body: FormData;
|
|
371
|
+
browser: string;
|
|
372
|
+
}) => Promise<{
|
|
373
|
+
status: number;
|
|
374
|
+
text: () => Promise<string>;
|
|
375
|
+
headers: {
|
|
376
|
+
toObject: () => Record<string, string>;
|
|
377
|
+
};
|
|
378
|
+
}>;
|
|
379
|
+
/**
|
|
380
|
+
* Test-only: replace the multipart-fetch implementation used by
|
|
381
|
+
* {@link photoUpload}. Pass `null` to restore the default. The override
|
|
382
|
+
* receives the same arguments as `node-wreq`'s `fetch` and must return a
|
|
383
|
+
* shape compatible with its `Response` (we only rely on `.status`,
|
|
384
|
+
* `.text()`, and `.headers.toObject()`).
|
|
385
|
+
*
|
|
386
|
+
* @internal
|
|
387
|
+
*/
|
|
388
|
+
export declare function _setMultipartFetchForTesting(impl: MultipartFetchImpl | null): void;
|
|
389
|
+
export {};
|
|
390
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/services/profile/basic/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAY1E,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,uBAAuB,CAAC;AAmN9E;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,eAAe,GACf,eAAe,GACf,YAAY,GACZ,kBAAkB,GAClB,kBAAkB,GAClB,SAAS,CAAC;AAEd,qBAAa,YAAa,SAAQ,KAAK;aAGnB,IAAI,EAAE,gBAAgB;IAFxC,SAAkB,IAAI,kBAAkB;gBAEtB,IAAI,EAAE,gBAAgB,EACtC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAIhC;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8CnE;AAoCD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,SAAS;IACxB,+FAA+F;IAC/F,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sDAAsD;IACtD,SAAS,EAAE,eAAe,EAAE,CAAC;CAC9B;AA8CD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CA4DpE;AAsCD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAkDD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC;IACF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B,EAAG,4CAAqD,CAAC;AAEpG;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAsB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAsH9G;AAmCD;;;;;;;;;;;;;;;GAeG;AACH,UAAU,wBAAwB;IAChC,OAAO,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAClE;AAqBD;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACxE,qBAAqB,EAAE,OAAO,CAAC;CAChC;AA+CD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyChE;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,wBAAwB,CAAC;CAC3C;AAiBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6F3F;AA0LD,KAAK,kBAAkB,GAAG,CACxB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KACvF,OAAO,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CACrD,CAAC,CAAC;AAIH;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAElF"}
|