@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.
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 +196 -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 +230 -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 +212 -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 +50 -0
  47. package/dist/configLock.d.ts.map +1 -0
  48. package/dist/configLock.js +88 -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 +687 -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 +415 -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 +111 -0
  135. package/dist/services/profile/employment/index.d.ts.map +1 -0
  136. package/dist/services/profile/employment/index.js +202 -0
  137. package/dist/services/profile/employment/index.js.map +1 -0
  138. package/dist/services/profile/external/index.d.ts +219 -0
  139. package/dist/services/profile/external/index.d.ts.map +1 -0
  140. package/dist/services/profile/external/index.js +560 -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 +326 -0
  175. package/dist/services/timesheet/index.d.ts.map +1 -0
  176. package/dist/services/timesheet/index.js +324 -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,560 @@
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 `externalProfiles` for
75
+ * `UpdateExternalProfiles` and `customRequirements` for
76
+ * `updateCustomRequirements` (the latter is empirically validated by
77
+ * `research/captures/web/inputs/UpdateCustomRequirementsInput.json`).
78
+ */
79
+ import { AuthRevokedError, TtctlError } from "../../../auth/errors.js";
80
+ import { impersonatedTransport } from "../../../transport.js";
81
+ import { ProfileError } from "../basic/index.js";
82
+ import { extractProfileId, isAuthRevokedExtensionCode } from "../shared.js";
83
+ // Re-export the shared `ProfileError` / `ProfileErrorCode` so consumers can
84
+ // continue to write `profile.external.ProfileError` (mirrors the
85
+ // `profile.basic.ProfileError` ergonomics).
86
+ export { ProfileError };
87
+ /**
88
+ * Parse a `TransportResponse` from the talent_profile surface into the
89
+ * typed `data` payload. Centralises the HTTP-status check, top-level
90
+ * GraphQL `errors` interpretation (with auth-revoked routing), and `data`
91
+ * presence check that every operation in this module needs.
92
+ *
93
+ * Returns `unknown` so callers can narrow to their operation-specific
94
+ * payload shape via a single `as` cast — this avoids `no-unnecessary-type-
95
+ * parameters` lint hits while keeping every call site one-line.
96
+ *
97
+ * `commandLabel` is folded into the error message ("<commandLabel> failed:
98
+ * …") so the user sees a meaningful prefix even for operations that share
99
+ * the same error code.
100
+ */
101
+ function parseTalentProfileResponse(res, commandLabel, fallbackErrorCode = "UNKNOWN") {
102
+ if (res.status === 401) {
103
+ throw new AuthRevokedError("Session is invalid or expired.");
104
+ }
105
+ if (res.status < 200 || res.status >= 300) {
106
+ throw new ProfileError(fallbackErrorCode, `${commandLabel} returned HTTP ${res.status.toString()}`);
107
+ }
108
+ const body = res.body;
109
+ if (body && Array.isArray(body.errors) && body.errors.length > 0) {
110
+ const first = body.errors[0];
111
+ const message = first?.message ?? "GraphQL error";
112
+ if (isAuthRevokedExtensionCode(first?.extensions?.code)) {
113
+ throw new AuthRevokedError("Session is invalid or expired.");
114
+ }
115
+ throw new ProfileError("GRAPHQL_ERROR", `${commandLabel} failed: ${message}`);
116
+ }
117
+ if (!body?.data) {
118
+ throw new ProfileError(fallbackErrorCode, `${commandLabel} response had no \`data\` field`);
119
+ }
120
+ return body.data;
121
+ }
122
+ /**
123
+ * Wrap a transport call so any thrown error becomes a typed
124
+ * `ProfileError(NETWORK_ERROR)`. `TtctlError` and `ProfileError` subclasses
125
+ * are preserved verbatim (the former carry their own `recovery` hints; the
126
+ * latter are already shape-correct).
127
+ */
128
+ async function withNetworkErrorMapping(commandLabel, fn) {
129
+ try {
130
+ return await fn();
131
+ }
132
+ catch (err) {
133
+ if (err instanceof TtctlError)
134
+ throw err;
135
+ if (err instanceof ProfileError)
136
+ throw err;
137
+ throw new ProfileError("NETWORK_ERROR", `${commandLabel} request failed: ${err.message}`, {
138
+ cause: err,
139
+ });
140
+ }
141
+ }
142
+ function coerceBoolean(value) {
143
+ return typeof value === "boolean" ? value : null;
144
+ }
145
+ function coerceString(value) {
146
+ return typeof value === "string" ? value : null;
147
+ }
148
+ /**
149
+ * Full-document `UpdateExternalProfiles` mutation. Mirrors
150
+ * `research/graphql/talent_profile/operations/UpdateExternalProfiles.graphql`
151
+ * with the fragments inlined. The `recommendations` selection from the
152
+ * upstream document is intentionally omitted at v0 — recommendations are
153
+ * surfaced via the dedicated `getProfileRecommendations` query
154
+ * ({@link recommendations}) and pulling them through every external-update
155
+ * response would force an over-broad type contract that's hard to keep
156
+ * stable. Caller can re-fetch recommendations after a successful update if
157
+ * they need the freshest list.
158
+ */
159
+ const UPDATE_EXTERNAL_PROFILES_MUTATION = `mutation UpdateExternalProfiles($input: UpdateExternalProfilesInput!) {
160
+ updateExternalProfiles(input: $input) {
161
+ profile {
162
+ id
163
+ updatedByTalentAt
164
+ linkedin
165
+ github
166
+ website
167
+ behance
168
+ dribbble
169
+ }
170
+ errors {
171
+ code
172
+ key
173
+ message
174
+ }
175
+ notice
176
+ success
177
+ }
178
+ }`;
179
+ /**
180
+ * Update external profile URLs (linkedin / github / website / twitter /
181
+ * behance / dribbble). Each field is optional; the caller must pass at
182
+ * least one. Unknown / extraneous fields are rejected at compile time by
183
+ * the {@link ExternalProfilesUpdate} type.
184
+ *
185
+ * Wire shape follows Pattern 1 of `research/notes/10-mutation-input-patterns.md`
186
+ * with the wrapper key `externalProfiles`. **INFERRED — UNVERIFIED**: no
187
+ * live curl capture exists in `research/captures/web/inputs/` for this
188
+ * mutation; deviations would surface as `USER_ERROR` at runtime.
189
+ *
190
+ * Errors:
191
+ * - `ProfileError("VALIDATION_ERROR")` when no fields are supplied
192
+ * - `ProfileError("USER_ERROR")` when the server rejects an individual
193
+ * field (e.g. malformed URL)
194
+ * - `AuthRevokedError`, `Cf403Error`, other `TtctlError` subclasses
195
+ * propagate verbatim
196
+ */
197
+ export async function update(token, changes) {
198
+ const fields = {};
199
+ if (changes.linkedin !== undefined)
200
+ fields.linkedin = changes.linkedin;
201
+ if (changes.github !== undefined)
202
+ fields.github = changes.github;
203
+ if (changes.website !== undefined)
204
+ fields.website = changes.website;
205
+ if (changes.twitter !== undefined)
206
+ fields.twitter = changes.twitter;
207
+ if (changes.behance !== undefined)
208
+ fields.behance = changes.behance;
209
+ if (changes.dribbble !== undefined)
210
+ fields.dribbble = changes.dribbble;
211
+ if (Object.keys(fields).length === 0) {
212
+ throw new ProfileError("VALIDATION_ERROR", "External profile update requires at least one of linkedin/github/website/twitter/behance/dribbble.");
213
+ }
214
+ const profileId = await extractProfileId(token);
215
+ // No safe round-trip: the service has no read endpoint exposing
216
+ // linkedin/github/website/twitter/behance/dribbble (basic profile show
217
+ // does not include them; the mutation response gives POST-state only),
218
+ // so a sentinel value cannot be reverted without a captured pre-state.
219
+ // Overwriting the maintainer's real URLs is destructive. Wire shape
220
+ // inferred from research/notes/10 Pattern 1 (wrapper key
221
+ // `externalProfiles`); see packages/e2e/src/38-profile-external.e2e.test.ts.
222
+ const res = await withNetworkErrorMapping("External profile update", () => impersonatedTransport({
223
+ surface: "talent-profile",
224
+ authToken: token,
225
+ body: {
226
+ // e2e-exempt: destructive — see comment above the withNetworkErrorMapping call.
227
+ operationName: "UpdateExternalProfiles",
228
+ query: UPDATE_EXTERNAL_PROFILES_MUTATION,
229
+ variables: { input: { profileId, externalProfiles: fields } },
230
+ },
231
+ }));
232
+ const data = parseTalentProfileResponse(res, "External profile update");
233
+ const payload = data.updateExternalProfiles;
234
+ if (!payload) {
235
+ throw new ProfileError("UNKNOWN", "External profile update response had no `data.updateExternalProfiles` field");
236
+ }
237
+ if (Array.isArray(payload.errors) && payload.errors.length > 0) {
238
+ const first = payload.errors[0];
239
+ const fieldHint = first?.key ? ` (${first.key})` : "";
240
+ throw new ProfileError("USER_ERROR", `External profile update rejected${fieldHint}: ${first?.message ?? "unknown error"}`);
241
+ }
242
+ if (payload.success === false) {
243
+ throw new ProfileError("USER_ERROR", `External profile update reported success=false${payload.notice ? `: ${payload.notice}` : ""}`);
244
+ }
245
+ if (!payload.profile) {
246
+ throw new ProfileError("UNKNOWN", "External profile update succeeded but response had no profile payload");
247
+ }
248
+ return {
249
+ profile: {
250
+ id: payload.profile.id,
251
+ updatedByTalentAt: coerceString(payload.profile.updatedByTalentAt),
252
+ linkedin: payload.profile.linkedin ?? null,
253
+ github: payload.profile.github ?? null,
254
+ website: payload.profile.website ?? null,
255
+ behance: payload.profile.behance ?? null,
256
+ dribbble: payload.profile.dribbble ?? null,
257
+ },
258
+ notice: payload.notice ?? null,
259
+ };
260
+ }
261
+ const GET_CUSTOM_REQUIREMENTS_QUERY = `query getCustomRequirements($profileId: ID!) {
262
+ profile(id: $profileId) {
263
+ id
264
+ customRequirements {
265
+ backgroundCheck
266
+ drugTest
267
+ timeTrackingTools
268
+ }
269
+ }
270
+ }`;
271
+ /**
272
+ * Read the three onboarding-readiness toggles for the signed-in user.
273
+ *
274
+ * Errors: `AuthRevokedError`, `ProfileError(GRAPHQL_ERROR)`,
275
+ * `ProfileError(NETWORK_ERROR)`, `Cf403Error` (and other `TtctlError`
276
+ * subclasses) propagate verbatim.
277
+ */
278
+ export async function customRequirementsShow(token) {
279
+ const profileId = await extractProfileId(token);
280
+ const res = await withNetworkErrorMapping("Custom requirements show", () => impersonatedTransport({
281
+ surface: "talent-profile",
282
+ authToken: token,
283
+ body: {
284
+ operationName: "getCustomRequirements",
285
+ query: GET_CUSTOM_REQUIREMENTS_QUERY,
286
+ variables: { profileId },
287
+ },
288
+ }));
289
+ const data = parseTalentProfileResponse(res, "Custom requirements show");
290
+ if (!data.profile) {
291
+ throw new ProfileError("NO_VIEWER", "Custom requirements query returned no profile.");
292
+ }
293
+ const cr = data.profile.customRequirements ?? {};
294
+ return {
295
+ backgroundCheck: coerceBoolean(cr.backgroundCheck),
296
+ drugTest: coerceBoolean(cr.drugTest),
297
+ timeTrackingTools: coerceBoolean(cr.timeTrackingTools),
298
+ };
299
+ }
300
+ const UPDATE_CUSTOM_REQUIREMENTS_MUTATION = `mutation updateCustomRequirements($input: UpdateCustomRequirementsInput!) {
301
+ updateCustomRequirements(input: $input) {
302
+ profile {
303
+ id
304
+ updatedByTalentAt
305
+ customRequirements {
306
+ backgroundCheck
307
+ drugTest
308
+ timeTrackingTools
309
+ }
310
+ }
311
+ errors {
312
+ code
313
+ key
314
+ message
315
+ }
316
+ notice
317
+ success
318
+ }
319
+ }`;
320
+ /**
321
+ * Toggle one or more of the three onboarding-readiness booleans
322
+ * (`backgroundCheck`, `drugTest`, `timeTrackingTools`). Caller-omitted
323
+ * fields are pre-filled from the current server state via
324
+ * {@link customRequirementsShow} before the mutation is sent (the underlying
325
+ * `updateCustomRequirements` mutation has no diff/PATCH semantics — every
326
+ * call resubmits all three booleans).
327
+ *
328
+ * Pre-fill of missing fields treats `null` (server has no value yet) as
329
+ * `false` for the post-merge wire shape, since the mutation input is
330
+ * `Boolean!` and rejects `null`.
331
+ *
332
+ * Errors: same taxonomy as {@link update}.
333
+ */
334
+ export async function customRequirementsSet(token, changes) {
335
+ if (changes.backgroundCheck === undefined &&
336
+ changes.drugTest === undefined &&
337
+ changes.timeTrackingTools === undefined) {
338
+ throw new ProfileError("VALIDATION_ERROR", "Custom requirements update requires at least one of backgroundCheck/drugTest/timeTrackingTools.");
339
+ }
340
+ // Resolve current state to fill in any caller-omitted fields. We deliberately
341
+ // make this fetch every time (rather than caching) — the mutation input is
342
+ // `Boolean!` for all three, and a stale cache would silently flip a bit the
343
+ // user didn't mean to change. The cost (one extra round-trip per set) is
344
+ // small relative to the user-visible correctness improvement.
345
+ const current = await customRequirementsShow(token);
346
+ const profileId = await extractProfileId(token);
347
+ const merged = {
348
+ backgroundCheck: changes.backgroundCheck ?? current.backgroundCheck ?? false,
349
+ drugTest: changes.drugTest ?? current.drugTest ?? false,
350
+ timeTrackingTools: changes.timeTrackingTools ?? current.timeTrackingTools ?? false,
351
+ };
352
+ const res = await withNetworkErrorMapping("Custom requirements update", () => impersonatedTransport({
353
+ surface: "talent-profile",
354
+ authToken: token,
355
+ body: {
356
+ operationName: "updateCustomRequirements",
357
+ query: UPDATE_CUSTOM_REQUIREMENTS_MUTATION,
358
+ variables: { input: { profileId, customRequirements: merged } },
359
+ },
360
+ }));
361
+ const data = parseTalentProfileResponse(res, "Custom requirements update");
362
+ const payload = data.updateCustomRequirements;
363
+ if (!payload) {
364
+ throw new ProfileError("UNKNOWN", "Custom requirements update response had no payload field");
365
+ }
366
+ if (Array.isArray(payload.errors) && payload.errors.length > 0) {
367
+ const first = payload.errors[0];
368
+ const fieldHint = first?.key ? ` (${first.key})` : "";
369
+ throw new ProfileError("USER_ERROR", `Custom requirements update rejected${fieldHint}: ${first?.message ?? "unknown error"}`);
370
+ }
371
+ if (payload.success === false) {
372
+ throw new ProfileError("USER_ERROR", `Custom requirements update reported success=false${payload.notice ? `: ${payload.notice}` : ""}`);
373
+ }
374
+ if (!payload.profile) {
375
+ throw new ProfileError("UNKNOWN", "Custom requirements update succeeded but response had no profile payload");
376
+ }
377
+ const cr = payload.profile.customRequirements ?? {};
378
+ return {
379
+ profile: {
380
+ id: payload.profile.id,
381
+ updatedByTalentAt: coerceString(payload.profile.updatedByTalentAt),
382
+ customRequirements: {
383
+ backgroundCheck: coerceBoolean(cr.backgroundCheck),
384
+ drugTest: coerceBoolean(cr.drugTest),
385
+ timeTrackingTools: coerceBoolean(cr.timeTrackingTools),
386
+ },
387
+ },
388
+ notice: payload.notice ?? null,
389
+ };
390
+ }
391
+ const GET_PROFILE_READINESS_QUERY = `query getProfileReadiness($profileId: ID!) {
392
+ profile(id: $profileId) {
393
+ id
394
+ submitAvailable
395
+ updatedByTalentAt
396
+ profileReadiness {
397
+ isPhotoResolutionSatisfied
398
+ isBasicInfoSatisfied
399
+ isCertificationsSatisfied
400
+ isEmploymentsCountSatisfied
401
+ isEmploymentConnectionsSatisfied
402
+ isSkillValidationsSatisfied
403
+ isPortfolioItemsCountSatisfied
404
+ isPortfolioItemConnectionsSatisfied
405
+ isWorkingHoursSatisfied
406
+ }
407
+ }
408
+ }`;
409
+ /**
410
+ * Read the per-section profile-readiness booleans plus the rolled-up
411
+ * `submitAvailable` flag and the last-edit timestamp.
412
+ *
413
+ * Errors: same taxonomy as {@link customRequirementsShow}.
414
+ */
415
+ export async function readiness(token) {
416
+ const profileId = await extractProfileId(token);
417
+ const res = await withNetworkErrorMapping("Profile readiness", () => impersonatedTransport({
418
+ surface: "talent-profile",
419
+ authToken: token,
420
+ body: {
421
+ operationName: "getProfileReadiness",
422
+ query: GET_PROFILE_READINESS_QUERY,
423
+ variables: { profileId },
424
+ },
425
+ }));
426
+ const data = parseTalentProfileResponse(res, "Profile readiness");
427
+ if (!data.profile) {
428
+ throw new ProfileError("NO_VIEWER", "Profile readiness query returned no profile.");
429
+ }
430
+ const pr = data.profile.profileReadiness ?? {};
431
+ return {
432
+ isPhotoResolutionSatisfied: coerceBoolean(pr.isPhotoResolutionSatisfied),
433
+ isBasicInfoSatisfied: coerceBoolean(pr.isBasicInfoSatisfied),
434
+ isCertificationsSatisfied: coerceBoolean(pr.isCertificationsSatisfied),
435
+ isEmploymentsCountSatisfied: coerceBoolean(pr.isEmploymentsCountSatisfied),
436
+ isEmploymentConnectionsSatisfied: coerceBoolean(pr.isEmploymentConnectionsSatisfied),
437
+ isSkillValidationsSatisfied: coerceBoolean(pr.isSkillValidationsSatisfied),
438
+ isPortfolioItemsCountSatisfied: coerceBoolean(pr.isPortfolioItemsCountSatisfied),
439
+ isPortfolioItemConnectionsSatisfied: coerceBoolean(pr.isPortfolioItemConnectionsSatisfied),
440
+ isWorkingHoursSatisfied: coerceBoolean(pr.isWorkingHoursSatisfied),
441
+ submitAvailable: coerceBoolean(data.profile.submitAvailable),
442
+ updatedByTalentAt: coerceString(data.profile.updatedByTalentAt),
443
+ };
444
+ }
445
+ const GET_PROFILE_RECOMMENDATIONS_QUERY = `query getProfileRecommendations($profileId: ID!) {
446
+ profile(id: $profileId) {
447
+ id
448
+ recommendations {
449
+ nodes {
450
+ type
451
+ ... on EmploymentsCountRecommendation { minimumCount }
452
+ ... on PortfolioItemsCountRecommendation { minimumCount }
453
+ ... on AdvancedProfileRecommendation { isCustomRequirementsCompleted isTravelInformationCompleted }
454
+ ... on ProfileFreshnessRecommendation {
455
+ skillsStatus
456
+ certificationsStatus
457
+ educationsStatus
458
+ workExperiencesStatus
459
+ portfolioItemsStatus
460
+ }
461
+ }
462
+ }
463
+ }
464
+ }`;
465
+ /**
466
+ * Read the list of profile recommendations. Each recommendation has a
467
+ * discriminator `type` and a small payload of variant-specific fields.
468
+ *
469
+ * Recommendations that involve nested entity lists (e.g.
470
+ * `EmploymentsMissingDataRecommendation` with a `nodes` array of employments)
471
+ * are intentionally trimmed at the GraphQL level — at v0 the CLI/MCP only
472
+ * surfaces the recommendation `type` and any scalar variant fields. Drilling
473
+ * into nested entity lists requires fetching the underlying domain
474
+ * (employments, portfolio items, skills) directly, which is outside the
475
+ * recommendations leaf's scope.
476
+ */
477
+ export async function recommendations(token) {
478
+ const profileId = await extractProfileId(token);
479
+ const res = await withNetworkErrorMapping("Profile recommendations", () => impersonatedTransport({
480
+ surface: "talent-profile",
481
+ authToken: token,
482
+ body: {
483
+ operationName: "getProfileRecommendations",
484
+ query: GET_PROFILE_RECOMMENDATIONS_QUERY,
485
+ variables: { profileId },
486
+ },
487
+ }));
488
+ const data = parseTalentProfileResponse(res, "Profile recommendations");
489
+ if (!data.profile) {
490
+ throw new ProfileError("NO_VIEWER", "Profile recommendations query returned no profile.");
491
+ }
492
+ const nodes = data.profile.recommendations?.nodes ?? [];
493
+ return nodes
494
+ .filter((n) => n !== null && typeof n === "object")
495
+ .map((node) => {
496
+ // Build a clean payload by stripping the discriminator and `__typename`.
497
+ const payload = {};
498
+ for (const [k, v] of Object.entries(node)) {
499
+ if (k === "type" || k === "__typename")
500
+ continue;
501
+ payload[k] = v;
502
+ }
503
+ const type = node.type;
504
+ return {
505
+ type: typeof type === "string" ? type : "Unknown",
506
+ payload,
507
+ };
508
+ });
509
+ }
510
+ const GET_ADVANCED_PROFILE_DATA_QUERY = `query getAdvancedProfileData($profileId: ID!) {
511
+ profile(id: $profileId) {
512
+ id
513
+ advancedProfileWizardStatus
514
+ travelVisas {
515
+ nodes {
516
+ id
517
+ }
518
+ }
519
+ }
520
+ }`;
521
+ /**
522
+ * Read the advanced-profile-wizard status plus a summary of the talent's
523
+ * travel-visa list. This is the read-side combined view of
524
+ * `getAdvancedProfileData` — the spec also references
525
+ * `GetAdvancedProfileWizardStatus` as a separate operation, but
526
+ * `getAdvancedProfileData` already returns `advancedProfileWizardStatus`, so
527
+ * one query is sufficient.
528
+ *
529
+ * The full TravelVisa fragment is intentionally trimmed to `id` only. Visa
530
+ * CRUD operations live in the `visas` sub-domain — surfacing the rich shape
531
+ * here would create a partial duplication that drifts as the visas
532
+ * sub-domain evolves.
533
+ */
534
+ export async function advancedWizardShow(token) {
535
+ const profileId = await extractProfileId(token);
536
+ const res = await withNetworkErrorMapping("Advanced profile wizard show", () => impersonatedTransport({
537
+ surface: "talent-profile",
538
+ authToken: token,
539
+ body: {
540
+ operationName: "getAdvancedProfileData",
541
+ query: GET_ADVANCED_PROFILE_DATA_QUERY,
542
+ variables: { profileId },
543
+ },
544
+ }));
545
+ const data = parseTalentProfileResponse(res, "Advanced profile wizard show");
546
+ if (!data.profile) {
547
+ throw new ProfileError("NO_VIEWER", "Advanced profile data query returned no profile.");
548
+ }
549
+ const visaNodes = data.profile.travelVisas?.nodes ?? [];
550
+ const travelVisaIds = visaNodes
551
+ .filter((n) => n !== null && typeof n === "object")
552
+ .map((n) => (typeof n.id === "string" ? n.id : ""))
553
+ .filter((id) => id.length > 0);
554
+ return {
555
+ wizardStatus: coerceString(data.profile.advancedProfileWizardStatus),
556
+ travelVisaCount: travelVisaIds.length,
557
+ travelVisaIds,
558
+ };
559
+ }
560
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/services/profile/external/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;AAEH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE5E,4EAA4E;AAC5E,iEAAiE;AACjE,4CAA4C;AAC5C,OAAO,EAAE,YAAY,EAAE,CAAC;AAwBxB;;;;;;;;;;;;;GAaG;AACH,SAAS,0BAA0B,CACjC,GAAsB,EACtB,YAAoB,EACpB,oBAAsC,SAAS;IAE/C,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvB,MAAM,IAAI,gBAAgB,CAAC,gCAAgC,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QAC1C,MAAM,IAAI,YAAY,CAAC,iBAAiB,EAAE,GAAG,YAAY,kBAAkB,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAA6C,CAAC;IAC/D,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,IAAI,eAAe,CAAC;QAClD,IAAI,0BAA0B,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,gBAAgB,CAAC,gCAAgC,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,GAAG,YAAY,YAAY,OAAO,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QAChB,MAAM,IAAI,YAAY,CAAC,iBAAiB,EAAE,GAAG,YAAY,iCAAiC,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,uBAAuB,CAAI,YAAoB,EAAE,EAAoB;IAClF,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,UAAU;YAAE,MAAM,GAAG,CAAC;QACzC,IAAI,GAAG,YAAY,YAAY;YAAE,MAAM,GAAG,CAAC;QAC3C,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,GAAG,YAAY,oBAAqB,GAAa,CAAC,OAAO,EAAE,EAAE;YACnG,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AA+CD;;;;;;;;;;GAUG;AACH,MAAM,iCAAiC,GAAG;;;;;;;;;;;;;;;;;;;EAmBxC,CAAC;AA6BH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAa,EAAE,OAA+B;IACzE,MAAM,MAAM,GAAoD,EAAE,CAAC;IACnE,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;QAAE,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IACvE,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACjE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACpE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACpE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACpE,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;QAAE,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IACvE,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,YAAY,CACpB,kBAAkB,EAClB,oGAAoG,CACrG,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEhD,gEAAgE;IAChE,uEAAuE;IACvE,uEAAuE;IACvE,uEAAuE;IACvE,oEAAoE;IACpE,yDAAyD;IACzD,6EAA6E;IAC7E,MAAM,GAAG,GAAG,MAAM,uBAAuB,CAAC,yBAAyB,EAAE,GAAG,EAAE,CACxE,qBAAqB,CAAC;QACpB,OAAO,EAAE,gBAAgB;QACzB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE;YACJ,gFAAgF;YAChF,aAAa,EAAE,wBAAwB;YACvC,KAAK,EAAE,iCAAiC;YACxC,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAwC,EAAE;SACpG;KACF,CAAC,CACH,CAAC;IAEF,MAAM,IAAI,GAAG,0BAA0B,CAAC,GAAG,EAAE,yBAAyB,CAErE,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,CAAC,sBAAsB,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,6EAA6E,CAAC,CAAC;IACnH,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,YAAY,CACpB,YAAY,EACZ,mCAAmC,SAAS,KAAK,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,CACrF,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC9B,MAAM,IAAI,YAAY,CACpB,YAAY,EACZ,iDAAiD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAC/F,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,uEAAuE,CAAC,CAAC;IAC7G,CAAC;IAED,OAAO;QACL,OAAO,EAAE;YACP,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YACtB,iBAAiB,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC;YAClE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI;YAC1C,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI;YACtC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI;YACxC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI;YACxC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI;SAC3C;QACD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;KAC/B,CAAC;AACJ,CAAC;AAsBD,MAAM,6BAA6B,GAAG;;;;;;;;;EASpC,CAAC;AAaH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAAa;IACxD,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAG,MAAM,uBAAuB,CAAC,0BAA0B,EAAE,GAAG,EAAE,CACzE,qBAAqB,CAAC;QACpB,OAAO,EAAE,gBAAgB;QACzB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE;YACJ,aAAa,EAAE,uBAAuB;YACtC,KAAK,EAAE,6BAA6B;YACpC,SAAS,EAAE,EAAE,SAAS,EAAE;SACzB;KACF,CAAC,CACH,CAAC;IAEF,MAAM,IAAI,GAAG,0BAA0B,CAAC,GAAG,EAAE,0BAA0B,CAA8B,CAAC;IACtG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,gDAAgD,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,EAAE,CAAC;IACjD,OAAO;QACL,eAAe,EAAE,aAAa,CAAC,EAAE,CAAC,eAAe,CAAC;QAClD,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC;QACpC,iBAAiB,EAAE,aAAa,CAAC,EAAE,CAAC,iBAAiB,CAAC;KACvD,CAAC;AACJ,CAAC;AAeD,MAAM,mCAAmC,GAAG;;;;;;;;;;;;;;;;;;;EAmB1C,CAAC;AAuCH;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAa,EACb,OAAiC;IAEjC,IACE,OAAO,CAAC,eAAe,KAAK,SAAS;QACrC,OAAO,CAAC,QAAQ,KAAK,SAAS;QAC9B,OAAO,CAAC,iBAAiB,KAAK,SAAS,EACvC,CAAC;QACD,MAAM,IAAI,YAAY,CACpB,kBAAkB,EAClB,iGAAiG,CAClG,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,8DAA8D;IAC9D,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAwD;QAClE,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,eAAe,IAAI,KAAK;QAC5E,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,IAAI,KAAK;QACvD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,IAAI,KAAK;KACnF,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,uBAAuB,CAAC,4BAA4B,EAAE,GAAG,EAAE,CAC3E,qBAAqB,CAAC;QACpB,OAAO,EAAE,gBAAgB;QACzB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE;YACJ,aAAa,EAAE,0BAA0B;YACzC,KAAK,EAAE,mCAAmC;YAC1C,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAA0C,EAAE;SACxG;KACF,CAAC,CACH,CAAC;IAEF,MAAM,IAAI,GAAG,0BAA0B,CAAC,GAAG,EAAE,4BAA4B,CAExE,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,CAAC,wBAAwB,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,0DAA0D,CAAC,CAAC;IAChG,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,YAAY,CACpB,YAAY,EACZ,sCAAsC,SAAS,KAAK,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,CACxF,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC9B,MAAM,IAAI,YAAY,CACpB,YAAY,EACZ,oDAAoD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAClG,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,0EAA0E,CAAC,CAAC;IAChH,CAAC;IACD,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,kBAAkB,IAAI,EAAE,CAAC;IACpD,OAAO;QACL,OAAO,EAAE;YACP,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YACtB,iBAAiB,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC;YAClE,kBAAkB,EAAE;gBAClB,eAAe,EAAE,aAAa,CAAC,EAAE,CAAC,eAAe,CAAC;gBAClD,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC;gBACpC,iBAAiB,EAAE,aAAa,CAAC,EAAE,CAAC,iBAAiB,CAAC;aACvD;SACF;QACD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;KAC/B,CAAC;AACJ,CAAC;AAiCD,MAAM,2BAA2B,GAAG;;;;;;;;;;;;;;;;;EAiBlC,CAAC;AAWH;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAa;IAC3C,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAG,MAAM,uBAAuB,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAClE,qBAAqB,CAAC;QACpB,OAAO,EAAE,gBAAgB;QACzB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE;YACJ,aAAa,EAAE,qBAAqB;YACpC,KAAK,EAAE,2BAA2B;YAClC,SAAS,EAAE,EAAE,SAAS,EAAE;SACzB;KACF,CAAC,CACH,CAAC;IAEF,MAAM,IAAI,GAAG,0BAA0B,CAAC,GAAG,EAAE,mBAAmB,CAA4B,CAAC;IAC7F,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,8CAA8C,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAC/C,OAAO;QACL,0BAA0B,EAAE,aAAa,CAAC,EAAE,CAAC,0BAA0B,CAAC;QACxE,oBAAoB,EAAE,aAAa,CAAC,EAAE,CAAC,oBAAoB,CAAC;QAC5D,yBAAyB,EAAE,aAAa,CAAC,EAAE,CAAC,yBAAyB,CAAC;QACtE,2BAA2B,EAAE,aAAa,CAAC,EAAE,CAAC,2BAA2B,CAAC;QAC1E,gCAAgC,EAAE,aAAa,CAAC,EAAE,CAAC,gCAAgC,CAAC;QACpF,2BAA2B,EAAE,aAAa,CAAC,EAAE,CAAC,2BAA2B,CAAC;QAC1E,8BAA8B,EAAE,aAAa,CAAC,EAAE,CAAC,8BAA8B,CAAC;QAChF,mCAAmC,EAAE,aAAa,CAAC,EAAE,CAAC,mCAAmC,CAAC;QAC1F,uBAAuB,EAAE,aAAa,CAAC,EAAE,CAAC,uBAAuB,CAAC;QAClE,eAAe,EAAE,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC;QAC5D,iBAAiB,EAAE,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC;KAChE,CAAC;AACJ,CAAC;AAsBD,MAAM,iCAAiC,GAAG;;;;;;;;;;;;;;;;;;;EAmBxC,CAAC;AAWH;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAa;IACjD,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAG,MAAM,uBAAuB,CAAC,yBAAyB,EAAE,GAAG,EAAE,CACxE,qBAAqB,CAAC;QACpB,OAAO,EAAE,gBAAgB;QACzB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE;YACJ,aAAa,EAAE,2BAA2B;YAC1C,KAAK,EAAE,iCAAiC;YACxC,SAAS,EAAE,EAAE,SAAS,EAAE;SACzB;KACF,CAAC,CACH,CAAC;IAEF,MAAM,IAAI,GAAG,0BAA0B,CAAC,GAAG,EAAE,yBAAyB,CAAkC,CAAC;IACzG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,oDAAoD,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC;IACxD,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,CAAC,EAAgC,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC;SAChF,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,yEAAyE;QACzE,MAAM,OAAO,GAA4B,EAAE,CAAC;QAC5C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,YAAY;gBAAE,SAAS;YACjD,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,OAAO;YACL,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YACjD,OAAO;SACR,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC;AA0BD,MAAM,+BAA+B,GAAG;;;;;;;;;;EAUtC,CAAC;AAYH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAa;IACpD,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAG,MAAM,uBAAuB,CAAC,8BAA8B,EAAE,GAAG,EAAE,CAC7E,qBAAqB,CAAC;QACpB,OAAO,EAAE,gBAAgB;QACzB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE;YACJ,aAAa,EAAE,wBAAwB;YACvC,KAAK,EAAE,+BAA+B;YACtC,SAAS,EAAE,EAAE,SAAS,EAAE;SACzB;KACF,CAAC,CACH,CAAC;IAEF,MAAM,IAAI,GAAG,0BAA0B,CAAC,GAAG,EAAE,8BAA8B,CAA+B,CAAC;IAC3G,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,kDAAkD,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC;IACxD,MAAM,aAAa,GAAG,SAAS;SAC5B,MAAM,CAAC,CAAC,CAAC,EAAyB,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC;SACzE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAClD,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACjC,OAAO;QACL,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,2BAA2B,CAAC;QACpE,eAAe,EAAE,aAAa,CAAC,MAAM;QACrC,aAAa;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `profile` services-tree facade. The 11 sub-domains follow the v0 epic
3
+ * cartography (#68): basic, skills, industries, education, certifications,
4
+ * employment, portfolio, visas, resume, external, reviews. Each is exposed
5
+ * as a namespace on this module so consumers write
6
+ * `profile.basic.show(...)`, `profile.skills.add(...)`, etc.
7
+ *
8
+ * Only `basic` carries operations today (`show`, `set`, plus the shared
9
+ * `ProfileError`/`ProfileUpdate`/`UpdateProfileResult` types). The other
10
+ * 10 sub-domains are placeholder modules that land actual operations in
11
+ * the follow-up issues (#73-#76).
12
+ */
13
+ export * as basic from "./basic/index.js";
14
+ export * as skills from "./skills/index.js";
15
+ export * as industries from "./industries/index.js";
16
+ export * as education from "./education/index.js";
17
+ export * as certifications from "./certifications/index.js";
18
+ export * as employment from "./employment/index.js";
19
+ export * as portfolio from "./portfolio/index.js";
20
+ export * as visas from "./visas/index.js";
21
+ export * as resume from "./resume/index.js";
22
+ export * as external from "./external/index.js";
23
+ export * as reviews from "./reviews/index.js";
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/profile/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,cAAc,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (C) 2026 Oleksii PELYKH
3
+ /**
4
+ * `profile` services-tree facade. The 11 sub-domains follow the v0 epic
5
+ * cartography (#68): basic, skills, industries, education, certifications,
6
+ * employment, portfolio, visas, resume, external, reviews. Each is exposed
7
+ * as a namespace on this module so consumers write
8
+ * `profile.basic.show(...)`, `profile.skills.add(...)`, etc.
9
+ *
10
+ * Only `basic` carries operations today (`show`, `set`, plus the shared
11
+ * `ProfileError`/`ProfileUpdate`/`UpdateProfileResult` types). The other
12
+ * 10 sub-domains are placeholder modules that land actual operations in
13
+ * the follow-up issues (#73-#76).
14
+ */
15
+ export * as basic from "./basic/index.js";
16
+ export * as skills from "./skills/index.js";
17
+ export * as industries from "./industries/index.js";
18
+ export * as education from "./education/index.js";
19
+ export * as certifications from "./certifications/index.js";
20
+ export * as employment from "./employment/index.js";
21
+ export * as portfolio from "./portfolio/index.js";
22
+ export * as visas from "./visas/index.js";
23
+ export * as resume from "./resume/index.js";
24
+ export * as external from "./external/index.js";
25
+ export * as reviews from "./reviews/index.js";
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/profile/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,cAAc,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC"}