@ttctl/core 0.0.0 → 0.1.0-rc.2

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.
Files changed (195) hide show
  1. package/README.md +49 -9
  2. package/dist/__generated__/gateway.d.ts +4546 -0
  3. package/dist/__generated__/gateway.d.ts.map +1 -0
  4. package/dist/__generated__/gateway.js +9 -0
  5. package/dist/__generated__/gateway.js.map +1 -0
  6. package/dist/__generated__/talent-profile-zod-schemas.d.ts +1187 -0
  7. package/dist/__generated__/talent-profile-zod-schemas.d.ts.map +1 -0
  8. package/dist/__generated__/talent-profile-zod-schemas.js +1136 -0
  9. package/dist/__generated__/talent-profile-zod-schemas.js.map +1 -0
  10. package/dist/__generated__/talent-profile.d.ts +1397 -0
  11. package/dist/__generated__/talent-profile.d.ts.map +1 -0
  12. package/dist/__generated__/talent-profile.js +9 -0
  13. package/dist/__generated__/talent-profile.js.map +1 -0
  14. package/dist/__generated__/zod-schemas.d.ts +2895 -0
  15. package/dist/__generated__/zod-schemas.d.ts.map +1 -0
  16. package/dist/__generated__/zod-schemas.js +3121 -0
  17. package/dist/__generated__/zod-schemas.js.map +1 -0
  18. package/dist/__tests__/fixtures/profile/builders.d.ts +74 -0
  19. package/dist/__tests__/fixtures/profile/builders.d.ts.map +1 -0
  20. package/dist/__tests__/fixtures/profile/builders.js +200 -0
  21. package/dist/__tests__/fixtures/profile/builders.js.map +1 -0
  22. package/dist/__tests__/fixtures/profile/data.d.ts +39 -0
  23. package/dist/__tests__/fixtures/profile/data.d.ts.map +1 -0
  24. package/dist/__tests__/fixtures/profile/data.js +238 -0
  25. package/dist/__tests__/fixtures/profile/data.js.map +1 -0
  26. package/dist/__tests__/fixtures/profile/index.d.ts +9 -0
  27. package/dist/__tests__/fixtures/profile/index.d.ts.map +1 -0
  28. package/dist/__tests__/fixtures/profile/index.js +10 -0
  29. package/dist/__tests__/fixtures/profile/index.js.map +1 -0
  30. package/dist/__tests__/fixtures/profile/types.d.ts +53 -0
  31. package/dist/__tests__/fixtures/profile/types.d.ts.map +1 -0
  32. package/dist/__tests__/fixtures/profile/types.js +4 -0
  33. package/dist/__tests__/fixtures/profile/types.js.map +1 -0
  34. package/dist/auth/errors.d.ts +82 -0
  35. package/dist/auth/errors.d.ts.map +1 -0
  36. package/dist/auth/errors.js +68 -0
  37. package/dist/auth/errors.js.map +1 -0
  38. package/dist/auth.d.ts +192 -0
  39. package/dist/auth.d.ts.map +1 -0
  40. package/dist/auth.js +294 -0
  41. package/dist/auth.js.map +1 -0
  42. package/dist/config.d.ts +214 -0
  43. package/dist/config.d.ts.map +1 -0
  44. package/dist/config.js +349 -0
  45. package/dist/config.js.map +1 -0
  46. package/dist/configLock.d.ts +52 -0
  47. package/dist/configLock.d.ts.map +1 -0
  48. package/dist/configLock.js +109 -0
  49. package/dist/configLock.js.map +1 -0
  50. package/dist/configWriter.d.ts +97 -0
  51. package/dist/configWriter.d.ts.map +1 -0
  52. package/dist/configWriter.js +688 -0
  53. package/dist/configWriter.js.map +1 -0
  54. package/dist/index.d.ts +37 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +28 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/kill-switch.d.ts +161 -0
  59. package/dist/kill-switch.d.ts.map +1 -0
  60. package/dist/kill-switch.js +235 -0
  61. package/dist/kill-switch.js.map +1 -0
  62. package/dist/lib/date.d.ts +58 -0
  63. package/dist/lib/date.d.ts.map +1 -0
  64. package/dist/lib/date.js +104 -0
  65. package/dist/lib/date.js.map +1 -0
  66. package/dist/lib/diagnostic-log.d.ts +159 -0
  67. package/dist/lib/diagnostic-log.d.ts.map +1 -0
  68. package/dist/lib/diagnostic-log.js +186 -0
  69. package/dist/lib/diagnostic-log.js.map +1 -0
  70. package/dist/lib/package-version.d.ts +19 -0
  71. package/dist/lib/package-version.d.ts.map +1 -0
  72. package/dist/lib/package-version.js +38 -0
  73. package/dist/lib/package-version.js.map +1 -0
  74. package/dist/lib/redact.d.ts +153 -0
  75. package/dist/lib/redact.d.ts.map +1 -0
  76. package/dist/lib/redact.js +207 -0
  77. package/dist/lib/redact.js.map +1 -0
  78. package/dist/lib/text.d.ts +14 -0
  79. package/dist/lib/text.d.ts.map +1 -0
  80. package/dist/lib/text.js +21 -0
  81. package/dist/lib/text.js.map +1 -0
  82. package/dist/lib/wire-shape.d.ts +131 -0
  83. package/dist/lib/wire-shape.d.ts.map +1 -0
  84. package/dist/lib/wire-shape.js +376 -0
  85. package/dist/lib/wire-shape.js.map +1 -0
  86. package/dist/onepassword.d.ts +29 -0
  87. package/dist/onepassword.d.ts.map +1 -0
  88. package/dist/onepassword.js +112 -0
  89. package/dist/onepassword.js.map +1 -0
  90. package/dist/services/_shared/transport.d.ts +148 -0
  91. package/dist/services/_shared/transport.d.ts.map +1 -0
  92. package/dist/services/_shared/transport.js +102 -0
  93. package/dist/services/_shared/transport.js.map +1 -0
  94. package/dist/services/applications/index.d.ts +210 -0
  95. package/dist/services/applications/index.d.ts.map +1 -0
  96. package/dist/services/applications/index.js +240 -0
  97. package/dist/services/applications/index.js.map +1 -0
  98. package/dist/services/availability/index.d.ts +254 -0
  99. package/dist/services/availability/index.d.ts.map +1 -0
  100. package/dist/services/availability/index.js +310 -0
  101. package/dist/services/availability/index.js.map +1 -0
  102. package/dist/services/contracts/index.d.ts +132 -0
  103. package/dist/services/contracts/index.d.ts.map +1 -0
  104. package/dist/services/contracts/index.js +211 -0
  105. package/dist/services/contracts/index.js.map +1 -0
  106. package/dist/services/engagements/index.d.ts +504 -0
  107. package/dist/services/engagements/index.d.ts.map +1 -0
  108. package/dist/services/engagements/index.js +613 -0
  109. package/dist/services/engagements/index.js.map +1 -0
  110. package/dist/services/jobs/index.d.ts +490 -0
  111. package/dist/services/jobs/index.d.ts.map +1 -0
  112. package/dist/services/jobs/index.js +753 -0
  113. package/dist/services/jobs/index.js.map +1 -0
  114. package/dist/services/payments/index.d.ts +425 -0
  115. package/dist/services/payments/index.d.ts.map +1 -0
  116. package/dist/services/payments/index.js +636 -0
  117. package/dist/services/payments/index.js.map +1 -0
  118. package/dist/services/profile/__tests__/fixtures.d.ts +214 -0
  119. package/dist/services/profile/__tests__/fixtures.d.ts.map +1 -0
  120. package/dist/services/profile/__tests__/fixtures.js +176 -0
  121. package/dist/services/profile/__tests__/fixtures.js.map +1 -0
  122. package/dist/services/profile/basic/index.d.ts +390 -0
  123. package/dist/services/profile/basic/index.d.ts.map +1 -0
  124. package/dist/services/profile/basic/index.js +1007 -0
  125. package/dist/services/profile/basic/index.js.map +1 -0
  126. package/dist/services/profile/certifications/index.d.ts +74 -0
  127. package/dist/services/profile/certifications/index.d.ts.map +1 -0
  128. package/dist/services/profile/certifications/index.js +169 -0
  129. package/dist/services/profile/certifications/index.js.map +1 -0
  130. package/dist/services/profile/education/index.d.ts +73 -0
  131. package/dist/services/profile/education/index.d.ts.map +1 -0
  132. package/dist/services/profile/education/index.js +168 -0
  133. package/dist/services/profile/education/index.js.map +1 -0
  134. package/dist/services/profile/employment/index.d.ts +132 -0
  135. package/dist/services/profile/employment/index.d.ts.map +1 -0
  136. package/dist/services/profile/employment/index.js +262 -0
  137. package/dist/services/profile/employment/index.js.map +1 -0
  138. package/dist/services/profile/external/index.d.ts +278 -0
  139. package/dist/services/profile/external/index.d.ts.map +1 -0
  140. package/dist/services/profile/external/index.js +640 -0
  141. package/dist/services/profile/external/index.js.map +1 -0
  142. package/dist/services/profile/index.d.ts +24 -0
  143. package/dist/services/profile/index.d.ts.map +1 -0
  144. package/dist/services/profile/index.js +26 -0
  145. package/dist/services/profile/index.js.map +1 -0
  146. package/dist/services/profile/industries/index.d.ts +130 -0
  147. package/dist/services/profile/industries/index.d.ts.map +1 -0
  148. package/dist/services/profile/industries/index.js +292 -0
  149. package/dist/services/profile/industries/index.js.map +1 -0
  150. package/dist/services/profile/portfolio/index.d.ts +352 -0
  151. package/dist/services/profile/portfolio/index.d.ts.map +1 -0
  152. package/dist/services/profile/portfolio/index.js +833 -0
  153. package/dist/services/profile/portfolio/index.js.map +1 -0
  154. package/dist/services/profile/resume/index.d.ts +60 -0
  155. package/dist/services/profile/resume/index.d.ts.map +1 -0
  156. package/dist/services/profile/resume/index.js +212 -0
  157. package/dist/services/profile/resume/index.js.map +1 -0
  158. package/dist/services/profile/reviews/index.d.ts +137 -0
  159. package/dist/services/profile/reviews/index.d.ts.map +1 -0
  160. package/dist/services/profile/reviews/index.js +431 -0
  161. package/dist/services/profile/reviews/index.js.map +1 -0
  162. package/dist/services/profile/shared.d.ts +127 -0
  163. package/dist/services/profile/shared.d.ts.map +1 -0
  164. package/dist/services/profile/shared.js +155 -0
  165. package/dist/services/profile/shared.js.map +1 -0
  166. package/dist/services/profile/skills/index.d.ts +212 -0
  167. package/dist/services/profile/skills/index.d.ts.map +1 -0
  168. package/dist/services/profile/skills/index.js +461 -0
  169. package/dist/services/profile/skills/index.js.map +1 -0
  170. package/dist/services/profile/visas/index.d.ts +74 -0
  171. package/dist/services/profile/visas/index.d.ts.map +1 -0
  172. package/dist/services/profile/visas/index.js +306 -0
  173. package/dist/services/profile/visas/index.js.map +1 -0
  174. package/dist/services/timesheet/index.d.ts +337 -0
  175. package/dist/services/timesheet/index.d.ts.map +1 -0
  176. package/dist/services/timesheet/index.js +336 -0
  177. package/dist/services/timesheet/index.js.map +1 -0
  178. package/dist/services/translations.d.ts +79 -0
  179. package/dist/services/translations.d.ts.map +1 -0
  180. package/dist/services/translations.js +136 -0
  181. package/dist/services/translations.js.map +1 -0
  182. package/dist/transport-resilience.d.ts +136 -0
  183. package/dist/transport-resilience.d.ts.map +1 -0
  184. package/dist/transport-resilience.js +247 -0
  185. package/dist/transport-resilience.js.map +1 -0
  186. package/dist/transport.d.ts +408 -0
  187. package/dist/transport.d.ts.map +1 -0
  188. package/dist/transport.js +691 -0
  189. package/dist/transport.js.map +1 -0
  190. package/dist/types.d.ts +41 -0
  191. package/dist/types.d.ts.map +1 -0
  192. package/dist/types.js +18 -0
  193. package/dist/types.js.map +1 -0
  194. package/package.json +40 -12
  195. package/index.js +0 -7
