@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,636 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
/**
|
|
4
|
+
* `payments` service module — read payouts, list configured payment
|
|
5
|
+
* methods, inspect the talent's current rate, and submit rate-change
|
|
6
|
+
* requests on engagements.
|
|
7
|
+
*
|
|
8
|
+
* In Toptal vocabulary, "Payments" is the talent's earnings surface:
|
|
9
|
+
* - **Payouts** — historical `TalentPayment` events (billing-cycle
|
|
10
|
+
* paid amounts, memorandums, status — DUE / PAID / DISPUTED / etc.)
|
|
11
|
+
* - **Methods** — `PaymentOption` records (Payoneer / direct deposit /
|
|
12
|
+
* etc.) the talent has configured.
|
|
13
|
+
* - **Rate** — the talent's hourly rate as defaulted on
|
|
14
|
+
* `viewerRole.hourlyRate` (the "rack rate" used for future
|
|
15
|
+
* engagements). Per-engagement rates live on
|
|
16
|
+
* `engagement.currentAgreement.talentRate` (already surfaced by the
|
|
17
|
+
* `engagements` service). A talent can request a rate change via
|
|
18
|
+
* `CreateRateChangeRequest`; the most recent / ongoing request is
|
|
19
|
+
* readable via `viewer.lastRateChangeRequest` /
|
|
20
|
+
* `viewer.ongoingRateChangeRequest`.
|
|
21
|
+
*
|
|
22
|
+
* | Leaf | Operation(s) |
|
|
23
|
+
* |-----------------------------------|---------------------------------------|
|
|
24
|
+
* | `payouts.list` | `Payments(filters: PaymentFilter)` |
|
|
25
|
+
* | `payouts.show` | `Payment(id: ID!)` (Relay `node`) |
|
|
26
|
+
* | `methods.list` | `PaymentOptions` (hand-authored) |
|
|
27
|
+
* | `methods.show` | `methods.list` + client-side filter |
|
|
28
|
+
* | `rate.show` | `LastRateChangeRequest` + `RateChangeFormDetails` |
|
|
29
|
+
* | `rate.questions` | `RateChangeRequestQuestions` |
|
|
30
|
+
* | `rate.change` | `CreateRateChangeRequest(input)` |
|
|
31
|
+
*
|
|
32
|
+
* **Routing**: All ops talk to the **mobile-gateway** surface
|
|
33
|
+
* (`https://www.toptal.com/gateway/graphql/talent/graphql`) via
|
|
34
|
+
* `stockTransport`. Plain HTTPS — no Cloudflare, no TLS impersonation
|
|
35
|
+
* needed. Same surface as `engagements`, `jobs`, `applications`.
|
|
36
|
+
*
|
|
37
|
+
* **Operations are inlined as strings** (NOT codegen-driven). Every
|
|
38
|
+
* payment-domain operation is in `GATEWAY_{MOBILE,PORTAL}_KNOWN_UNTRUSTED_OPS`
|
|
39
|
+
* per `codegen.config.ts` — the SDL synthesizer has `Unknown` placeholders
|
|
40
|
+
* for `PaymentFilter.{kind,status,…}` and the `engagement: Unknown` field
|
|
41
|
+
* on `RateChangeRequest`, so generated types do not exist. Captured
|
|
42
|
+
* operation documents live in:
|
|
43
|
+
* - `../research/graphql/gateway/operations/mobile/Payments.graphql`
|
|
44
|
+
* - `../research/graphql/gateway/operations/mobile/Payment.graphql`
|
|
45
|
+
* - `../research/graphql/gateway/operations/mobile/LastRateChangeRequest.graphql`
|
|
46
|
+
* - `../research/graphql/gateway/operations/mobile/RateChangeRequestQuestions.graphql`
|
|
47
|
+
* - `../research/graphql/gateway/operations/mobile/RateChangeFormDetails.graphql`
|
|
48
|
+
* - `../research/graphql/gateway/operations/mobile/CreateRateChangeRequest.graphql`
|
|
49
|
+
* - `PaymentOptions` is hand-authored (the captured portal op
|
|
50
|
+
* `GetTalentPaymentOptions` doesn't have a mobile sibling; this
|
|
51
|
+
* service uses a minimal projection compatible with the mobile-gateway
|
|
52
|
+
* surface; verified-via-E2E).
|
|
53
|
+
*
|
|
54
|
+
* **CLAUDE.md schema/contract validation rule**: Every operation in
|
|
55
|
+
* this module is **[INFERRED — UNVERIFIED]** until its gated
|
|
56
|
+
* `*.e2e.test.ts` file passes against a live session. The mutation
|
|
57
|
+
* (`rate.change`) is the highest-stakes trigger; ALL operations need
|
|
58
|
+
* E2E coverage before merge per `scripts/check-e2e-coverage.ts`.
|
|
59
|
+
*
|
|
60
|
+
* **Rate-change semantics**:
|
|
61
|
+
* - `requestType: CURRENT_ENGAGEMENT` — rate change for ONE existing
|
|
62
|
+
* engagement; requires `engagementId`.
|
|
63
|
+
* - `requestType: FUTURE_ENGAGEMENTS` — change the talent's default
|
|
64
|
+
* "rack rate" applied to NEW engagement applications. Does NOT
|
|
65
|
+
* affect any active engagements.
|
|
66
|
+
* - `requestType: CONSULTATION` — rate change for the consultation
|
|
67
|
+
* surface (separate from engagement work). The talent's role must
|
|
68
|
+
* support consultations; rejection by the server surfaces as
|
|
69
|
+
* `MUTATION_ERROR` here.
|
|
70
|
+
*
|
|
71
|
+
* **Out of scope for v1** (deferred to follow-ups):
|
|
72
|
+
* - Payment-method mutations (create / update / remove /
|
|
73
|
+
* mark-as-preferred) — explicitly excluded per issue #149's
|
|
74
|
+
* out-of-scope list.
|
|
75
|
+
* - Withdrawal request initiation — Toptal admin-side flow.
|
|
76
|
+
* - Tax document generation / download — post-v1.
|
|
77
|
+
* - Cross-engagement payment aggregation beyond what the API
|
|
78
|
+
* surfaces.
|
|
79
|
+
*/
|
|
80
|
+
import { z } from "zod";
|
|
81
|
+
import { VerticalGlobalMarketConditionSchema, VerticalMarketConditionSchema } from "../../__generated__/zod-schemas.js";
|
|
82
|
+
import { buildDryRunPreview } from "../../transport.js";
|
|
83
|
+
import { callGatewayShared } from "../_shared/transport.js";
|
|
84
|
+
export class PaymentsError extends Error {
|
|
85
|
+
code;
|
|
86
|
+
name = "PaymentsError";
|
|
87
|
+
constructor(code, message, options) {
|
|
88
|
+
super(message, options);
|
|
89
|
+
this.code = code;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// ---------------------------------------------------------------------
|
|
93
|
+
// Public types — rate namespace
|
|
94
|
+
// ---------------------------------------------------------------------
|
|
95
|
+
/**
|
|
96
|
+
* Three flavors of rate-change request, mapped to the wire enum
|
|
97
|
+
* `RateChangeRequestTypeEnum`.
|
|
98
|
+
*/
|
|
99
|
+
export const RATE_CHANGE_KINDS = ["current-engagement", "future-engagements", "consultation"];
|
|
100
|
+
const RATE_CHANGE_KIND_TO_WIRE = {
|
|
101
|
+
"current-engagement": "CURRENT_ENGAGEMENT",
|
|
102
|
+
"future-engagements": "FUTURE_ENGAGEMENTS",
|
|
103
|
+
consultation: "CONSULTATION",
|
|
104
|
+
};
|
|
105
|
+
const RATE_CHANGE_STATUS_VERBOSE = {
|
|
106
|
+
PENDING: "Pending",
|
|
107
|
+
CLAIMED: "Claimed",
|
|
108
|
+
COMPLETED: "Completed",
|
|
109
|
+
};
|
|
110
|
+
// ---------------------------------------------------------------------
|
|
111
|
+
// GraphQL operation strings — verbatim from captured documents where
|
|
112
|
+
// possible. Hand-authored ops carry a doc-string note.
|
|
113
|
+
// ---------------------------------------------------------------------
|
|
114
|
+
// Verbatim from `../research/graphql/gateway/operations/mobile/Payments.graphql`.
|
|
115
|
+
const PAYMENTS_QUERY = `query Payments($filters: PaymentFilter) { viewer { __typename id payments(offsetPagination: { offset: 0 limit: 20 } , filters: $filters) { __typename ...paymentsData } } } fragment paymentFields on TalentPayment { __typename amount correctionAmount billingCycle { __typename id endDate startDate } description job { __typename id title client { __typename id fullName } } memorandums { __typename nodes { __typename amount balance downloadPdfUrl effectiveDate id } } kindCategory paymentGroupId createdAt updatedAt downloadPdfUrl dueDate paidAt id number status } fragment paymentsData on PaymentsConnection { __typename ids nodes { __typename ...paymentFields } summary { __typename totalDisputed totalDue totalOnHold totalOutstanding totalOverdue totalPaid } }`;
|
|
116
|
+
// Verbatim from `../research/graphql/gateway/operations/mobile/Payment.graphql`.
|
|
117
|
+
const PAYMENT_QUERY = `query Payment($id: ID!) { node(id: $id) { __typename ... on TalentPayment { ...paymentFields } } } fragment paymentFields on TalentPayment { __typename amount correctionAmount billingCycle { __typename id endDate startDate } description job { __typename id title client { __typename id fullName } } memorandums { __typename nodes { __typename amount balance downloadPdfUrl effectiveDate id } } kindCategory paymentGroupId createdAt updatedAt downloadPdfUrl dueDate paidAt id number status }`;
|
|
118
|
+
// Hand-authored — no mobile-side `PaymentOptions` operation exists in
|
|
119
|
+
// the research repo. Minimal projection covering what the v1 CLI / MCP
|
|
120
|
+
// surface needs. Live-validated via E2E (`32-payments-methods.e2e.test.ts`).
|
|
121
|
+
//
|
|
122
|
+
// Per CLAUDE.md § Schema/contract validation rule, this operation is
|
|
123
|
+
// hand-authored → mandatory live E2E coverage. The `paymentOptions`
|
|
124
|
+
// field on `Viewer` exists in the synthesized SDL via portal capture;
|
|
125
|
+
// the empirical question is whether the mobile-gateway endpoint serves
|
|
126
|
+
// it (the assumption is yes since portal + mobile share the same
|
|
127
|
+
// backend per `08-portal-api.md`).
|
|
128
|
+
const PAYMENT_OPTIONS_QUERY = `query PaymentOptions { viewer { __typename id paymentOptions { __typename id paymentMethod preferredOption fullName payoneerId comment toptalPaymentsPending } } }`;
|
|
129
|
+
// Verbatim from `../research/graphql/gateway/operations/mobile/LastRateChangeRequest.graphql`.
|
|
130
|
+
const LAST_RATE_CHANGE_REQUEST_QUERY = `query LastRateChangeRequest { viewer { __typename id ...lastRateChangeRequestData } } fragment rateInsightForCommitmentData on TalentRateInsightForCommitment { __typename currentRateCompetitive recentApplicationRate recommendedRate } fragment profileRatesData on ViewerRole { __typename rates { __typename hourly } rateInsight { __typename hourly { __typename ...rateInsightForCommitmentData } } } fragment lastRateChangeRequestData on Viewer { __typename id lastRateChangeRequest { __typename id createdAt desiredRate engagement { __typename id job { __typename id title client { __typename id fullName } } currentAgreement { __typename commitment { __typename slug } } } outcomeRate requestType status talentComment } viewerRole { __typename ...profileRatesData } }`;
|
|
131
|
+
// Verbatim from `../research/graphql/gateway/operations/mobile/RateChangeFormDetails.graphql`.
|
|
132
|
+
const RATE_CHANGE_FORM_DETAILS_QUERY = `query RateChangeFormDetails { viewer { __typename id ...marketConditionData viewerRole { __typename ...profileRatesData } } platformConfiguration { __typename ...rateValidationRulesData } } fragment marketConditionData on Viewer { __typename viewerRole { __typename vertical { __typename name marketCondition { __typename condition } globalMarketCondition { __typename condition conditionColor conditionVerbose reportUrl } } } } fragment rateInsightForCommitmentData on TalentRateInsightForCommitment { __typename currentRateCompetitive recentApplicationRate recommendedRate } fragment profileRatesData on ViewerRole { __typename rates { __typename hourly } rateInsight { __typename hourly { __typename ...rateInsightForCommitmentData } } } fragment talentRateValidationRuleData on TalentRateValidationRule { __typename minRate rateStep } fragment rateValidationRulesData on PlatformConfiguration { __typename id rateValidationRules { __typename hourly { __typename ...talentRateValidationRuleData } } }`;
|
|
133
|
+
// Verbatim from `../research/graphql/gateway/operations/mobile/RateChangeRequestQuestions.graphql`.
|
|
134
|
+
const RATE_CHANGE_QUESTIONS_QUERY = `query RateChangeRequestQuestions { viewer { id rateChangeRequestQuestions { id ...RateChangeRequestQuestion } } } fragment RateChangeRequestQuestion on RateChangeRequestQuestion { id kind label options { commentRequired label } }`;
|
|
135
|
+
// Verbatim from `../research/graphql/gateway/operations/mobile/CreateRateChangeRequest.graphql`.
|
|
136
|
+
const CREATE_RATE_CHANGE_REQUEST_MUTATION = `mutation CreateRateChangeRequest($desiredRate: BigDecimal, $engagementId: ID, $requestType: RateChangeRequestTypeEnum!, $talentComment: String, $answers: [RateChangeRequestAnswerInput!]!) { viewerRole { __typename createRateChangeRequest(input: { answers: $answers desiredRate: $desiredRate engagementId: $engagementId requestType: $requestType talentComment: $talentComment } ) { __typename ...mutationResultFields notice viewer { __typename id ...lastRateChangeRequestData } } } } fragment mutationResultFields on MutationResult { __typename errors { __typename key message code } success } fragment rateInsightForCommitmentData on TalentRateInsightForCommitment { __typename currentRateCompetitive recentApplicationRate recommendedRate } fragment profileRatesData on ViewerRole { __typename rates { __typename hourly } rateInsight { __typename hourly { __typename ...rateInsightForCommitmentData } } } fragment lastRateChangeRequestData on Viewer { __typename id lastRateChangeRequest { __typename id createdAt desiredRate engagement { __typename id job { __typename id title client { __typename id fullName } } currentAgreement { __typename commitment { __typename slug } } } outcomeRate requestType status talentComment } viewerRole { __typename ...profileRatesData } }`;
|
|
137
|
+
/**
|
|
138
|
+
* Z-4 (#288) beachhead schema — first production wire-up of the
|
|
139
|
+
* runtime-validation seam built in Z-3 (#286). Validates the
|
|
140
|
+
* `RateChangeFormDetails` mobile-gateway response against the
|
|
141
|
+
* structural shape `rate.show()` depends on.
|
|
142
|
+
*
|
|
143
|
+
* Beachhead choice rationale:
|
|
144
|
+
* - `RateChangeFormDetails` is the SOLE existing `callGateway` site
|
|
145
|
+
* in the codebase using a TRUSTED operation (i.e., NOT in
|
|
146
|
+
* `GATEWAY_{MOBILE,PORTAL}_KNOWN_UNTRUSTED_OPS` per
|
|
147
|
+
* `codegen.config.ts`). The codegen emits a
|
|
148
|
+
* `RateChangeFormDetailsQuery` type in `gateway.ts`, confirming
|
|
149
|
+
* the operation passes SDL validation end-to-end.
|
|
150
|
+
* - The query text in `RATE_CHANGE_FORM_DETAILS_QUERY` above is
|
|
151
|
+
* verbatim from `../research/graphql/gateway/operations/mobile/
|
|
152
|
+
* RateChangeFormDetails.graphql`, so the wire response is exactly
|
|
153
|
+
* what the SDL declares.
|
|
154
|
+
*
|
|
155
|
+
* Generated zod sub-schemas used directly:
|
|
156
|
+
* - {@link VerticalMarketConditionSchema} — the wire's
|
|
157
|
+
* `viewerRole.vertical.marketCondition` selection (`{ condition }`)
|
|
158
|
+
* matches the SDL type `VerticalMarketCondition` exactly. No
|
|
159
|
+
* `__typename` mismatch risk for the inner type because the
|
|
160
|
+
* selection includes `__typename` per the verbatim query.
|
|
161
|
+
* - {@link VerticalGlobalMarketConditionSchema} — the wire's
|
|
162
|
+
* `viewerRole.vertical.globalMarketCondition` selection
|
|
163
|
+
* (`{ condition, conditionColor, conditionVerbose, reportUrl }`)
|
|
164
|
+
* matches the SDL type `VerticalGlobalMarketCondition` exactly
|
|
165
|
+
* (4 string fields).
|
|
166
|
+
*
|
|
167
|
+
* Inline (NOT-from-codegen) sub-schemas used elsewhere:
|
|
168
|
+
* - `viewer` / `viewerRole` / `vertical` / `platformConfiguration`
|
|
169
|
+
* envelopes — partial selections of larger SDL types; the
|
|
170
|
+
* auto-generated `ViewerSchema` etc. require every SDL-declared
|
|
171
|
+
* field, which the operation does not select. An inline shape
|
|
172
|
+
* matches the actual selection set.
|
|
173
|
+
* - `rates`, `rateInsight.hourly`, and
|
|
174
|
+
* `platformConfiguration.rateValidationRules.hourly` — the SDL
|
|
175
|
+
* declares `TalentRate.hourly: String!` (non-null),
|
|
176
|
+
* `TalentRateInsightForCommitment.currentRateCompetitive: Boolean!`
|
|
177
|
+
* (boolean), and `TalentRateValidationRule.rateStep: Int!`
|
|
178
|
+
* (number). The hand-rolled service-layer types
|
|
179
|
+
* (`WireViewerRoleRates`, `WireRateInsightForCommitment`,
|
|
180
|
+
* `WireTalentRateValidationRule`) declare `hourly` as
|
|
181
|
+
* `string | null` (defensive null tolerance) and now declare
|
|
182
|
+
* `currentRateCompetitive` as `boolean | null` and `rateStep` as
|
|
183
|
+
* `number | null` (SDL-aligned per #319 — pre-#319 they were
|
|
184
|
+
* widened to `string | null`, the T2 Zod validator caught the
|
|
185
|
+
* drift on the live wire on 2026-05-15).
|
|
186
|
+
*
|
|
187
|
+
* Schema/contract rule disposition: NOT triggered. The wire shape
|
|
188
|
+
* being validated is the SAME shape the hand-rolled types now
|
|
189
|
+
* encode; the schema is a structural mirror. Issue #319 reconciled
|
|
190
|
+
* the `currentRateCompetitive` / `rateStep` types with the SDL truth
|
|
191
|
+
* and the live wire (post-Z-4 beachhead follow-up).
|
|
192
|
+
*
|
|
193
|
+
* Vertical is `.optional()` because the existing in-tree unit
|
|
194
|
+
* fixtures for `rate.show` don't carry it (the hand-rolled
|
|
195
|
+
* `WireViewerRole` doesn't declare `vertical` either). The live wire
|
|
196
|
+
* does include it per the verbatim query selection — `.optional()`
|
|
197
|
+
* keeps the schema compatible with both shapes.
|
|
198
|
+
*/
|
|
199
|
+
const RATE_CHANGE_FORM_DETAILS_RESPONSE_SCHEMA = z.object({
|
|
200
|
+
viewer: z
|
|
201
|
+
.object({
|
|
202
|
+
id: z.string(),
|
|
203
|
+
viewerRole: z
|
|
204
|
+
.object({
|
|
205
|
+
vertical: z
|
|
206
|
+
.object({
|
|
207
|
+
name: z.string(),
|
|
208
|
+
marketCondition: VerticalMarketConditionSchema(),
|
|
209
|
+
globalMarketCondition: VerticalGlobalMarketConditionSchema(),
|
|
210
|
+
})
|
|
211
|
+
.optional(),
|
|
212
|
+
rates: z
|
|
213
|
+
.object({
|
|
214
|
+
hourly: z.string().nullable(),
|
|
215
|
+
})
|
|
216
|
+
.nullable(),
|
|
217
|
+
rateInsight: z
|
|
218
|
+
.object({
|
|
219
|
+
hourly: z
|
|
220
|
+
.object({
|
|
221
|
+
// `Boolean!` per SDL; live wire returns JSON boolean (#319).
|
|
222
|
+
currentRateCompetitive: z.boolean().nullable(),
|
|
223
|
+
recentApplicationRate: z.string().nullable(),
|
|
224
|
+
recommendedRate: z.string().nullable(),
|
|
225
|
+
})
|
|
226
|
+
.nullable(),
|
|
227
|
+
})
|
|
228
|
+
.nullable(),
|
|
229
|
+
})
|
|
230
|
+
.nullable(),
|
|
231
|
+
})
|
|
232
|
+
.nullable(),
|
|
233
|
+
platformConfiguration: z
|
|
234
|
+
.object({
|
|
235
|
+
id: z.string(),
|
|
236
|
+
rateValidationRules: z
|
|
237
|
+
.object({
|
|
238
|
+
hourly: z
|
|
239
|
+
.object({
|
|
240
|
+
minRate: z.string().nullable(),
|
|
241
|
+
// `Int!` per SDL; live wire returns JSON number (#319).
|
|
242
|
+
rateStep: z.number().nullable(),
|
|
243
|
+
})
|
|
244
|
+
.nullable(),
|
|
245
|
+
})
|
|
246
|
+
.nullable(),
|
|
247
|
+
})
|
|
248
|
+
.nullable(),
|
|
249
|
+
});
|
|
250
|
+
// Wire pattern: bad Relay ID returns `Node id "<id>" resolves to ...`
|
|
251
|
+
// per memory `project_toptal_wire_quirks.md`. Used by `payouts.show()`
|
|
252
|
+
// to remap the wire-level decode error to a typed NOT_FOUND.
|
|
253
|
+
const NODE_NOT_FOUND_PATTERN = /Node id .* resolves to/i;
|
|
254
|
+
// ---------------------------------------------------------------------
|
|
255
|
+
// Transport helper (mirrors the engagements/applications pattern)
|
|
256
|
+
// ---------------------------------------------------------------------
|
|
257
|
+
/**
|
|
258
|
+
* Thin per-service wrapper around {@link callGatewayShared} (issue
|
|
259
|
+
* #329). Pins the mobile-gateway surface and the {@link PaymentsError}
|
|
260
|
+
* domain class.
|
|
261
|
+
*/
|
|
262
|
+
async function callGateway(token, operationName, query, variables, schema) {
|
|
263
|
+
return callGatewayShared("mobile-gateway", token, operationName, query, variables, PaymentsError, {
|
|
264
|
+
schema,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function formatMutationErrors(prefix, errors) {
|
|
268
|
+
if (errors == null || errors.length === 0) {
|
|
269
|
+
return `${prefix}: no error detail returned.`;
|
|
270
|
+
}
|
|
271
|
+
const parts = errors.map((e) => {
|
|
272
|
+
const fields = [];
|
|
273
|
+
if (e.code != null)
|
|
274
|
+
fields.push(`code=${e.code}`);
|
|
275
|
+
if (e.key != null)
|
|
276
|
+
fields.push(`key=${e.key}`);
|
|
277
|
+
const head = fields.length > 0 ? `[${fields.join(", ")}] ` : "";
|
|
278
|
+
return `${head}${e.message ?? "(no message)"}`;
|
|
279
|
+
});
|
|
280
|
+
return `${prefix}: ${parts.join("; ")}`;
|
|
281
|
+
}
|
|
282
|
+
// ---------------------------------------------------------------------
|
|
283
|
+
// Projections
|
|
284
|
+
// ---------------------------------------------------------------------
|
|
285
|
+
function emptyPayoutsSummary() {
|
|
286
|
+
return {
|
|
287
|
+
totalDisputed: "0",
|
|
288
|
+
totalDue: "0",
|
|
289
|
+
totalOnHold: "0",
|
|
290
|
+
totalOutstanding: "0",
|
|
291
|
+
totalOverdue: "0",
|
|
292
|
+
totalPaid: "0",
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function projectMemorandum(wire) {
|
|
296
|
+
return {
|
|
297
|
+
id: wire.id,
|
|
298
|
+
amount: wire.amount,
|
|
299
|
+
balance: wire.balance,
|
|
300
|
+
downloadPdfUrl: wire.downloadPdfUrl,
|
|
301
|
+
effectiveDate: wire.effectiveDate,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function projectPayout(wire) {
|
|
305
|
+
const memos = (wire.memorandums?.nodes ?? []).filter((m) => m !== null);
|
|
306
|
+
return {
|
|
307
|
+
id: wire.id,
|
|
308
|
+
number: wire.number,
|
|
309
|
+
amount: wire.amount,
|
|
310
|
+
correctionAmount: wire.correctionAmount,
|
|
311
|
+
description: wire.description,
|
|
312
|
+
status: wire.status,
|
|
313
|
+
kindCategory: wire.kindCategory,
|
|
314
|
+
paymentGroupId: wire.paymentGroupId,
|
|
315
|
+
billingCycle: wire.billingCycle,
|
|
316
|
+
dueDate: wire.dueDate,
|
|
317
|
+
paidAt: wire.paidAt,
|
|
318
|
+
createdAt: wire.createdAt,
|
|
319
|
+
updatedAt: wire.updatedAt,
|
|
320
|
+
downloadPdfUrl: wire.downloadPdfUrl,
|
|
321
|
+
job: wire.job,
|
|
322
|
+
memorandums: memos.map(projectMemorandum),
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function projectPaymentMethod(wire) {
|
|
326
|
+
return {
|
|
327
|
+
id: wire.id,
|
|
328
|
+
paymentMethod: wire.paymentMethod,
|
|
329
|
+
preferredOption: wire.preferredOption,
|
|
330
|
+
fullName: wire.fullName,
|
|
331
|
+
payoneerId: wire.payoneerId,
|
|
332
|
+
comment: wire.comment,
|
|
333
|
+
toptalPaymentsPending: wire.toptalPaymentsPending,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function projectRateChangeRequest(wire) {
|
|
337
|
+
const job = wire.engagement?.job ?? null;
|
|
338
|
+
return {
|
|
339
|
+
id: wire.id,
|
|
340
|
+
createdAt: wire.createdAt,
|
|
341
|
+
desiredRate: wire.desiredRate,
|
|
342
|
+
outcomeRate: wire.outcomeRate,
|
|
343
|
+
requestType: wire.requestType,
|
|
344
|
+
status: wire.status,
|
|
345
|
+
statusVerbose: RATE_CHANGE_STATUS_VERBOSE[wire.status] ?? wire.status,
|
|
346
|
+
talentComment: wire.talentComment,
|
|
347
|
+
engagementId: wire.engagement?.id ?? null,
|
|
348
|
+
engagementTitle: job?.title ?? null,
|
|
349
|
+
clientName: job?.client?.fullName ?? null,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function projectRateQuestion(wire) {
|
|
353
|
+
const opts = (wire.options ?? []).filter((o) => o !== null);
|
|
354
|
+
return {
|
|
355
|
+
id: wire.id,
|
|
356
|
+
kind: wire.kind,
|
|
357
|
+
label: wire.label,
|
|
358
|
+
options: opts.map((o) => ({ label: o.label, commentRequired: o.commentRequired })),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
// ---------------------------------------------------------------------
|
|
362
|
+
// Payouts namespace
|
|
363
|
+
// ---------------------------------------------------------------------
|
|
364
|
+
/**
|
|
365
|
+
* Payouts — historical `TalentPayment` events. Read-only in v1.
|
|
366
|
+
*/
|
|
367
|
+
export const payouts = {
|
|
368
|
+
/**
|
|
369
|
+
* List historical payouts. Default pagination is the captured wire
|
|
370
|
+
* shape: `offset: 0 limit: 20` (hardcoded in the operation). The
|
|
371
|
+
* server returns the most recent 20 paid/due payouts by default;
|
|
372
|
+
* date filtering narrows the window.
|
|
373
|
+
*
|
|
374
|
+
* Filter map: `fromDate` / `toDate` flow into the wire's
|
|
375
|
+
* `filters.createdOn` field, which expects an inclusive-on-both-ends
|
|
376
|
+
* `DateFilter` shape `{from?: Date, to?: Date}`. Empty filter object
|
|
377
|
+
* (`opts === {}`) sends `filters: null` per Toptal convention.
|
|
378
|
+
*
|
|
379
|
+
* Returns an array of {@link Payout} rows AND the server-provided
|
|
380
|
+
* {@link PayoutsSummary} aggregates for the same filter window —
|
|
381
|
+
* surfacing both lets the CLI render a summary line above the table
|
|
382
|
+
* without a second round-trip.
|
|
383
|
+
*/
|
|
384
|
+
async list(token, opts = {}) {
|
|
385
|
+
const hasFilter = opts.fromDate !== undefined || opts.toDate !== undefined;
|
|
386
|
+
const variables = {
|
|
387
|
+
filters: hasFilter ? { createdOn: { from: opts.fromDate ?? null, to: opts.toDate ?? null } } : null,
|
|
388
|
+
};
|
|
389
|
+
const data = await callGateway(token, "Payments", PAYMENTS_QUERY, variables);
|
|
390
|
+
if (data.viewer === null) {
|
|
391
|
+
throw new PaymentsError("NO_VIEWER", "Session is valid but no viewer is bound to it.");
|
|
392
|
+
}
|
|
393
|
+
if (data.viewer.payments === null) {
|
|
394
|
+
return { items: [], summary: emptyPayoutsSummary() };
|
|
395
|
+
}
|
|
396
|
+
const nodes = (data.viewer.payments.nodes ?? []).filter((n) => n !== null);
|
|
397
|
+
return {
|
|
398
|
+
items: nodes.map(projectPayout),
|
|
399
|
+
summary: data.viewer.payments.summary ?? emptyPayoutsSummary(),
|
|
400
|
+
};
|
|
401
|
+
},
|
|
402
|
+
/**
|
|
403
|
+
* Fetch a single payout's detail by `TalentPayment.id`.
|
|
404
|
+
*
|
|
405
|
+
* Throws `PaymentsError("NOT_FOUND")` when the id doesn't resolve
|
|
406
|
+
* (two wire shapes both fold here: the Relay `node` returning `null`,
|
|
407
|
+
* AND the gateway returning a `Node id "<id>" resolves to ...` decode
|
|
408
|
+
* error in `errors[]`).
|
|
409
|
+
*/
|
|
410
|
+
async show(token, id) {
|
|
411
|
+
let data;
|
|
412
|
+
try {
|
|
413
|
+
data = await callGateway(token, "Payment", PAYMENT_QUERY, { id });
|
|
414
|
+
}
|
|
415
|
+
catch (err) {
|
|
416
|
+
if (err instanceof PaymentsError && err.code === "GRAPHQL_ERROR" && NODE_NOT_FOUND_PATTERN.test(err.message)) {
|
|
417
|
+
throw new PaymentsError("NOT_FOUND", `No payout found with id "${id}" (or you don't have access to it).`, {
|
|
418
|
+
cause: err,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
throw err;
|
|
422
|
+
}
|
|
423
|
+
if (data.node === null) {
|
|
424
|
+
throw new PaymentsError("NOT_FOUND", `No payout found with id "${id}" (or you don't have access to it).`);
|
|
425
|
+
}
|
|
426
|
+
return projectPayout(data.node);
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
// ---------------------------------------------------------------------
|
|
430
|
+
// Methods namespace
|
|
431
|
+
// ---------------------------------------------------------------------
|
|
432
|
+
/**
|
|
433
|
+
* Payment methods — `PaymentOption` records configured by the talent.
|
|
434
|
+
* Read-only in v1; mutations (create / update / mark-as-preferred /
|
|
435
|
+
* remove) are explicitly out of scope per #149.
|
|
436
|
+
*/
|
|
437
|
+
export const methods = {
|
|
438
|
+
/**
|
|
439
|
+
* List configured payment methods. No filter args on the wire — the
|
|
440
|
+
* full list is small (typically 1-3 entries).
|
|
441
|
+
*
|
|
442
|
+
* `preferredOption: true` marks the active method; the CLI / MCP
|
|
443
|
+
* surface annotates this in the rendered output.
|
|
444
|
+
*/
|
|
445
|
+
async list(token) {
|
|
446
|
+
const data = await callGateway(token, "PaymentOptions", PAYMENT_OPTIONS_QUERY, {});
|
|
447
|
+
if (data.viewer === null) {
|
|
448
|
+
throw new PaymentsError("NO_VIEWER", "Session is valid but no viewer is bound to it.");
|
|
449
|
+
}
|
|
450
|
+
const wires = (data.viewer.paymentOptions ?? []).filter((p) => p !== null);
|
|
451
|
+
return wires.map(projectPaymentMethod);
|
|
452
|
+
},
|
|
453
|
+
/**
|
|
454
|
+
* Fetch a single payment method by id. The wire has no per-id query;
|
|
455
|
+
* this client-side filter on {@link methods.list} is the API reality.
|
|
456
|
+
* Adds one round-trip cost relative to a hypothetical
|
|
457
|
+
* `paymentOption(id)` query — acceptable given the list is small.
|
|
458
|
+
*
|
|
459
|
+
* Throws `PaymentsError("NOT_FOUND")` when no entry matches.
|
|
460
|
+
*/
|
|
461
|
+
async show(token, id) {
|
|
462
|
+
const list = await methods.list(token);
|
|
463
|
+
const found = list.find((m) => m.id === id);
|
|
464
|
+
if (found === undefined) {
|
|
465
|
+
throw new PaymentsError("NOT_FOUND", `No payment method found with id "${id}".`);
|
|
466
|
+
}
|
|
467
|
+
return found;
|
|
468
|
+
},
|
|
469
|
+
};
|
|
470
|
+
// ---------------------------------------------------------------------
|
|
471
|
+
// Rate namespace
|
|
472
|
+
// ---------------------------------------------------------------------
|
|
473
|
+
function projectViewerRoleRate(role) {
|
|
474
|
+
if (role === null)
|
|
475
|
+
return { decimal: null, verbose: null };
|
|
476
|
+
const decimal = role.rates?.hourly ?? null;
|
|
477
|
+
const verbose = role.hourlyRate?.verbose ?? null;
|
|
478
|
+
return { decimal, verbose };
|
|
479
|
+
}
|
|
480
|
+
function projectMarketInsight(role) {
|
|
481
|
+
const insight = role?.rateInsight?.hourly;
|
|
482
|
+
if (insight == null)
|
|
483
|
+
return null;
|
|
484
|
+
return {
|
|
485
|
+
currentRateCompetitive: insight.currentRateCompetitive,
|
|
486
|
+
recentApplicationRate: insight.recentApplicationRate,
|
|
487
|
+
recommendedRate: insight.recommendedRate,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
function projectValidation(config) {
|
|
491
|
+
const hourly = config?.rateValidationRules?.hourly;
|
|
492
|
+
if (hourly == null)
|
|
493
|
+
return null;
|
|
494
|
+
return { minRate: hourly.minRate, rateStep: hourly.rateStep };
|
|
495
|
+
}
|
|
496
|
+
function classifyOngoing(req) {
|
|
497
|
+
if (req === null)
|
|
498
|
+
return null;
|
|
499
|
+
if (req.status !== "PENDING" && req.status !== "CLAIMED")
|
|
500
|
+
return null;
|
|
501
|
+
return projectRateChangeRequest(req);
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Rate management — show the current rate + change history; submit a
|
|
505
|
+
* rate-change request.
|
|
506
|
+
*/
|
|
507
|
+
export const rate = {
|
|
508
|
+
/**
|
|
509
|
+
* Show the talent's current rate + most-recent rate-change request
|
|
510
|
+
* + market insight + validation rules. Issues TWO parallel queries:
|
|
511
|
+
* - `LastRateChangeRequest` — carries the most-recent change AND
|
|
512
|
+
* the current rates / market insight on the viewerRole side.
|
|
513
|
+
* - `RateChangeFormDetails` — carries the rate-validation rules
|
|
514
|
+
* (minRate / rateStep) the server enforces on `rate.change`.
|
|
515
|
+
*
|
|
516
|
+
* Both queries return overlapping viewerRole / rateInsight projections;
|
|
517
|
+
* we prefer the `LastRateChangeRequest` shape for those fields (its
|
|
518
|
+
* projection is denser) and fall back to `RateChangeFormDetails` for
|
|
519
|
+
* the validation rules (only this query exposes them).
|
|
520
|
+
*
|
|
521
|
+
* The wire's `ongoingRateChangeRequest` field is `Unknown`-typed and
|
|
522
|
+
* not exposed on `lastRateChangeRequest`; this projection classifies
|
|
523
|
+
* the returned `lastRateChangeRequest` by status — `PENDING` /
|
|
524
|
+
* `CLAIMED` count as "ongoing"; `COMPLETED` counts only as "last".
|
|
525
|
+
* If the wire shape ever grows a separate `ongoingRateChangeRequest`
|
|
526
|
+
* field that can be projected, swap the classification here for a
|
|
527
|
+
* direct read.
|
|
528
|
+
*/
|
|
529
|
+
async show(token) {
|
|
530
|
+
const [lastData, formData] = await Promise.all([
|
|
531
|
+
callGateway(token, "LastRateChangeRequest", LAST_RATE_CHANGE_REQUEST_QUERY, {}),
|
|
532
|
+
// Z-4 (#288) beachhead: the only `callGateway` site that passes
|
|
533
|
+
// a schema. See `RATE_CHANGE_FORM_DETAILS_RESPONSE_SCHEMA` for
|
|
534
|
+
// the audit transcript and the SDL-vs-hand-rolled disposition.
|
|
535
|
+
callGateway(token, "RateChangeFormDetails", RATE_CHANGE_FORM_DETAILS_QUERY, {}, RATE_CHANGE_FORM_DETAILS_RESPONSE_SCHEMA),
|
|
536
|
+
]);
|
|
537
|
+
if (lastData.viewer === null) {
|
|
538
|
+
throw new PaymentsError("NO_VIEWER", "Session is valid but no viewer is bound to it.");
|
|
539
|
+
}
|
|
540
|
+
const lastWire = lastData.viewer.lastRateChangeRequest;
|
|
541
|
+
const last = lastWire !== null ? projectRateChangeRequest(lastWire) : null;
|
|
542
|
+
const ongoing = classifyOngoing(lastWire);
|
|
543
|
+
const role = lastData.viewer.viewerRole ?? formData.viewer?.viewerRole ?? null;
|
|
544
|
+
const rates = projectViewerRoleRate(role);
|
|
545
|
+
return {
|
|
546
|
+
currentRateVerbose: rates.verbose,
|
|
547
|
+
currentRateDecimal: rates.decimal,
|
|
548
|
+
lastChange: last,
|
|
549
|
+
ongoingChange: ongoing,
|
|
550
|
+
marketInsight: projectMarketInsight(role),
|
|
551
|
+
validation: projectValidation(formData.platformConfiguration ?? null),
|
|
552
|
+
};
|
|
553
|
+
},
|
|
554
|
+
/**
|
|
555
|
+
* Fetch the rate-change form's question catalog. Answers to these
|
|
556
|
+
* questions are required as the `answers[]` input to
|
|
557
|
+
* {@link rate.change}. Mirrors the discovery pattern of
|
|
558
|
+
* `engagements.breaks.reasonsList()`.
|
|
559
|
+
*/
|
|
560
|
+
async questions(token) {
|
|
561
|
+
const data = await callGateway(token, "RateChangeRequestQuestions", RATE_CHANGE_QUESTIONS_QUERY, {});
|
|
562
|
+
if (data.viewer === null) {
|
|
563
|
+
throw new PaymentsError("NO_VIEWER", "Session is valid but no viewer is bound to it.");
|
|
564
|
+
}
|
|
565
|
+
const wires = (data.viewer.rateChangeRequestQuestions ?? []).filter((q) => q !== null);
|
|
566
|
+
return wires.map(projectRateQuestion);
|
|
567
|
+
},
|
|
568
|
+
/**
|
|
569
|
+
* Submit a rate-change request. Client-side validation:
|
|
570
|
+
* - `kind === "current-engagement"` requires `engagementId`.
|
|
571
|
+
* - Other kinds reject `engagementId`.
|
|
572
|
+
* - `desiredRate` and `answers` are passed verbatim to the wire.
|
|
573
|
+
*
|
|
574
|
+
* Dry-run path: when `dryRunOpts.dryRun === true`, short-circuit
|
|
575
|
+
* before any transport call and return a {@link DryRunPreview}-bearing
|
|
576
|
+
* outcome. No prefetch is required (the mutation has no implicit
|
|
577
|
+
* read).
|
|
578
|
+
*
|
|
579
|
+
* Apply path: invokes `CreateRateChangeRequest`. On `success: false`,
|
|
580
|
+
* throws `PaymentsError("MUTATION_ERROR")` with formatted per-field
|
|
581
|
+
* errors.
|
|
582
|
+
*/
|
|
583
|
+
async change(token, opts, dryRunOpts = {}) {
|
|
584
|
+
// Client-side validation — surface BEFORE any transport call.
|
|
585
|
+
if (opts.kind === "current-engagement" && (opts.engagementId === undefined || opts.engagementId === "")) {
|
|
586
|
+
throw new PaymentsError("MISSING_INPUT", "`rate change --kind=current-engagement` requires `--engagement <id>`.");
|
|
587
|
+
}
|
|
588
|
+
if (opts.kind !== "current-engagement" && opts.engagementId !== undefined && opts.engagementId !== "") {
|
|
589
|
+
throw new PaymentsError("MISSING_INPUT", `\`rate change --kind=${opts.kind}\` rejects \`--engagement <id>\` — drop the flag (the change is account-wide for this kind).`);
|
|
590
|
+
}
|
|
591
|
+
const wireAnswers = opts.answers.map((a) => {
|
|
592
|
+
const wire = { questionId: a.questionId, value: a.value };
|
|
593
|
+
if (a.comment !== undefined)
|
|
594
|
+
wire["comment"] = a.comment;
|
|
595
|
+
return wire;
|
|
596
|
+
});
|
|
597
|
+
const variables = {
|
|
598
|
+
desiredRate: opts.desiredRate,
|
|
599
|
+
engagementId: opts.engagementId ?? null,
|
|
600
|
+
requestType: RATE_CHANGE_KIND_TO_WIRE[opts.kind],
|
|
601
|
+
talentComment: opts.talentComment ?? null,
|
|
602
|
+
answers: wireAnswers,
|
|
603
|
+
};
|
|
604
|
+
if (dryRunOpts.dryRun === true) {
|
|
605
|
+
return {
|
|
606
|
+
kind: "preview",
|
|
607
|
+
preview: buildDryRunPreview({
|
|
608
|
+
surface: "mobile-gateway",
|
|
609
|
+
authToken: token,
|
|
610
|
+
body: {
|
|
611
|
+
operationName: "CreateRateChangeRequest",
|
|
612
|
+
query: CREATE_RATE_CHANGE_REQUEST_MUTATION,
|
|
613
|
+
variables,
|
|
614
|
+
},
|
|
615
|
+
}),
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
const data = await callGateway(token, "CreateRateChangeRequest", CREATE_RATE_CHANGE_REQUEST_MUTATION, variables);
|
|
619
|
+
if (data.viewerRole === null) {
|
|
620
|
+
throw new PaymentsError("UNKNOWN", "CreateRateChangeRequest response had no `viewerRole`.");
|
|
621
|
+
}
|
|
622
|
+
const result = data.viewerRole.createRateChangeRequest;
|
|
623
|
+
if (result === null) {
|
|
624
|
+
throw new PaymentsError("UNKNOWN", "CreateRateChangeRequest returned a null payload.");
|
|
625
|
+
}
|
|
626
|
+
if (!result.success) {
|
|
627
|
+
throw new PaymentsError("MUTATION_ERROR", formatMutationErrors("CreateRateChangeRequest failed", result.errors));
|
|
628
|
+
}
|
|
629
|
+
const wire = result.viewer?.lastRateChangeRequest ?? null;
|
|
630
|
+
if (wire === null) {
|
|
631
|
+
throw new PaymentsError("UNKNOWN", "CreateRateChangeRequest reported success but the returned `viewer.lastRateChangeRequest` was null.");
|
|
632
|
+
}
|
|
633
|
+
return { kind: "applied", result: projectRateChangeRequest(wire), notice: result.notice };
|
|
634
|
+
},
|
|
635
|
+
};
|
|
636
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/payments/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4EG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,mCAAmC,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACxH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAoC5D,MAAM,OAAO,aAAc,SAAQ,KAAK;IAGpB;IAFA,IAAI,GAAG,eAAe,CAAC;IACzC,YACkB,IAAuB,EACvC,OAAe,EACf,OAA6B;QAE7B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAJR,SAAI,GAAJ,IAAI,CAAmB;IAKzC,CAAC;CACF;AAqID,wEAAwE;AACxE,gCAAgC;AAChC,wEAAwE;AAExE;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,oBAAoB,EAAE,oBAAoB,EAAE,cAAc,CAAU,CAAC;AAGvG,MAAM,wBAAwB,GAAyF;IACrH,oBAAoB,EAAE,oBAAoB;IAC1C,oBAAoB,EAAE,oBAAoB;IAC1C,YAAY,EAAE,cAAc;CAC7B,CAAC;AAEF,MAAM,0BAA0B,GAA2B;IACzD,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;CACvB,CAAC;AA2KF,wEAAwE;AACxE,qEAAqE;AACrE,uDAAuD;AACvD,wEAAwE;AAExE,kFAAkF;AAClF,MAAM,cAAc,GAAG,8vBAA8vB,CAAC;AAEtxB,iFAAiF;AACjF,MAAM,aAAa,GAAG,6eAA6e,CAAC;AAEpgB,sEAAsE;AACtE,uEAAuE;AACvE,6EAA6E;AAC7E,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,sEAAsE;AACtE,uEAAuE;AACvE,iEAAiE;AACjE,mCAAmC;AACnC,MAAM,qBAAqB,GAAG,oKAAoK,CAAC;AAEnM,+FAA+F;AAC/F,MAAM,8BAA8B,GAAG,owBAAowB,CAAC;AAE5yB,+FAA+F;AAC/F,MAAM,8BAA8B,GAAG,k/BAAk/B,CAAC;AAE1hC,oGAAoG;AACpG,MAAM,2BAA2B,GAAG,wOAAwO,CAAC;AAE7Q,iGAAiG;AACjG,MAAM,mCAAmC,GAAG,gwCAAgwC,CAAC;AAyK7yC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,MAAM,wCAAwC,GAAG,CAAC,CAAC,MAAM,CAAC;IACxD,MAAM,EAAE,CAAC;SACN,MAAM,CAAC;QACN,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;QACd,UAAU,EAAE,CAAC;aACV,MAAM,CAAC;YACN,QAAQ,EAAE,CAAC;iBACR,MAAM,CAAC;gBACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;gBAChB,eAAe,EAAE,6BAA6B,EAAE;gBAChD,qBAAqB,EAAE,mCAAmC,EAAE;aAC7D,CAAC;iBACD,QAAQ,EAAE;YACb,KAAK,EAAE,CAAC;iBACL,MAAM,CAAC;gBACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC9B,CAAC;iBACD,QAAQ,EAAE;YACb,WAAW,EAAE,CAAC;iBACX,MAAM,CAAC;gBACN,MAAM,EAAE,CAAC;qBACN,MAAM,CAAC;oBACN,6DAA6D;oBAC7D,sBAAsB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;oBAC9C,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;oBAC5C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;iBACvC,CAAC;qBACD,QAAQ,EAAE;aACd,CAAC;iBACD,QAAQ,EAAE;SACd,CAAC;aACD,QAAQ,EAAE;KACd,CAAC;SACD,QAAQ,EAAE;IACb,qBAAqB,EAAE,CAAC;SACrB,MAAM,CAAC;QACN,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;QACd,mBAAmB,EAAE,CAAC;aACnB,MAAM,CAAC;YACN,MAAM,EAAE,CAAC;iBACN,MAAM,CAAC;gBACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;gBAC9B,wDAAwD;gBACxD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAChC,CAAC;iBACD,QAAQ,EAAE;SACd,CAAC;aACD,QAAQ,EAAE;KACd,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAgCH,sEAAsE;AACtE,uEAAuE;AACvE,6DAA6D;AAC7D,MAAM,sBAAsB,GAAG,yBAAyB,CAAC;AAEzD,wEAAwE;AACxE,kEAAkE;AAClE,wEAAwE;AAExE;;;;GAIG;AACH,KAAK,UAAU,WAAW,CACxB,KAAa,EACb,aAAqB,EACrB,KAAa,EACb,SAAkC,EAClC,MAAqB;IAErB,OAAO,iBAAiB,CAAmB,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE;QAClH,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAc,EAAE,MAAiD;IAC7F,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,OAAO,GAAG,MAAM,6BAA6B,CAAC;IAChD,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1C,CAAC;AAED,wEAAwE;AACxE,cAAc;AACd,wEAAwE;AAExE,SAAS,mBAAmB;IAC1B,OAAO;QACL,aAAa,EAAE,GAAG;QAClB,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,GAAG;QAChB,gBAAgB,EAAE,GAAG;QACrB,YAAY,EAAE,GAAG;QACjB,SAAS,EAAE,GAAG;KACf,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,IAA+B;IACxD,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAiB;IACtC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAkC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACxG,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAuB;IACnD,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;KAClD,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAAC,IAA2B;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,IAAI,CAAC;IACzC,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,aAAa,EAAE,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM;QACrE,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,YAAY,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,IAAI;QACzC,eAAe,EAAE,GAAG,EAAE,KAAK,IAAI,IAAI;QACnC,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,IAAI,IAAI;KAC1C,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,IAA4B;IACvD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAqC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC/F,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;KACnF,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,oBAAoB;AACpB,wEAAwE;AAExE;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,OAA2B,EAAE;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;QAC3E,MAAM,SAAS,GAA4B;YACzC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI;SACpG,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,WAAW,CAAuB,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;QACnG,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,gDAAgD,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAClC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,CAAC;QACvD,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAoB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QAC7F,OAAO;YACL,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;YAC/B,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,IAAI,mBAAmB,EAAE;SAC/D,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,EAAU;QAClC,IAAI,IAAyB,CAAC;QAC9B,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,WAAW,CAAsB,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACzF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,aAAa,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,IAAI,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC7G,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,4BAA4B,EAAE,qCAAqC,EAAE;oBACxG,KAAK,EAAE,GAAG;iBACX,CAAC,CAAC;YACL,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,4BAA4B,EAAE,qCAAqC,CAAC,CAAC;QAC5G,CAAC;QACD,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;CACF,CAAC;AAEF,wEAAwE;AACxE,oBAAoB;AACpB,wEAAwE;AAExE;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,CAAC,KAAa;QACtB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAyB,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,EAAE,CAAC,CAAC;QAC3G,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,gDAAgD,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAA0B,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACnG,OAAO,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,EAAU;QAClC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,oCAAoC,EAAE,IAAI,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC;AAEF,wEAAwE;AACxE,iBAAiB;AACjB,wEAAwE;AAExE,SAAS,qBAAqB,CAAC,IAA2B;IACxD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,IAAI,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,IAAI,IAAI,CAAC;IACjD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,oBAAoB,CAAC,IAA2B;IACvD,MAAM,OAAO,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC;IAC1C,IAAI,OAAO,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO;QACL,sBAAsB,EAAE,OAAO,CAAC,sBAAsB;QACtD,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;QACpD,eAAe,EAAE,OAAO,CAAC,eAAe;KACzC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAwC;IACjE,MAAM,MAAM,GAAG,MAAM,EAAE,mBAAmB,EAAE,MAAM,CAAC;IACnD,IAAI,MAAM,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;AAChE,CAAC;AAED,SAAS,eAAe,CAAC,GAAiC;IACxD,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,wBAAwB,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,IAAI,CAAC,KAAa;QACtB,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC7C,WAAW,CAAgC,KAAK,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,EAAE,CAAC;YAC9G,gEAAgE;YAChE,+DAA+D;YAC/D,+DAA+D;YAC/D,WAAW,CACT,KAAK,EACL,uBAAuB,EACvB,8BAA8B,EAC9B,EAAE,EACF,wCAAwC,CACzC;SACF,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC7B,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,gDAAgD,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,qBAAqB,CAAC;QACvD,MAAM,IAAI,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3E,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,IAAI,QAAQ,CAAC,MAAM,EAAE,UAAU,IAAI,IAAI,CAAC;QAC/E,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO;YACL,kBAAkB,EAAE,KAAK,CAAC,OAAO;YACjC,kBAAkB,EAAE,KAAK,CAAC,OAAO;YACjC,UAAU,EAAE,IAAI;YAChB,aAAa,EAAE,OAAO;YACtB,aAAa,EAAE,oBAAoB,CAAC,IAAI,CAAC;YACzC,UAAU,EAAE,iBAAiB,CAAC,QAAQ,CAAC,qBAAqB,IAAI,IAAI,CAAC;SACtE,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,KAAa;QAC3B,MAAM,IAAI,GAAG,MAAM,WAAW,CAC5B,KAAK,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,EAAE,CACH,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,gDAAgD,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAA+B,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACpH,OAAO,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,IAAuB,EAAE,aAA4B,EAAE;QACjF,8DAA8D;QAC9D,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,KAAK,EAAE,CAAC,EAAE,CAAC;YACxG,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,uEAAuE,CAAC,CAAC;QACpH,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,KAAK,EAAE,EAAE,CAAC;YACtG,MAAM,IAAI,aAAa,CACrB,eAAe,EACf,wBAAwB,IAAI,CAAC,IAAI,8FAA8F,CAChI,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACzC,MAAM,IAAI,GAA4B,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;YACnF,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;gBAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QACH,MAAM,SAAS,GAA4B;YACzC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI;YACvC,WAAW,EAAE,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC;YAChD,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI;YACzC,OAAO,EAAE,WAAW;SACrB,CAAC;QAEF,IAAI,UAAU,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC/B,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,kBAAkB,CAAC;oBAC1B,OAAO,EAAE,gBAAgB;oBACzB,SAAS,EAAE,KAAK;oBAChB,IAAI,EAAE;wBACJ,aAAa,EAAE,yBAAyB;wBACxC,KAAK,EAAE,mCAAmC;wBAC1C,SAAS;qBACV;iBACF,CAAC;aACH,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,WAAW,CAC5B,KAAK,EACL,yBAAyB,EACzB,mCAAmC,EACnC,SAAS,CACV,CAAC;QACF,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,uDAAuD,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,uBAAuB,CAAC;QACvD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,kDAAkD,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,aAAa,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,gCAAgC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACnH,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,qBAAqB,IAAI,IAAI,CAAC;QAC1D,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,aAAa,CACrB,SAAS,EACT,oGAAoG,CACrG,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,wBAAwB,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC5F,CAAC;CACF,CAAC"}
|