@@ -0,0 +1,640 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ /**
4
+ * `profile.external` service module.
5
+ *
6
+ * The "external" sub-domain is the most heterogeneous of the 11 profile
7
+ * sub-domains: it bundles operations that the operation catalog clusters
8
+ * under the umbrella names `external profile / advanced profile / wizard`.
9
+ * Per issue #76 the v0 user-facing surface exposes:
10
+ *
11
+ * 1. {@link update} — set external profile URLs (linkedin/github/website/…)
12
+ * 2. {@link customRequirementsShow} — read the three onboarding-readiness toggles
13
+ * 3. {@link customRequirementsSet} — toggle the three onboarding-readiness booleans
14
+ * 4. {@link readiness} — read the per-section completion meter
15
+ * 5. {@link recommendations} — read the per-section "do this next" recommendations
16
+ * 6. {@link advancedWizardShow} — read the advanced-profile-wizard status
17
+ *
18
+ * ## Spec / API divergences (documented per #76 AC)
19
+ *
20
+ * The issue (#76) describes `customRequirementsSet` as multi-paragraph
21
+ * **free-text** (and the AC explicitly lists "Free-text helper (#70) consumed
22
+ * by `external custom-requirements set`"). Empirically — see
23
+ * `research/captures/web/inputs/UpdateCustomRequirementsInput.json` and
24
+ * `research/graphql/talent_profile/fragments/CustomRequirements.graphql` —
25
+ * the underlying `CustomRequirementsInput` is in fact **three booleans**
26
+ * (`backgroundCheck`, `drugTest`, `timeTrackingTools`); no free-text field
27
+ * exists on the schema. The capture notes:
28
+ *
29
+ * "Form has no save button — autosaves on checkbox toggle. Each toggle
30
+ * sends ALL three current states (no diff/PATCH semantics)."
31
+ *
32
+ * We follow API ground truth: the `set` function takes the boolean trio.
33
+ * The free-text helper (#70) is therefore **not** consumed by this leaf.
34
+ * The AC item failure is surfaced in the PR description and CHANGELOG.
35
+ *
36
+ * The issue spec also lists `--portfolio-url` as a field of `update`. The
37
+ * actual schema's settable external-profile fields are `linkedin / github /
38
+ * website / twitter / behance / dribbble`; a portfolio URL is a server-
39
+ * determined read (`getPublicProfileUrl`), not a settable input. We expose
40
+ * the schema-supported set; `--portfolio-url` is dropped.
41
+ *
42
+ * ## Operations explicitly NOT exposed at v0
43
+ *
44
+ * Per issue #76 § "Operations explicitly NOT exposed as user-facing CLI
45
+ * leaves", the following are intentionally **not** implemented at v0. None
46
+ * is exported from this module — they are not even private helpers — so
47
+ * future maintainers can audit the exact deferral set without shadow-API
48
+ * hazards. File a follow-up issue if user demand surfaces:
49
+ *
50
+ * - `getStepsAndLinks` — implementation-detail navigation helper
51
+ * - `getProfilePrefillStatus` — server-determined prefill state
52
+ * - `getProfileSettingsUrls` — settings-URL navigator
53
+ * - `getPublicProfileUrl` — single value; defer until user demand
54
+ * - `getProfileVersionsCount` — internal telemetry
55
+ * - `analyticsInfo` — internal telemetry
56
+ * - `getProfileTimestamps` — internal telemetry
57
+ * - `getProfileItems` — generic list with unclear semantics
58
+ * - `UpdateAdvancedProfileWizardStatus` — wizard-internal state mutation
59
+ *
60
+ * ## Wire-shape decisions
61
+ *
62
+ * All operations target the talent_profile surface
63
+ * (`https://www.toptal.com/api/talent_profile/graphql`) which is
64
+ * Cloudflare-protected and uses {@link impersonatedTransport}. Because the
65
+ * talent_profile backend does not publish a persisted-query catalog, every
66
+ * operation is sent as a full-document GraphQL request. We hand-write the
67
+ * query/mutation strings here (mirrored from `research/graphql/
68
+ * talent_profile/operations/`) and the input/output TypeScript types because
69
+ * codegen is currently scoped to the gateway surface only (see
70
+ * `codegen.config.ts`).
71
+ *
72
+ * Mutation input shapes follow Pattern 1 of
73
+ * `research/notes/10-mutation-input-patterns.md` (`{ input: { profileId,
74
+ * <wrapper>: { … } } }`). The wrapper key is `profile` for
75
+ * `UpdateExternalProfiles` (validated 2026-05-17 via the
76
+ * 42-profile-external-show E2E round-trip — the previously inferred
77
+ * `externalProfiles` wrapper was wrong; same exception class as
78
+ * `UPDATE_BASIC_INFO` and `updateTimeZoneWorkingHours`, both of which write
79
+ * fields directly on the Profile entity) and `customRequirements` for
80
+ * `updateCustomRequirements` (empirically validated by
81
+ * `research/captures/web/inputs/UpdateCustomRequirementsInput.json`).
82
+ */
83
+ import { AuthRevokedError, TtctlError } from "../../../auth/errors.js";
84
+ import { impersonatedTransport } from "../../../transport.js";
85
+ import { ProfileError } from "../basic/index.js";
86
+ import { extractProfileId, isAuthRevokedExtensionCode } from "../shared.js";
87
+ // Re-export the shared `ProfileError` / `ProfileErrorCode` so consumers can
88
+ // continue to write `profile.external.ProfileError` (mirrors the
89
+ // `profile.basic.ProfileError` ergonomics).
90
+ export { ProfileError };
91
+ /**
92
+ * Parse a `TransportResponse` from the talent_profile surface into the
93
+ * typed `data` payload. Centralises the HTTP-status check, top-level
94
+ * GraphQL `errors` interpretation (with auth-revoked routing), and `data`
95
+ * presence check that every operation in this module needs.
96
+ *
97
+ * Returns `unknown` so callers can narrow to their operation-specific
98
+ * payload shape via a single `as` cast — this avoids `no-unnecessary-type-
99
+ * parameters` lint hits while keeping every call site one-line.
100
+ *
101
+ * `commandLabel` is folded into the error message ("<commandLabel> failed:
102
+ * …") so the user sees a meaningful prefix even for operations that share
103
+ * the same error code.
104
+ */
105
+ function parseTalentProfileResponse(res, commandLabel, fallbackErrorCode = "UNKNOWN") {
106
+ if (res.status === 401) {
107
+ throw new AuthRevokedError("Session is invalid or expired.");
108
+ }
109
+ if (res.status < 200 || res.status >= 300) {
110
+ throw new ProfileError(fallbackErrorCode, `${commandLabel} returned HTTP ${res.status.toString()}`);
111
+ }
112
+ const body = res.body;
113
+ if (body && Array.isArray(body.errors) && body.errors.length > 0) {
114
+ const first = body.errors[0];
115
+ const message = first?.message ?? "GraphQL error";
116
+ if (isAuthRevokedExtensionCode(first?.extensions?.code)) {
117
+ throw new AuthRevokedError("Session is invalid or expired.");
118
+ }
119
+ throw new ProfileError("GRAPHQL_ERROR", `${commandLabel} failed: ${message}`);
120
+ }
121
+ if (!body?.data) {
122
+ throw new ProfileError(fallbackErrorCode, `${commandLabel} response had no \`data\` field`);
123
+ }
124
+ return body.data;
125
+ }
126
+ /**
127
+ * Wrap a transport call so any thrown error becomes a typed
128
+ * `ProfileError(NETWORK_ERROR)`. `TtctlError` and `ProfileError` subclasses
129
+ * are preserved verbatim (the former carry their own `recovery` hints; the
130
+ * latter are already shape-correct).
131
+ */
132
+ async function withNetworkErrorMapping(commandLabel, fn) {
133
+ try {
134
+ return await fn();
135
+ }
136
+ catch (err) {
137
+ if (err instanceof TtctlError)
138
+ throw err;
139
+ if (err instanceof ProfileError)
140
+ throw err;
141
+ throw new ProfileError("NETWORK_ERROR", `${commandLabel} request failed: ${err.message}`, {
142
+ cause: err,
143
+ });
144
+ }
145
+ }
146
+ function coerceBoolean(value) {
147
+ return typeof value === "boolean" ? value : null;
148
+ }
149
+ function coerceString(value) {
150
+ return typeof value === "string" ? value : null;
151
+ }
152
+ /**
153
+ * Full-document `UpdateExternalProfiles` mutation. Mirrors
154
+ * `research/graphql/talent_profile/operations/UpdateExternalProfiles.graphql`
155
+ * with the fragments inlined. The `recommendations` selection from the
156
+ * upstream document is intentionally omitted at v0 — recommendations are
157
+ * surfaced via the dedicated `getProfileRecommendations` query
158
+ * ({@link recommendations}) and pulling them through every external-update
159
+ * response would force an over-broad type contract that's hard to keep
160
+ * stable. Caller can re-fetch recommendations after a successful update if
161
+ * they need the freshest list.
162
+ */
163
+ const UPDATE_EXTERNAL_PROFILES_MUTATION = `mutation UpdateExternalProfiles($input: UpdateExternalProfilesInput!) {
164
+ updateExternalProfiles(input: $input) {
165
+ profile {
166
+ id
167
+ updatedByTalentAt
168
+ linkedin
169
+ github
170
+ website
171
+ twitter
172
+ behance
173
+ dribbble
174
+ }
175
+ errors {
176
+ code
177
+ key
178
+ message
179
+ }
180
+ notice
181
+ success
182
+ }
183
+ }`;
184
+ /**
185
+ * Update external profile URLs (linkedin / github / website / twitter /
186
+ * behance / dribbble). Each field is optional; the caller must pass at
187
+ * least one. Unknown / extraneous fields are rejected at compile time by
188
+ * the {@link ExternalProfilesUpdate} type.
189
+ *
190
+ * Wire shape: `{ input: { profileId, profile: { …urls } } }`. Validated
191
+ * 2026-05-17 via the round-trip E2E at
192
+ * `packages/e2e/src/42-profile-external-show.e2e.test.ts`. The
193
+ * previously-inferred `externalProfiles:` wrapper (per Pattern 1 in
194
+ * `research/notes/10-mutation-input-patterns.md`) was incorrect — same
195
+ * exception class as `UPDATE_BASIC_INFO` and `updateTimeZoneWorkingHours`,
196
+ * both of which use `profile:` because they write fields directly on the
197
+ * Profile entity.
198
+ *
199
+ * Errors:
200
+ * - `ProfileError("VALIDATION_ERROR")` when no fields are supplied
201
+ * - `ProfileError("USER_ERROR")` when the server rejects an individual
202
+ * field (e.g. malformed URL)
203
+ * - `AuthRevokedError`, `Cf403Error`, other `TtctlError` subclasses
204
+ * propagate verbatim
205
+ */
206
+ export async function update(token, changes) {
207
+ const fields = {};
208
+ if (changes.linkedin !== undefined)
209
+ fields.linkedin = changes.linkedin;
210
+ if (changes.github !== undefined)
211
+ fields.github = changes.github;
212
+ if (changes.website !== undefined)
213
+ fields.website = changes.website;
214
+ if (changes.twitter !== undefined)
215
+ fields.twitter = changes.twitter;
216
+ if (changes.behance !== undefined)
217
+ fields.behance = changes.behance;
218
+ if (changes.dribbble !== undefined)
219
+ fields.dribbble = changes.dribbble;
220
+ if (Object.keys(fields).length === 0) {
221
+ throw new ProfileError("VALIDATION_ERROR", "External profile update requires at least one of linkedin/github/website/twitter/behance/dribbble.");
222
+ }
223
+ const profileId = await extractProfileId(token);
224
+ // Wire shape validated 2026-05-17 via TTCTL_E2E=1 round-trip in
225
+ // packages/e2e/src/42-profile-external-show.e2e.test.ts (re-apply current
226
+ // URL via update, show echoes it). The wrapper key is `profile:`, NOT
227
+ // `externalProfiles:` — Pattern 1 from research/notes/10 was inferred and
228
+ // wrong here. This is the same exception class as UPDATE_BASIC_INFO and
229
+ // updateTimeZoneWorkingHours: when the mutation writes fields directly on
230
+ // the Profile entity (rather than on a sub-entity like
231
+ // `customRequirements`), the wrapper is `profile:`. The
232
+ // UpdateExternalProfilesInput schema is `_placeholder: String` in the
233
+ // synthesized SDL — the live API is the only authority on the shape.
234
+ const res = await withNetworkErrorMapping("External profile update", () => impersonatedTransport({
235
+ surface: "talent-profile",
236
+ authToken: token,
237
+ body: {
238
+ operationName: "UpdateExternalProfiles",
239
+ query: UPDATE_EXTERNAL_PROFILES_MUTATION,
240
+ variables: { input: { profileId, profile: fields } },
241
+ },
242
+ }));
243
+ const data = parseTalentProfileResponse(res, "External profile update");
244
+ const payload = data.updateExternalProfiles;
245
+ if (!payload) {
246
+ throw new ProfileError("UNKNOWN", "External profile update response had no `data.updateExternalProfiles` field");
247
+ }
248
+ if (Array.isArray(payload.errors) && payload.errors.length > 0) {
249
+ const first = payload.errors[0];
250
+ const fieldHint = first?.key ? ` (${first.key})` : "";
251
+ throw new ProfileError("USER_ERROR", `External profile update rejected${fieldHint}: ${first?.message ?? "unknown error"}`);
252
+ }
253
+ if (payload.success === false) {
254
+ throw new ProfileError("USER_ERROR", `External profile update reported success=false${payload.notice ? `: ${payload.notice}` : ""}`);
255
+ }
256
+ if (!payload.profile) {
257
+ throw new ProfileError("UNKNOWN", "External profile update succeeded but response had no profile payload");
258
+ }
259
+ return {
260
+ profile: {
261
+ id: payload.profile.id,
262
+ updatedByTalentAt: coerceString(payload.profile.updatedByTalentAt),
263
+ linkedin: payload.profile.linkedin ?? null,
264
+ github: payload.profile.github ?? null,
265
+ website: payload.profile.website ?? null,
266
+ twitter: payload.profile.twitter ?? null,
267
+ behance: payload.profile.behance ?? null,
268
+ dribbble: payload.profile.dribbble ?? null,
269
+ },
270
+ notice: payload.notice ?? null,
271
+ };
272
+ }
273
+ const GET_CUSTOM_REQUIREMENTS_QUERY = `query getCustomRequirements($profileId: ID!) {
274
+ profile(id: $profileId) {
275
+ id
276
+ customRequirements {
277
+ backgroundCheck
278
+ drugTest
279
+ timeTrackingTools
280
+ }
281
+ }
282
+ }`;
283
+ /**
284
+ * Read the three onboarding-readiness toggles for the signed-in user.
285
+ *
286
+ * Errors: `AuthRevokedError`, `ProfileError(GRAPHQL_ERROR)`,
287
+ * `ProfileError(NETWORK_ERROR)`, `Cf403Error` (and other `TtctlError`
288
+ * subclasses) propagate verbatim.
289
+ */
290
+ export async function customRequirementsShow(token) {
291
+ const profileId = await extractProfileId(token);
292
+ const res = await withNetworkErrorMapping("Custom requirements show", () => impersonatedTransport({
293
+ surface: "talent-profile",
294
+ authToken: token,
295
+ body: {
296
+ operationName: "getCustomRequirements",
297
+ query: GET_CUSTOM_REQUIREMENTS_QUERY,
298
+ variables: { profileId },
299
+ },
300
+ }));
301
+ const data = parseTalentProfileResponse(res, "Custom requirements show");
302
+ if (!data.profile) {
303
+ throw new ProfileError("NO_VIEWER", "Custom requirements query returned no profile.");
304
+ }
305
+ const cr = data.profile.customRequirements ?? {};
306
+ return {
307
+ backgroundCheck: coerceBoolean(cr.backgroundCheck),
308
+ drugTest: coerceBoolean(cr.drugTest),
309
+ timeTrackingTools: coerceBoolean(cr.timeTrackingTools),
310
+ };
311
+ }
312
+ const UPDATE_CUSTOM_REQUIREMENTS_MUTATION = `mutation updateCustomRequirements($input: UpdateCustomRequirementsInput!) {
313
+ updateCustomRequirements(input: $input) {
314
+ profile {
315
+ id
316
+ updatedByTalentAt
317
+ customRequirements {
318
+ backgroundCheck
319
+ drugTest
320
+ timeTrackingTools
321
+ }
322
+ }
323
+ errors {
324
+ code
325
+ key
326
+ message
327
+ }
328
+ notice
329
+ success
330
+ }
331
+ }`;
332
+ /**
333
+ * Toggle one or more of the three onboarding-readiness booleans
334
+ * (`backgroundCheck`, `drugTest`, `timeTrackingTools`). Caller-omitted
335
+ * fields are pre-filled from the current server state via
336
+ * {@link customRequirementsShow} before the mutation is sent (the underlying
337
+ * `updateCustomRequirements` mutation has no diff/PATCH semantics — every
338
+ * call resubmits all three booleans).
339
+ *
340
+ * Pre-fill of missing fields treats `null` (server has no value yet) as
341
+ * `false` for the post-merge wire shape, since the mutation input is
342
+ * `Boolean!` and rejects `null`.
343
+ *
344
+ * Errors: same taxonomy as {@link update}.
345
+ */
346
+ export async function customRequirementsSet(token, changes) {
347
+ if (changes.backgroundCheck === undefined &&
348
+ changes.drugTest === undefined &&
349
+ changes.timeTrackingTools === undefined) {
350
+ throw new ProfileError("VALIDATION_ERROR", "Custom requirements update requires at least one of backgroundCheck/drugTest/timeTrackingTools.");
351
+ }
352
+ // Resolve current state to fill in any caller-omitted fields. We deliberately
353
+ // make this fetch every time (rather than caching) — the mutation input is
354
+ // `Boolean!` for all three, and a stale cache would silently flip a bit the
355
+ // user didn't mean to change. The cost (one extra round-trip per set) is
356
+ // small relative to the user-visible correctness improvement.
357
+ const current = await customRequirementsShow(token);
358
+ const profileId = await extractProfileId(token);
359
+ const merged = {
360
+ backgroundCheck: changes.backgroundCheck ?? current.backgroundCheck ?? false,
361
+ drugTest: changes.drugTest ?? current.drugTest ?? false,
362
+ timeTrackingTools: changes.timeTrackingTools ?? current.timeTrackingTools ?? false,
363
+ };
364
+ const res = await withNetworkErrorMapping("Custom requirements update", () => impersonatedTransport({
365
+ surface: "talent-profile",
366
+ authToken: token,
367
+ body: {
368
+ operationName: "updateCustomRequirements",
369
+ query: UPDATE_CUSTOM_REQUIREMENTS_MUTATION,
370
+ variables: { input: { profileId, customRequirements: merged } },
371
+ },
372
+ }));
373
+ const data = parseTalentProfileResponse(res, "Custom requirements update");
374
+ const payload = data.updateCustomRequirements;
375
+ if (!payload) {
376
+ throw new ProfileError("UNKNOWN", "Custom requirements update response had no payload field");
377
+ }
378
+ if (Array.isArray(payload.errors) && payload.errors.length > 0) {
379
+ const first = payload.errors[0];
380
+ const fieldHint = first?.key ? ` (${first.key})` : "";
381
+ throw new ProfileError("USER_ERROR", `Custom requirements update rejected${fieldHint}: ${first?.message ?? "unknown error"}`);
382
+ }
383
+ if (payload.success === false) {
384
+ throw new ProfileError("USER_ERROR", `Custom requirements update reported success=false${payload.notice ? `: ${payload.notice}` : ""}`);
385
+ }
386
+ if (!payload.profile) {
387
+ throw new ProfileError("UNKNOWN", "Custom requirements update succeeded but response had no profile payload");
388
+ }
389
+ const cr = payload.profile.customRequirements ?? {};
390
+ return {
391
+ profile: {
392
+ id: payload.profile.id,
393
+ updatedByTalentAt: coerceString(payload.profile.updatedByTalentAt),
394
+ customRequirements: {
395
+ backgroundCheck: coerceBoolean(cr.backgroundCheck),
396
+ drugTest: coerceBoolean(cr.drugTest),
397
+ timeTrackingTools: coerceBoolean(cr.timeTrackingTools),
398
+ },
399
+ },
400
+ notice: payload.notice ?? null,
401
+ };
402
+ }
403
+ const GET_PROFILE_READINESS_QUERY = `query getProfileReadiness($profileId: ID!) {
404
+ profile(id: $profileId) {
405
+ id
406
+ submitAvailable
407
+ updatedByTalentAt
408
+ profileReadiness {
409
+ isPhotoResolutionSatisfied
410
+ isBasicInfoSatisfied
411
+ isCertificationsSatisfied
412
+ isEmploymentsCountSatisfied
413
+ isEmploymentConnectionsSatisfied
414
+ isSkillValidationsSatisfied
415
+ isPortfolioItemsCountSatisfied
416
+ isPortfolioItemConnectionsSatisfied
417
+ isWorkingHoursSatisfied
418
+ }
419
+ }
420
+ }`;
421
+ /**
422
+ * Read the per-section profile-readiness booleans plus the rolled-up
423
+ * `submitAvailable` flag and the last-edit timestamp.
424
+ *
425
+ * Errors: same taxonomy as {@link customRequirementsShow}.
426
+ */
427
+ export async function readiness(token) {
428
+ const profileId = await extractProfileId(token);
429
+ const res = await withNetworkErrorMapping("Profile readiness", () => impersonatedTransport({
430
+ surface: "talent-profile",
431
+ authToken: token,
432
+ body: {
433
+ operationName: "getProfileReadiness",
434
+ query: GET_PROFILE_READINESS_QUERY,
435
+ variables: { profileId },
436
+ },
437
+ }));
438
+ const data = parseTalentProfileResponse(res, "Profile readiness");
439
+ if (!data.profile) {
440
+ throw new ProfileError("NO_VIEWER", "Profile readiness query returned no profile.");
441
+ }
442
+ const pr = data.profile.profileReadiness ?? {};
443
+ return {
444
+ isPhotoResolutionSatisfied: coerceBoolean(pr.isPhotoResolutionSatisfied),
445
+ isBasicInfoSatisfied: coerceBoolean(pr.isBasicInfoSatisfied),
446
+ isCertificationsSatisfied: coerceBoolean(pr.isCertificationsSatisfied),
447
+ isEmploymentsCountSatisfied: coerceBoolean(pr.isEmploymentsCountSatisfied),
448
+ isEmploymentConnectionsSatisfied: coerceBoolean(pr.isEmploymentConnectionsSatisfied),
449
+ isSkillValidationsSatisfied: coerceBoolean(pr.isSkillValidationsSatisfied),
450
+ isPortfolioItemsCountSatisfied: coerceBoolean(pr.isPortfolioItemsCountSatisfied),
451
+ isPortfolioItemConnectionsSatisfied: coerceBoolean(pr.isPortfolioItemConnectionsSatisfied),
452
+ isWorkingHoursSatisfied: coerceBoolean(pr.isWorkingHoursSatisfied),
453
+ submitAvailable: coerceBoolean(data.profile.submitAvailable),
454
+ updatedByTalentAt: coerceString(data.profile.updatedByTalentAt),
455
+ };
456
+ }
457
+ const GET_PROFILE_RECOMMENDATIONS_QUERY = `query getProfileRecommendations($profileId: ID!) {
458
+ profile(id: $profileId) {
459
+ id
460
+ recommendations {
461
+ nodes {
462
+ type
463
+ ... on EmploymentsCountRecommendation { minimumCount }
464
+ ... on PortfolioItemsCountRecommendation { minimumCount }
465
+ ... on AdvancedProfileRecommendation { isCustomRequirementsCompleted isTravelInformationCompleted }
466
+ ... on ProfileFreshnessRecommendation {
467
+ skillsStatus
468
+ certificationsStatus
469
+ educationsStatus
470
+ workExperiencesStatus
471
+ portfolioItemsStatus
472
+ }
473
+ }
474
+ }
475
+ }
476
+ }`;
477
+ /**
478
+ * Read the list of profile recommendations. Each recommendation has a
479
+ * discriminator `type` and a small payload of variant-specific fields.
480
+ *
481
+ * Recommendations that involve nested entity lists (e.g.
482
+ * `EmploymentsMissingDataRecommendation` with a `nodes` array of employments)
483
+ * are intentionally trimmed at the GraphQL level — at v0 the CLI/MCP only
484
+ * surfaces the recommendation `type` and any scalar variant fields. Drilling
485
+ * into nested entity lists requires fetching the underlying domain
486
+ * (employments, portfolio items, skills) directly, which is outside the
487
+ * recommendations leaf's scope.
488
+ */
489
+ export async function recommendations(token) {
490
+ const profileId = await extractProfileId(token);
491
+ const res = await withNetworkErrorMapping("Profile recommendations", () => impersonatedTransport({
492
+ surface: "talent-profile",
493
+ authToken: token,
494
+ body: {
495
+ operationName: "getProfileRecommendations",
496
+ query: GET_PROFILE_RECOMMENDATIONS_QUERY,
497
+ variables: { profileId },
498
+ },
499
+ }));
500
+ const data = parseTalentProfileResponse(res, "Profile recommendations");
501
+ if (!data.profile) {
502
+ throw new ProfileError("NO_VIEWER", "Profile recommendations query returned no profile.");
503
+ }
504
+ const nodes = data.profile.recommendations?.nodes ?? [];
505
+ return nodes
506
+ .filter((n) => n !== null && typeof n === "object")
507
+ .map((node) => {
508
+ // Build a clean payload by stripping the discriminator and `__typename`.
509
+ const payload = {};
510
+ for (const [k, v] of Object.entries(node)) {
511
+ if (k === "type" || k === "__typename")
512
+ continue;
513
+ payload[k] = v;
514
+ }
515
+ const type = node.type;
516
+ return {
517
+ type: typeof type === "string" ? type : "Unknown",
518
+ payload,
519
+ };
520
+ });
521
+ }
522
+ const GET_ADVANCED_PROFILE_DATA_QUERY = `query getAdvancedProfileData($profileId: ID!) {
523
+ profile(id: $profileId) {
524
+ id
525
+ advancedProfileWizardStatus
526
+ travelVisas {
527
+ nodes {
528
+ id
529
+ }
530
+ }
531
+ }
532
+ }`;
533
+ /**
534
+ * Read the advanced-profile-wizard status plus a summary of the talent's
535
+ * travel-visa list. This is the read-side combined view of
536
+ * `getAdvancedProfileData` — the spec also references
537
+ * `GetAdvancedProfileWizardStatus` as a separate operation, but
538
+ * `getAdvancedProfileData` already returns `advancedProfileWizardStatus`, so
539
+ * one query is sufficient.
540
+ *
541
+ * The full TravelVisa fragment is intentionally trimmed to `id` only. Visa
542
+ * CRUD operations live in the `visas` sub-domain — surfacing the rich shape
543
+ * here would create a partial duplication that drifts as the visas
544
+ * sub-domain evolves.
545
+ */
546
+ export async function advancedWizardShow(token) {
547
+ const profileId = await extractProfileId(token);
548
+ const res = await withNetworkErrorMapping("Advanced profile wizard show", () => impersonatedTransport({
549
+ surface: "talent-profile",
550
+ authToken: token,
551
+ body: {
552
+ operationName: "getAdvancedProfileData",
553
+ query: GET_ADVANCED_PROFILE_DATA_QUERY,
554
+ variables: { profileId },
555
+ },
556
+ }));
557
+ const data = parseTalentProfileResponse(res, "Advanced profile wizard show");
558
+ if (!data.profile) {
559
+ throw new ProfileError("NO_VIEWER", "Advanced profile data query returned no profile.");
560
+ }
561
+ const visaNodes = data.profile.travelVisas?.nodes ?? [];
562
+ const travelVisaIds = visaNodes
563
+ .filter((n) => n !== null && typeof n === "object")
564
+ .map((n) => (typeof n.id === "string" ? n.id : ""))
565
+ .filter((id) => id.length > 0);
566
+ return {
567
+ wizardStatus: coerceString(data.profile.advancedProfileWizardStatus),
568
+ travelVisaCount: travelVisaIds.length,
569
+ travelVisaIds,
570
+ };
571
+ }
572
+ /**
573
+ * Full-document `getExternalProfiles` query. Reads the six external-URL
574
+ * fields directly off the `Profile` type via the `profile(id:)` root
575
+ * query — the same access pattern `GET_BASIC_INFO` uses (it selects the
576
+ * identical six URL fields). Mirrored at
577
+ * `research/graphql/talent_profile/operations/getExternalProfiles.graphql`.
578
+ *
579
+ * **INFERRED — UNVERIFIED**: the synthesized talent_profile SDL types
580
+ * every selected field as the `Unknown` placeholder (no live capture
581
+ * pinned a concrete type), so this operation is listed in
582
+ * `TALENT_PROFILE_KNOWN_UNTRUSTED_OPS` (codegen excludes it; T1
583
+ * wire-shape-snapshot disposition). The wire shape is exercised by
584
+ * `packages/e2e/src/42-profile-external-show.e2e.test.ts` (gated by
585
+ * `TTCTL_E2E=1`) per CLAUDE.md § Schema/contract validation rule.
586
+ */
587
+ const GET_EXTERNAL_PROFILES_QUERY = `query getExternalProfiles($profileId: ID!) {
588
+ profile(id: $profileId) {
589
+ id
590
+ updatedByTalentAt
591
+ linkedin
592
+ github
593
+ website
594
+ twitter
595
+ behance
596
+ dribbble
597
+ }
598
+ }`;
599
+ /**
600
+ * Read the talent's stored external profile URLs (linkedin / github /
601
+ * website / twitter / behance / dribbble) plus `id` and the last
602
+ * talent-side edit timestamp.
603
+ *
604
+ * This is the primary read for the external-URL state — use it instead of
605
+ * a no-op {@link update} (which is a write-disguised-as-read and risks an
606
+ * unintended write if the response is misinterpreted).
607
+ *
608
+ * Errors: `AuthRevokedError`, `ProfileError(GRAPHQL_ERROR)`,
609
+ * `ProfileError(NETWORK_ERROR)`, `ProfileError(NO_VIEWER)`, `Cf403Error`
610
+ * (and other `TtctlError` subclasses) propagate verbatim — same taxonomy
611
+ * as {@link customRequirementsShow} / {@link readiness}.
612
+ */
613
+ export async function show(token) {
614
+ const profileId = await extractProfileId(token);
615
+ const res = await withNetworkErrorMapping("External profiles show", () => impersonatedTransport({
616
+ surface: "talent-profile",
617
+ authToken: token,
618
+ body: {
619
+ operationName: "getExternalProfiles",
620
+ query: GET_EXTERNAL_PROFILES_QUERY,
621
+ variables: { profileId },
622
+ },
623
+ }));
624
+ const data = parseTalentProfileResponse(res, "External profiles show");
625
+ if (!data.profile) {
626
+ throw new ProfileError("NO_VIEWER", "External profiles query returned no profile.");
627
+ }
628
+ const p = data.profile;
629
+ return {
630
+ id: p.id,
631
+ updatedByTalentAt: coerceString(p.updatedByTalentAt),
632
+ linkedin: coerceString(p.linkedin),
633
+ github: coerceString(p.github),
634
+ website: coerceString(p.website),
635
+ twitter: coerceString(p.twitter),
636
+ behance: coerceString(p.behance),
637
+ dribbble: coerceString(p.dribbble),
638
+ };
639
+ }
640
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/services/profile/external/index.ts"],"names":[],"mappings":"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"}