@curviate/sdk 0.14.1 → 0.15.0

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/dist/index.js CHANGED
@@ -1,4 +1,70 @@
1
1
  // src/errors.ts
2
+ var ERROR_CODES = [
3
+ // Authentication / authorization
4
+ "UNAUTHORIZED",
5
+ "INVALID_REQUEST",
6
+ "UNSUPPORTED_MEDIA_TYPE",
7
+ "PAYLOAD_TOO_LARGE",
8
+ // Account state
9
+ "ACCOUNT_NOT_FOUND",
10
+ "ACCOUNT_RESTRICTED",
11
+ // Duplicate connect — reconnect or adopt the existing account instead of
12
+ // linking again. Not retryable.
13
+ "ACCOUNT_ALREADY_LINKED",
14
+ "RESOURCE_NOT_FOUND",
15
+ "RESOURCE_ACCESS_RESTRICTED",
16
+ // Tier / subscription gating
17
+ "TIER_NOT_ACTIVE",
18
+ "LINKEDIN_FEATURE_NOT_SUBSCRIBED",
19
+ // Rate limits
20
+ "RATE_LIMIT_ACCOUNT",
21
+ "RATE_LIMIT_TENANT",
22
+ "PLATFORM_RATE_LIMIT",
23
+ // LinkedIn-platform-level throttling on the Recruiter / Sales Navigator read
24
+ // surface (carries dedicated RateLimit-Policy / RateLimit / Retry-After
25
+ // response headers). Distinct from the account/tenant/platform trio above.
26
+ // Always retry-safe (retry_likely_to_succeed: true) — see RETRYABLE_CODES.
27
+ "RATE_LIMITED",
28
+ // Platform errors
29
+ "PLATFORM_ERROR",
30
+ "PLATFORM_NOT_IMPLEMENTED",
31
+ // Permanent LinkedIn platform limitation for the attempted operation (e.g.
32
+ // listing a non-self user's following list). Not a transient failure —
33
+ // retrying will not help.
34
+ "LINKEDIN_OPERATION_NOT_SUPPORTED",
35
+ // Checkpoint (account connect flow)
36
+ "CHECKPOINT_NOT_FOUND",
37
+ "CHECKPOINT_EXPIRED",
38
+ "CHECKPOINT_INVALID_CODE",
39
+ "CHECKPOINT_MAX_ATTEMPTS",
40
+ "CHECKPOINT_ALREADY_RESOLVED",
41
+ "CHECKPOINT_UNSUPPORTED",
42
+ "CONNECTION_IN_PROGRESS",
43
+ // LinkedIn-specific connect errors
44
+ "LINKEDIN_AUTH_FAILED",
45
+ "LINKEDIN_RATE_LIMITED",
46
+ "LINKEDIN_COOKIE_INVALID",
47
+ "LINKEDIN_SERVICE_UNAVAILABLE",
48
+ // Messaging / connect-request mutation
49
+ "MESSAGE_WINDOW_EXPIRED",
50
+ "RECIPIENT_UNREACHABLE",
51
+ // Duplicate / already-connected connect-request conflict: a send to a
52
+ // recipient who already has a pending request from this account, or is already
53
+ // a first-degree connection. user_fixable, never retryable — do not re-send.
54
+ "CONNECTION_REQUEST_CONFLICT",
55
+ // Billing (surface: tenant-management)
56
+ "PAYMENT_REQUIRED",
57
+ "PAYMENT_FAILED",
58
+ "SUBSCRIPTION_BUSY",
59
+ "SUBSCRIPTION_NOT_FOUND",
60
+ "SEAT_NOT_FOUND",
61
+ "SEAT_CANCELLED",
62
+ // Generic
63
+ "INTERNAL"
64
+ ];
65
+ var KNOWN_ERROR_CODES = new Set(ERROR_CODES);
66
+ var REQUIRED_TIERS = ["core", "sn", "sales_nav", "recruiter"];
67
+ var KNOWN_REQUIRED_TIERS = new Set(REQUIRED_TIERS);
2
68
  var CurviateError = class _CurviateError extends Error {
3
69
  constructor(init) {
4
70
  super(init.message);
@@ -66,53 +132,10 @@ var RETRYABLE_CODES = /* @__PURE__ */ new Set([
66
132
  "PLATFORM_ERROR",
67
133
  "PLATFORM_RATE_LIMIT",
68
134
  "RATE_LIMIT_ACCOUNT",
69
- "RATE_LIMIT_TENANT"
70
- ]);
71
- var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PATCH", "PUT", "DELETE"]);
72
- var KNOWN_CODES = /* @__PURE__ */ new Set([
73
- "UNAUTHORIZED",
74
- "INVALID_REQUEST",
75
- "UNSUPPORTED_MEDIA_TYPE",
76
- "PAYLOAD_TOO_LARGE",
77
- "ACCOUNT_NOT_FOUND",
78
- "ACCOUNT_RESTRICTED",
79
- "ACCOUNT_ALREADY_LINKED",
80
- "RESOURCE_NOT_FOUND",
81
- "RESOURCE_ACCESS_RESTRICTED",
82
- "TIER_NOT_ACTIVE",
83
- "LINKEDIN_FEATURE_NOT_SUBSCRIBED",
84
- "RATE_LIMIT_ACCOUNT",
85
135
  "RATE_LIMIT_TENANT",
86
- "PLATFORM_RATE_LIMIT",
87
- "PLATFORM_ERROR",
88
- "PLATFORM_NOT_IMPLEMENTED",
89
- "CHECKPOINT_NOT_FOUND",
90
- "CHECKPOINT_EXPIRED",
91
- "CHECKPOINT_INVALID_CODE",
92
- "CHECKPOINT_MAX_ATTEMPTS",
93
- "CHECKPOINT_ALREADY_RESOLVED",
94
- "CHECKPOINT_UNSUPPORTED",
95
- "CONNECTION_IN_PROGRESS",
96
- "LINKEDIN_AUTH_FAILED",
97
- "LINKEDIN_RATE_LIMITED",
98
- "LINKEDIN_COOKIE_INVALID",
99
- "LINKEDIN_SERVICE_UNAVAILABLE",
100
- "MESSAGE_WINDOW_EXPIRED",
101
- "RECIPIENT_UNREACHABLE",
102
- "PAYMENT_REQUIRED",
103
- "PAYMENT_FAILED",
104
- "SUBSCRIPTION_BUSY",
105
- "SUBSCRIPTION_NOT_FOUND",
106
- "SEAT_NOT_FOUND",
107
- "SEAT_CANCELLED",
108
- "INTERNAL"
109
- ]);
110
- var REQUIRED_TIERS = /* @__PURE__ */ new Set([
111
- "core",
112
- "sn",
113
- "sales_nav",
114
- "recruiter"
136
+ "RATE_LIMITED"
115
137
  ]);
138
+ var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PATCH", "PUT", "DELETE"]);
116
139
  function defaultSleep(ms) {
117
140
  return new Promise((resolve) => setTimeout(resolve, ms));
118
141
  }
@@ -127,7 +150,7 @@ function backoffDelay(n, jitter) {
127
150
  return exp + jitter;
128
151
  }
129
152
  function toErrorCode(code) {
130
- return code && KNOWN_CODES.has(code) ? code : "INTERNAL";
153
+ return code && KNOWN_ERROR_CODES.has(code) ? code : "INTERNAL";
131
154
  }
132
155
  function toRetryHint(hint) {
133
156
  if (!hint || typeof hint !== "object") return null;
@@ -145,7 +168,7 @@ async function errorFromResponse(res) {
145
168
  } catch {
146
169
  env = void 0;
147
170
  }
148
- const requiredTier = env?.required_tier && REQUIRED_TIERS.has(env.required_tier) ? env.required_tier : void 0;
171
+ const requiredTier = env?.required_tier && KNOWN_REQUIRED_TIERS.has(env.required_tier) ? env.required_tier : void 0;
149
172
  return new CurviateError({
150
173
  code: toErrorCode(env?.code),
151
174
  message: env?.message ?? `Request failed with status ${res.status}.`,
@@ -216,7 +239,7 @@ async function execute(method, path, opts) {
216
239
  let res;
217
240
  try {
218
241
  res = await doFetch(url, buildInit(method, opts, controller.signal));
219
- } catch (cause) {
242
+ } catch {
220
243
  clearTimeout(timer);
221
244
  const aborted = controller.signal.aborted;
222
245
  const err2 = new CurviateError({
@@ -251,37 +274,22 @@ async function execute(method, path, opts) {
251
274
  }
252
275
 
253
276
  // src/internal/context.ts
254
- function injectAccountIdIntoBody(body, accountId) {
255
- if (body instanceof FormData) {
256
- if (!body.has("account_id")) body.append("account_id", accountId);
257
- return body;
258
- }
259
- if (body !== null && typeof body === "object") {
260
- const obj = body;
261
- return "account_id" in obj ? obj : { account_id: accountId, ...obj };
262
- }
263
- return body;
277
+ var ACCOUNT_ID_PLACEHOLDER = "{account_id}";
278
+ function injectAccountIdIntoPath(path, accountId) {
279
+ if (accountId === void 0) return path;
280
+ return path.split(ACCOUNT_ID_PLACEHOLDER).join(accountId);
264
281
  }
265
282
  function createContext(config, accountId) {
266
283
  const request = (args) => {
267
- const target = args.accountIdIn ?? "query";
268
- let { query, body } = args;
269
- if (accountId !== void 0) {
270
- if (target === "body") {
271
- body = injectAccountIdIntoBody(body, accountId);
272
- } else if (target === "none") {
273
- } else {
274
- query = { account_id: accountId, ...args.query };
275
- }
276
- }
277
- return execute(args.method, args.path, {
284
+ const path = injectAccountIdIntoPath(args.path, accountId);
285
+ return execute(args.method, path, {
278
286
  apiKey: config.apiKey,
279
287
  baseUrl: config.baseUrl,
280
288
  timeout: config.timeout,
281
289
  maxRetries: config.maxRetries,
282
290
  ...config.fetch ? { fetch: config.fetch } : {},
283
- ...query !== void 0 ? { query } : {},
284
- ...body !== void 0 ? { body } : {}
291
+ ...args.query !== void 0 ? { query: args.query } : {},
292
+ ...args.body !== void 0 ? { body: args.body } : {}
285
293
  });
286
294
  };
287
295
  return { request, accountId };
@@ -330,450 +338,387 @@ var AccountsResource = class {
330
338
  });
331
339
  }
332
340
  /**
333
- * Connect a LinkedIn account to an empty seat.
334
- *
335
- * Returns an account (201) or a checkpoint challenge (202) when LinkedIn
336
- * requires verification. Callers discriminate on `result.object`; resolve a
337
- * 202 with {@link solveCheckpoint} (code) or {@link pollCheckpoint}
338
- * (mobile-app approval).
339
- *
340
- * For `auth_method: "cookie"`, `user_agent` is **required** — connecting by
341
- * session cookie without one is rejected with `INVALID_REQUEST`. It stays
342
- * optional for `auth_method: "credentials"`.
341
+ * Return metadata and current state for one connected account, including the
342
+ * central `quotas[]` view for all tracked quota families and `seat_id` (the
343
+ * seat this account occupies, `null` for an admin seatless account).
343
344
  *
344
- * On a 201 account, `recovered` is `true` only when the connect reclaimed a
345
- * LinkedIn identity already present on the workspace (claiming it into your
346
- * account) rather than connecting a brand-new one — it is absent on a normal
347
- * connect. Its `status` reflects the account's real observed state: as well as
348
- * `active` it may be `reconnect_needed`, `restricted`, or `disconnected` (a
349
- * recovered identity often needs a reconnect).
345
+ * This is a stale-while-revalidate read — it always returns immediately
346
+ * from the cached row (never blocks on a live substrate call). The cached
347
+ * enrichment fields `full_name` and `substrate_created_at` are populated by
348
+ * a background enrichment pass; `username`, `premium_id`,
349
+ * `public_identifier`, `signatures`, and `groups` are not sourced on the
350
+ * current connection surface and read `null`/`[]`.
350
351
  */
351
- link(body) {
352
+ get(accountId) {
352
353
  return this.ctx.request({
353
- method: "POST",
354
- path: "/v1/accounts/link",
355
- body
354
+ method: "GET",
355
+ path: `/v1/accounts/${accountId}`
356
356
  });
357
357
  }
358
358
  /**
359
- * Solve a checkpoint challenge by submitting an OTP or 2FA code.
360
- *
361
- * The account is addressed by `accountId` (the provisional `account_id`
362
- * returned on the 202 `checkpoint_required` response); the body carries the
363
- * `code`. Returns the connected account (201) or, when LinkedIn chains a
364
- * second challenge, another checkpoint (202) — resolve that one with a
365
- * further `solveCheckpoint` call for the same `accountId`.
366
- *
367
- * On the 201 account, `recovered` is `true` only when solving the challenge
368
- * reclaimed a LinkedIn identity already present on the workspace (rather than
369
- * connecting a brand-new one); it is absent otherwise. Its `status` reflects
370
- * the account's real observed state — as well as `active` it may be
371
- * `reconnect_needed`, `restricted`, or `disconnected`.
359
+ * Update an account's configuration.
372
360
  *
373
- * @param accountId - the provisional `account_id` from the 202 response.
374
- * @param body - the verification `code`.
361
+ * `metadata` is a flat string→string map that **replaces** the account's
362
+ * custom-data store wholesale (keys not provided are removed). `proxy` sets a
363
+ * custom egress proxy, or clears it (reverting to automatic proxy protection)
364
+ * when passed as `null`. The `proxy.password`, if given, is stored securely
365
+ * and never returned.
375
366
  */
376
- solveCheckpoint(accountId, body) {
367
+ update(accountId, body) {
377
368
  return this.ctx.request({
378
- method: "POST",
379
- path: `/v1/accounts/${accountId}/checkpoint/solve`,
369
+ method: "PATCH",
370
+ path: `/v1/accounts/${accountId}`,
380
371
  body
381
372
  });
382
373
  }
383
374
  /**
384
- * Re-request the pending verification challenge notification for an account.
385
- *
386
- * Useful when the end user says they never received the code or push
387
- * notification for a pending checkpoint. `resent` echoes the outcome
388
- * honestly: `true` once the notification was actually re-sent, `false` when
389
- * there was nothing to re-send for that challenge type (this call never
390
- * throws just because a re-send wasn't applicable). Does not reset the
391
- * checkpoint's expiry.
392
- *
393
- * @param accountId - the provisional `account_id` from the 202 response.
375
+ * Hard-disconnect a LinkedIn account; releases the attached seat.
394
376
  */
395
- requestCheckpoint(accountId) {
377
+ disconnect(accountId) {
396
378
  return this.ctx.request({
397
- method: "POST",
398
- path: `/v1/accounts/${accountId}/checkpoint/request`
379
+ method: "DELETE",
380
+ path: `/v1/accounts/${accountId}`
399
381
  });
400
382
  }
383
+ };
384
+
385
+ // src/resources/auth.ts
386
+ var AuthResource = class {
387
+ constructor(ctx) {
388
+ this.ctx = ctx;
389
+ }
401
390
  /**
402
- * Poll for mobile-app approval of a pending checkpoint challenge.
391
+ * Authenticate a LinkedIn account with credentials or a session cookie.
403
392
  *
404
- * The account is addressed by `accountId` (the provisional `account_id`
405
- * from the 202 response). `status` is `pending` until the end user approves
406
- * on their device, then `active` (the account is connected), or
407
- * `expired` / `failed`. Poll until it leaves `pending`.
393
+ * Omit `account_id` to connect a NEW account into an empty seat; include it
394
+ * to re-authenticate an EXISTING account in place. Returns the account on
395
+ * success (200 re-authenticated in place / 201 new), or a checkpoint
396
+ * challenge (202) when LinkedIn requires verification — resolve it with
397
+ * {@link solveCheckpoint} (code) or {@link pollCheckpoint} (mobile-app
398
+ * approval).
408
399
  *
409
- * On `status: "expired"` (the approval timed out), the response carries
410
- * `challenge_type` (`"mobile_app_approval"`) and a human-readable
411
- * `recovery_hint` — the actionable next step — so a client can render the
412
- * right recovery guidance without parsing prose.
400
+ * For `auth_method: "cookie"`, `user_agent` is **required** — connecting by
401
+ * session cookie without one is rejected with `INVALID_REQUEST`. It stays
402
+ * optional for `auth_method: "credentials"`.
413
403
  *
414
- * @param accountId - the provisional `account_id` from the 202 response.
415
- */
416
- pollCheckpoint(accountId) {
417
- return this.ctx.request({
418
- method: "POST",
419
- path: `/v1/accounts/${accountId}/checkpoint/poll`
420
- });
421
- }
422
- /**
423
- * Generate a one-time hosted connection link the end user opens to authorize
424
- * a new LinkedIn connection without credentials transiting the API or LLM
425
- * context. Poll completion with {@link getConnectSession} using the returned
426
- * `session_id`. To re-authorize an existing account, use
427
- * {@link createReconnectLink} instead.
404
+ * On a 201 account, `recovered` is `true` only when the connect reclaimed a
405
+ * LinkedIn identity already present on the workspace (claiming it into your
406
+ * account) rather than connecting a brand-new one — it is absent on a normal
407
+ * connect.
428
408
  */
429
- createConnectLink(body) {
409
+ intent(body) {
430
410
  return this.ctx.request({
431
411
  method: "POST",
432
- path: "/v1/accounts/connect-link",
412
+ path: "/v1/auth/intent",
433
413
  body
434
414
  });
435
415
  }
436
416
  /**
437
- * Generate a one-time hosted **re-authorization** link for an existing
438
- * account that became disconnected — the hosted counterpart of
439
- * {@link reconnect}. The end user opens the returned `url`; poll completion
440
- * with {@link getConnectSession} using the returned `session_id`. The account
441
- * keeps its `account_id` and seat.
417
+ * Solve a checkpoint challenge by submitting an OTP / 2FA code (or the
418
+ * special value `TRY_ANOTHER_WAY` to switch challenge method).
442
419
  *
443
- * @param accountId - the account to re-authorize.
444
- * @param body - optional `expires_in_seconds` and `redirect_url`.
420
+ * Returns the connected account (201) or, when LinkedIn chains a second
421
+ * challenge, another checkpoint (202) — resolve that one with a further
422
+ * `solveCheckpoint` call for the same `accountId`.
423
+ *
424
+ * @param accountId - the (provisional) `account_id` from the 202 response.
425
+ * @param body - the verification `code`.
445
426
  */
446
- createReconnectLink(accountId, body) {
427
+ solveCheckpoint(accountId, body) {
447
428
  return this.ctx.request({
448
429
  method: "POST",
449
- path: `/v1/accounts/${accountId}/reconnect-link`,
450
- ...body !== void 0 ? { body } : {}
430
+ path: "/v1/auth/checkpoint/solve",
431
+ body: { account_id: accountId, ...body }
451
432
  });
452
433
  }
453
434
  /**
454
- * Poll a hosted connect session minted by {@link createConnectLink} or
455
- * {@link createReconnectLink} (its `session_id`).
456
- *
457
- * A pure status read — it makes no external call and does not itself complete
458
- * the connection. `status` is `pending` until the end user finishes the
459
- * hosted flow, then `resolved` (with `account_id`), or `expired` / `failed`.
460
- * Poll until it leaves `pending`.
435
+ * Re-request the pending checkpoint notification (OTP / 2FA / mobile-app
436
+ * push). `resent` is honest: `true` once the notification was actually
437
+ * re-sent, `false` when there was nothing to re-send for that challenge
438
+ * type (e.g. an authenticator-app code) — this call never throws just
439
+ * because a re-send wasn't applicable. Does not reset the checkpoint's
440
+ * expiry.
461
441
  *
462
- * @param sessionId - the `session_id` returned on the connect-link 201 body.
463
- * @returns the session's current `status` and, once `resolved`, `account_id`.
442
+ * @param accountId - the (provisional) `account_id` from the 202 response.
464
443
  */
465
- getConnectSession(sessionId) {
444
+ requestCheckpoint(accountId) {
466
445
  return this.ctx.request({
467
- method: "GET",
468
- path: `/v1/accounts/connect-sessions/${sessionId}`
446
+ method: "POST",
447
+ path: "/v1/auth/checkpoint/request",
448
+ body: { account_id: accountId }
469
449
  });
470
450
  }
471
451
  /**
472
- * Return metadata and current state for one connected account, including the
473
- * central `quotas[]` view for all tracked quota families and `seat_id` (the
474
- * seat this account occupies, `null` for an admin seatless account).
452
+ * Poll for mobile-app approval of a pending checkpoint challenge until it
453
+ * leaves `pending`.
475
454
  *
476
- * This is a stale-while-revalidate read — it always returns immediately
477
- * from the cached row (never blocks on a live substrate call). The cached
478
- * enrichment fields `full_name` and `substrate_created_at` are populated by
479
- * a background enrichment pass; `username`, `premium_id`,
480
- * `public_identifier`, `signatures`, and `groups` are not sourced on the
481
- * current connection surface and read `null`/`[]`.
482
- */
483
- get(accountId) {
484
- return this.ctx.request({
485
- method: "GET",
486
- path: `/v1/accounts/${accountId}`
487
- });
488
- }
489
- /**
490
- * Re-authorize a disconnected account in place (same `account_id`, same
491
- * seat). Returns the reconnected account (200) or a checkpoint challenge
492
- * (202) when LinkedIn requires verification — resolve a 202 with
493
- * {@link solveCheckpoint} / {@link pollCheckpoint}, exactly like {@link link}.
455
+ * On `status: "expired"`, the response carries `challenge_type`
456
+ * (`"mobile_app_approval"`) and a human-readable `recovery_hint`.
494
457
  *
495
- * For `auth_method: "cookie"`, `user_agent` is **required** (as on
496
- * {@link link}). For the hosted re-auth flow, use {@link createReconnectLink}.
458
+ * @param accountId - the (provisional) `account_id` from the 202 response.
497
459
  */
498
- reconnect(accountId, body) {
460
+ pollCheckpoint(accountId) {
499
461
  return this.ctx.request({
500
462
  method: "POST",
501
- path: `/v1/accounts/${accountId}/reconnect`,
502
- body
463
+ path: "/v1/auth/checkpoint/poll",
464
+ body: { account_id: accountId }
503
465
  });
504
466
  }
505
467
  /**
506
- * Update an account's configuration.
468
+ * Poll a credential connect session by its account id — a pure status read
469
+ * that makes no external call and does not itself complete the connection.
470
+ * `status` is `checkpoint_required` until resolved, then `done` (with
471
+ * `account_id`), or `expired` / `failed`.
507
472
  *
508
- * `metadata` is a flat string→string map that **replaces** the account's
509
- * custom-data store wholesale (keys not provided are removed). `proxy` sets a
510
- * custom egress proxy, or clears it (reverting to automatic proxy protection)
511
- * when passed as `null`. The `proxy.password`, if given, is stored securely
512
- * and never returned.
513
- */
514
- update(accountId, body) {
515
- return this.ctx.request({
516
- method: "PATCH",
517
- path: `/v1/accounts/${accountId}`,
518
- body
519
- });
520
- }
521
- /**
522
- * Hard-disconnect a LinkedIn account; releases the attached seat.
473
+ * @param sessionId - the acc_… id returned by {@link intent} or a checkpoint response.
523
474
  */
524
- disconnect(accountId) {
475
+ getSession(sessionId) {
525
476
  return this.ctx.request({
526
- method: "DELETE",
527
- path: `/v1/accounts/${accountId}`
477
+ method: "GET",
478
+ path: `/v1/auth/sessions/${sessionId}`
528
479
  });
529
480
  }
530
481
  };
531
482
 
532
483
  // src/resources/messaging.ts
533
- function buildFormData(scalars, attachments) {
534
- const form = new FormData();
535
- for (const [key, value] of Object.entries(scalars)) {
536
- if (value !== void 0 && value !== null) {
537
- form.append(key, String(value));
538
- }
539
- }
540
- for (const attachment of attachments) {
541
- if (attachment instanceof File) {
542
- form.append("attachments", attachment);
543
- } else {
544
- form.append("attachments", new Blob([attachment]));
545
- }
546
- }
547
- return form;
548
- }
549
484
  var MessagingResource = class {
550
485
  constructor(ctx) {
551
486
  this.ctx = ctx;
552
487
  }
553
- /** List paginated chats for the account. `GET /v1/chats` */
488
+ /** List paginated chats for the account. `GET /v1/{account_id}/chats` */
554
489
  listChats(params) {
555
490
  return this.ctx.request({
556
491
  method: "GET",
557
- path: "/v1/chats",
492
+ path: "/v1/{account_id}/chats",
558
493
  ...params ? { query: params } : {}
559
494
  });
560
495
  }
561
496
  /**
562
- * Start a new chat. Accepts optional `attachments[]` — when present, the
563
- * request is sent as `multipart/form-data`. `POST /v1/chats`
497
+ * Start a new chat with one or more members. `POST /v1/{account_id}/chats`
498
+ * `attachments[]`, when supplied, carry base64-encoded file bytes — always
499
+ * sent as JSON, never multipart.
564
500
  */
565
501
  startChat(body) {
566
- const { attachments, ...scalars } = body;
567
- if (attachments && attachments.length > 0) {
568
- return this.ctx.request({
569
- method: "POST",
570
- path: "/v1/chats",
571
- body: buildFormData(scalars, attachments),
572
- accountIdIn: "body"
573
- });
574
- }
575
502
  return this.ctx.request({
576
503
  method: "POST",
577
- path: "/v1/chats",
578
- body: scalars,
579
- accountIdIn: "body"
504
+ path: "/v1/{account_id}/chats",
505
+ body
580
506
  });
581
507
  }
582
- /** Get details of a single chat. `GET /v1/chats/{chat_id}` */
508
+ /** Get details of a single chat. `GET /v1/{account_id}/chats/{chat_id}` */
583
509
  getChat(chatId) {
584
510
  return this.ctx.request({
585
511
  method: "GET",
586
- path: `/v1/chats/${chatId}`
512
+ path: `/v1/{account_id}/chats/${chatId}`
513
+ });
514
+ }
515
+ /**
516
+ * Mark a chat read or unread. `PATCH /v1/{account_id}/chats/{chat_id}`
517
+ * Body: `{read}`.
518
+ */
519
+ markChatRead(chatId, body) {
520
+ return this.ctx.request({
521
+ method: "PATCH",
522
+ path: `/v1/{account_id}/chats/${chatId}`,
523
+ body
587
524
  });
588
525
  }
589
- /** List messages in a chat, cursor-paginated. `GET /v1/chats/{chat_id}/messages` */
526
+ /**
527
+ * List messages in a chat, cursor-paginated.
528
+ * `GET /v1/{account_id}/chats/{chat_id}/messages`
529
+ */
590
530
  listMessages(chatId, params) {
591
531
  return this.ctx.request({
592
532
  method: "GET",
593
- path: `/v1/chats/${chatId}/messages`,
533
+ path: `/v1/{account_id}/chats/${chatId}/messages`,
594
534
  ...params ? { query: params } : {}
595
535
  });
596
536
  }
597
537
  /**
598
- * Send a message in a chat. Multipart when `attachments[]` are provided.
599
- * `POST /v1/chats/{chat_id}/messages`
538
+ * Send a message in a chat. `POST /v1/{account_id}/chats/{chat_id}/messages`
539
+ * `attachments[]`, when supplied, carry base64-encoded file bytes — always
540
+ * sent as JSON, never multipart. At least one of `text`/`attachments` is
541
+ * required (enforced server-side).
600
542
  */
601
543
  sendMessage(chatId, body) {
602
- const { attachments, ...scalars } = body;
603
- if (attachments && attachments.length > 0) {
604
- return this.ctx.request({
605
- method: "POST",
606
- path: `/v1/chats/${chatId}/messages`,
607
- body: buildFormData(scalars, attachments),
608
- accountIdIn: "body"
609
- });
610
- }
611
544
  return this.ctx.request({
612
545
  method: "POST",
613
- path: `/v1/chats/${chatId}/messages`,
614
- body: scalars,
615
- accountIdIn: "body"
616
- });
617
- }
618
- /** Trigger a re-sync of a specific chat's message history. `GET /v1/chats/{chat_id}/sync` */
619
- syncChat(chatId) {
620
- return this.ctx.request({
621
- method: "GET",
622
- path: `/v1/chats/${chatId}/sync`
546
+ path: `/v1/{account_id}/chats/${chatId}/messages`,
547
+ body
623
548
  });
624
549
  }
625
- /** Get a single message by ID. `GET /v1/messages/{message_id}` */
626
- getMessage(messageId) {
550
+ /**
551
+ * Get a single message by ID, re-homed under its chat.
552
+ * `GET /v1/{account_id}/chats/{chat_id}/messages/{message_id}`
553
+ */
554
+ getMessage(chatId, messageId) {
627
555
  return this.ctx.request({
628
556
  method: "GET",
629
- path: `/v1/messages/${messageId}`
557
+ path: `/v1/{account_id}/chats/${chatId}/messages/${messageId}`
630
558
  });
631
559
  }
632
- /** Edit a message within the ~60-minute edit window. `PATCH /v1/messages/{message_id}` */
633
- editMessage(messageId, body) {
560
+ /**
561
+ * Edit a message within the ~60-minute edit window.
562
+ * `PATCH /v1/{account_id}/chats/{chat_id}/messages/{message_id}`
563
+ */
564
+ editMessage(chatId, messageId, body) {
634
565
  return this.ctx.request({
635
566
  method: "PATCH",
636
- path: `/v1/messages/${messageId}`,
567
+ path: `/v1/{account_id}/chats/${chatId}/messages/${messageId}`,
637
568
  body
638
569
  });
639
570
  }
640
- /** Delete a message within the delete window. `DELETE /v1/messages/{message_id}` */
641
- deleteMessage(messageId) {
571
+ /**
572
+ * Delete a message within the delete window (bodyless).
573
+ * `DELETE /v1/{account_id}/chats/{chat_id}/messages/{message_id}`
574
+ */
575
+ deleteMessage(chatId, messageId) {
642
576
  return this.ctx.request({
643
577
  method: "DELETE",
644
- path: `/v1/messages/${messageId}`,
645
- accountIdIn: "none"
646
- // server resolves owning account from message id
578
+ path: `/v1/{account_id}/chats/${chatId}/messages/${messageId}`
647
579
  });
648
580
  }
649
581
  /**
650
- * Download a message attachment. Returns raw binary.
651
- * `GET /v1/messages/{message_id}/attachments/{attachment_id}`
652
- * Returns `ArrayBuffer` — binary response; the SDK does not cache or store it.
582
+ * Add a reaction to a message.
583
+ * `POST /v1/{account_id}/chats/{chat_id}/messages/{message_id}/reactions`
653
584
  */
654
- getAttachment(messageId, attachmentId) {
655
- return this.ctx.request({
656
- method: "GET",
657
- path: `/v1/messages/${messageId}/attachments/${attachmentId}`
658
- });
659
- }
660
- /** Add a reaction to a message. `POST /v1/messages/{message_id}/reactions` */
661
- addReaction(messageId, body) {
585
+ addReaction(chatId, messageId, body) {
662
586
  return this.ctx.request({
663
587
  method: "POST",
664
- path: `/v1/messages/${messageId}/reactions`,
665
- body,
666
- accountIdIn: "none"
667
- // server resolves owning account from message id
668
- });
669
- }
670
- /** Send an InMail. `POST /v1/messages/inmail` */
671
- sendInMail(body) {
672
- return this.ctx.request({
673
- method: "POST",
674
- path: "/v1/messages/inmail",
675
- body,
676
- accountIdIn: "body"
588
+ path: `/v1/{account_id}/chats/${chatId}/messages/${messageId}/reactions`,
589
+ body
677
590
  });
678
591
  }
679
- /** Get the account's InMail credit balance. `GET /v1/messaging/inmail-balance` */
680
- getInMailBalance(params) {
592
+ /**
593
+ * Download a message attachment. Returns raw binary.
594
+ * `GET /v1/{account_id}/chats/{chat_id}/messages/{message_id}/attachments/{attachment_id}`
595
+ * Returns `ArrayBuffer` — binary response; the SDK does not cache or store it.
596
+ */
597
+ getAttachment(chatId, messageId, attachmentId) {
681
598
  return this.ctx.request({
682
599
  method: "GET",
683
- path: "/v1/messaging/inmail-balance",
684
- ...params ? { query: params } : {}
600
+ path: `/v1/{account_id}/chats/${chatId}/messages/${messageId}/attachments/${attachmentId}`
685
601
  });
686
602
  }
687
- /** Re-sync account message history. `GET /v1/messages/sync` */
688
- syncMessages(params) {
603
+ /** Send an InMail. `POST /v1/{account_id}/messages/inmail` */
604
+ sendInMail(body) {
689
605
  return this.ctx.request({
690
- method: "GET",
691
- path: "/v1/messages/sync",
692
- ...params ? { query: params } : {}
606
+ method: "POST",
607
+ path: "/v1/{account_id}/messages/inmail",
608
+ body
693
609
  });
694
610
  }
695
611
  };
696
612
 
697
- // src/resources/profiles.ts
698
- var ProfilesResource = class {
613
+ // src/resources/users.ts
614
+ var UsersResource = class {
699
615
  constructor(ctx) {
700
616
  this.ctx = ctx;
701
617
  }
702
618
  /**
703
- * Get the account's own LinkedIn profile. `GET /v1/profiles/me`
704
- * Pass `{ linkedin_sections: ['about', 'experience', ...] }` to request enriched sections.
705
- * The `account_id` is injected by the account-scoped context.
619
+ * Retrieve a user's profile. `GET /v1/{account_id}/users/{user_id}`
620
+ * Pass `userId: "me"` for the caller's own account (folds in the old
621
+ * standalone `getMe()`). Pass `{ linkedin_sections: [...] }` to request
622
+ * enriched sections.
706
623
  */
707
- getMe(params) {
624
+ get(userId, params) {
708
625
  return this.ctx.request({
709
626
  method: "GET",
710
- path: "/v1/profiles/me",
627
+ path: `/v1/{account_id}/users/${userId}`,
711
628
  ...params ? { query: params } : {}
712
629
  });
713
630
  }
714
631
  /**
715
- * Get a LinkedIn member profile by id or public handle.
716
- * `GET /v1/profiles/{profile_id}`
717
- * Pass `{ notify: true }` to signal a profile view.
718
- * The `account_id` is injected by the account-scoped context.
632
+ * Update the caller's own profile. `PATCH /v1/{account_id}/users/{user_id}`
633
+ * Only `first_name`, `last_name`, `bio`, `headline`, `skills`, `picture`,
634
+ * `background_picture` are accepted — there is no `description` key.
635
+ * `description` is not part of the update contract: TypeScript already
636
+ * rejects it at the call site, but an untyped/JS caller (or an `as`-cast)
637
+ * could still smuggle it onto the object, so it is also stripped
638
+ * defensively at runtime before the request goes out — the caller's
639
+ * object is never mutated.
640
+ */
641
+ update(userId, body) {
642
+ const { description: _description, ...safeBody } = body;
643
+ return this.ctx.request({
644
+ method: "PATCH",
645
+ path: `/v1/{account_id}/users/${userId}`,
646
+ body: safeBody
647
+ });
648
+ }
649
+ /**
650
+ * List the account's 1st-degree connections.
651
+ * `GET /v1/{account_id}/profiles/relations` (served URL keeps `profiles/`).
652
+ * Was `profiles.listConnections`.
719
653
  */
720
- get(profileId, params) {
654
+ listRelations(params) {
721
655
  return this.ctx.request({
722
656
  method: "GET",
723
- path: `/v1/profiles/${profileId}`,
657
+ path: "/v1/{account_id}/profiles/relations",
724
658
  ...params ? { query: params } : {}
725
659
  });
726
660
  }
727
- /** List the account's 1st-degree connections. `GET /v1/profiles/relations` */
728
- listConnections(params) {
661
+ /** List a user's followers. `GET /v1/{account_id}/users/{user_id}/followers` */
662
+ listFollowers(userId, params) {
729
663
  return this.ctx.request({
730
664
  method: "GET",
731
- path: "/v1/profiles/relations",
665
+ path: `/v1/{account_id}/users/${userId}/followers`,
732
666
  ...params ? { query: params } : {}
733
667
  });
734
668
  }
735
- /** List a profile's followers. `GET /v1/profiles/{profile_id}/followers` */
736
- listFollowers(profileId, params) {
669
+ /** List who a user follows. `GET /v1/{account_id}/users/{user_id}/following` */
670
+ listFollowing(userId, params) {
737
671
  return this.ctx.request({
738
672
  method: "GET",
739
- path: `/v1/profiles/${profileId}/followers`,
673
+ path: `/v1/{account_id}/users/${userId}/following`,
740
674
  ...params ? { query: params } : {}
741
675
  });
742
676
  }
743
677
  /**
744
- * List a profile's posts. `GET /v1/profiles/{profile_id}/posts`
745
- * Pass `{ is_company: true }` for company posts.
678
+ * Follow a user (bodyless). `POST /v1/{account_id}/users/{user_id}/follow`
679
+ * If the target's profile is private, sends a connect request instead and
680
+ * returns `connect_request_sent`.
746
681
  */
747
- listPosts(profileId, params) {
682
+ follow(userId) {
748
683
  return this.ctx.request({
749
- method: "GET",
750
- path: `/v1/profiles/${profileId}/posts`,
751
- ...params ? { query: params } : {}
684
+ method: "POST",
685
+ path: `/v1/{account_id}/users/${userId}/follow`
752
686
  });
753
687
  }
754
- /** List a profile's comments. `GET /v1/profiles/{profile_id}/comments` */
755
- listComments(profileId, params) {
688
+ /**
689
+ * Unfollow a user (bodyless). `DELETE /v1/{account_id}/users/{user_id}/follow`
690
+ * Idempotent — unfollowing a user this account does not currently follow
691
+ * still returns 200.
692
+ */
693
+ unfollow(userId) {
756
694
  return this.ctx.request({
757
- method: "GET",
758
- path: `/v1/profiles/${profileId}/comments`,
759
- ...params ? { query: params } : {}
695
+ method: "DELETE",
696
+ path: `/v1/{account_id}/users/${userId}/follow`
760
697
  });
761
698
  }
762
- /** List a profile's reactions. `GET /v1/profiles/{profile_id}/reactions` */
763
- listReactions(profileId, params) {
699
+ /**
700
+ * Get remaining InMail credits across subscribed LinkedIn premium products.
701
+ * `GET /v1/{account_id}/inmail-credits`
702
+ * Relocated from `messaging.getInMailBalance`.
703
+ */
704
+ getInMailCredits(params) {
764
705
  return this.ctx.request({
765
706
  method: "GET",
766
- path: `/v1/profiles/${profileId}/reactions`,
707
+ path: "/v1/{account_id}/inmail-credits",
767
708
  ...params ? { query: params } : {}
768
709
  });
769
710
  }
770
- /** Endorse a skill on a profile. `POST /v1/profiles/{profile_id}/endorse` */
771
- endorse(profileId, body) {
711
+ /**
712
+ * Endorse one specific skill on a target member's profile.
713
+ * `POST /v1/{account_id}/users/{user_id}/endorse-skill`
714
+ * Body key is `endorsement_id` (was `skill_endorsement_id` on `profiles.endorse`).
715
+ * Obtain it from `GET /v1/{account_id}/users/{user_id}?linkedin_sections=linkedin_skills`.
716
+ */
717
+ endorseSkill(userId, body) {
772
718
  return this.ctx.request({
773
719
  method: "POST",
774
- path: `/v1/profiles/${profileId}/endorse`,
775
- body,
776
- accountIdIn: "body"
720
+ path: `/v1/{account_id}/users/${userId}/endorse-skill`,
721
+ body
777
722
  });
778
723
  }
779
724
  };
@@ -783,398 +728,468 @@ var InvitesResource = class {
783
728
  constructor(ctx) {
784
729
  this.ctx = ctx;
785
730
  }
786
- /** Send a connection invitation. `POST /v1/invites` */
731
+ /** Send a connect-request. `POST /v1/{account_id}/invites` */
787
732
  send(body) {
788
733
  return this.ctx.request({
789
734
  method: "POST",
790
- path: "/v1/invites",
791
- body,
792
- accountIdIn: "body"
735
+ path: "/v1/{account_id}/invites",
736
+ body
793
737
  });
794
738
  }
795
- /** List sent invitations. `GET /v1/invites/sent` */
739
+ /** List sent connect-requests. `GET /v1/{account_id}/invites/sent` */
796
740
  listSent(params) {
797
741
  return this.ctx.request({
798
742
  method: "GET",
799
- path: "/v1/invites/sent",
743
+ path: "/v1/{account_id}/invites/sent",
800
744
  ...params ? { query: params } : {}
801
745
  });
802
746
  }
803
- /** List received invitations. `GET /v1/invites/received` */
747
+ /** List received connect-requests. `GET /v1/{account_id}/invites/received` */
804
748
  listReceived(params) {
805
749
  return this.ctx.request({
806
750
  method: "GET",
807
- path: "/v1/invites/received",
751
+ path: "/v1/{account_id}/invites/received",
808
752
  ...params ? { query: params } : {}
809
753
  });
810
754
  }
811
755
  /**
812
- * Accept or decline a received invitation.
813
- * `POST /v1/invites/received/{invitation_id}`
756
+ * Accept a received connect-request (bodyless). An unrecognized or
757
+ * non-pending `invitationId` returns `status: "not_found"`, not an error.
758
+ * `POST /v1/{account_id}/invites/received/{invitation_id}/accept`
814
759
  */
815
- respond(invitationId, body) {
760
+ accept(invitationId) {
816
761
  return this.ctx.request({
817
762
  method: "POST",
818
- path: `/v1/invites/received/${invitationId}`,
819
- body,
820
- accountIdIn: "body"
763
+ path: `/v1/{account_id}/invites/received/${invitationId}/accept`
764
+ });
765
+ }
766
+ /**
767
+ * Decline a received connect-request (bodyless). An unrecognized or
768
+ * non-pending `invitationId` returns `status: "not_found"`, not an error.
769
+ * `POST /v1/{account_id}/invites/received/{invitation_id}/decline`
770
+ */
771
+ decline(invitationId) {
772
+ return this.ctx.request({
773
+ method: "POST",
774
+ path: `/v1/{account_id}/invites/received/${invitationId}/decline`
821
775
  });
822
776
  }
823
- /** Cancel a sent invitation. `DELETE /v1/invites/{invitation_id}` */
777
+ /**
778
+ * Withdraw a sent connect-request (bodyless). An already-absent or
779
+ * unrecognized `invitationId` returns `status: "not_found"`, not an error.
780
+ * `DELETE /v1/{account_id}/invites/sent/{invitation_id}`
781
+ */
824
782
  cancel(invitationId) {
825
783
  return this.ctx.request({
826
784
  method: "DELETE",
827
- path: `/v1/invites/${invitationId}`
785
+ path: `/v1/{account_id}/invites/sent/${invitationId}`
828
786
  });
829
787
  }
830
788
  };
831
789
 
832
790
  // src/resources/search.ts
791
+ function splitPagination(merged) {
792
+ const { cursor, limit, offset, ...body } = merged;
793
+ const hasQuery = cursor !== void 0 || limit !== void 0 || offset !== void 0;
794
+ return {
795
+ body,
796
+ ...hasQuery ? {
797
+ query: {
798
+ ...cursor !== void 0 ? { cursor } : {},
799
+ ...limit !== void 0 ? { limit } : {},
800
+ ...offset !== void 0 ? { offset } : {}
801
+ }
802
+ } : {}
803
+ };
804
+ }
833
805
  var SearchResource = class {
834
806
  constructor(ctx) {
835
807
  this.ctx = ctx;
836
808
  }
837
809
  /**
838
810
  * Resolve human-readable terms to opaque filter IDs for structured search.
839
- * `GET /v1/search/parameters`
811
+ * `GET /v1/{account_id}/search/parameters`
840
812
  */
841
813
  getParameters(query) {
842
814
  return this.ctx.request({
843
815
  method: "GET",
844
- path: "/v1/search/parameters",
816
+ path: "/v1/{account_id}/search/parameters",
845
817
  query
846
818
  });
847
819
  }
848
820
  /**
849
- * Search people with structured filters or a pasted URL.
850
- * `POST /v1/search/people`
851
- * Cursor passed via query param (not body) — matches the OpenAPI spec.
821
+ * Search people with structured filters.
822
+ * `POST /v1/{account_id}/search/people`
823
+ * `offset`/`limit`/`cursor` are top-level query params, never in the body.
852
824
  */
853
825
  people(body) {
854
- const { cursor, limit, ...rest } = body;
826
+ const split = splitPagination(body);
855
827
  return this.ctx.request({
856
828
  method: "POST",
857
- path: "/v1/search/people",
858
- body: rest,
859
- ...cursor !== void 0 || limit !== void 0 ? { query: { ...cursor !== void 0 ? { cursor } : {}, ...limit !== void 0 ? { limit } : {} } } : {}
829
+ path: "/v1/{account_id}/search/people",
830
+ body: split.body,
831
+ ...split.query ? { query: split.query } : {}
860
832
  });
861
833
  }
862
834
  /**
863
- * Search companies.
864
- * `POST /v1/search/companies`
835
+ * Search companies with structured filters.
836
+ * `POST /v1/{account_id}/search/companies`
865
837
  */
866
838
  companies(body) {
867
- const { cursor, limit, ...rest } = body;
839
+ const split = splitPagination(body);
868
840
  return this.ctx.request({
869
841
  method: "POST",
870
- path: "/v1/search/companies",
871
- body: rest,
872
- ...cursor !== void 0 || limit !== void 0 ? { query: { ...cursor !== void 0 ? { cursor } : {}, ...limit !== void 0 ? { limit } : {} } } : {}
842
+ path: "/v1/{account_id}/search/companies",
843
+ body: split.body,
844
+ ...split.query ? { query: split.query } : {}
873
845
  });
874
846
  }
875
847
  /**
876
- * Search posts.
877
- * `POST /v1/search/posts`
848
+ * Search posts with structured filters.
849
+ * `POST /v1/{account_id}/search/posts`
878
850
  */
879
851
  posts(body) {
880
- const { cursor, limit, ...rest } = body;
852
+ const split = splitPagination(body);
881
853
  return this.ctx.request({
882
854
  method: "POST",
883
- path: "/v1/search/posts",
884
- body: rest,
885
- ...cursor !== void 0 || limit !== void 0 ? { query: { ...cursor !== void 0 ? { cursor } : {}, ...limit !== void 0 ? { limit } : {} } } : {}
855
+ path: "/v1/{account_id}/search/posts",
856
+ body: split.body,
857
+ ...split.query ? { query: split.query } : {}
886
858
  });
887
859
  }
888
860
  /**
889
- * Search jobs.
890
- * `POST /v1/search/jobs`
861
+ * Search jobs with structured filters.
862
+ * `POST /v1/{account_id}/search/jobs`
891
863
  */
892
864
  jobs(body) {
893
- const { cursor, limit, ...rest } = body;
865
+ const split = splitPagination(body);
894
866
  return this.ctx.request({
895
867
  method: "POST",
896
- path: "/v1/search/jobs",
897
- body: rest,
898
- ...cursor !== void 0 || limit !== void 0 ? { query: { ...cursor !== void 0 ? { cursor } : {}, ...limit !== void 0 ? { limit } : {} } } : {}
868
+ path: "/v1/{account_id}/search/jobs",
869
+ body: split.body,
870
+ ...split.query ? { query: split.query } : {}
871
+ });
872
+ }
873
+ /**
874
+ * Run a pasted LinkedIn search/saved-search/lead-list URL directly.
875
+ * `POST /v1/{account_id}/search`
876
+ * `url` is the ONLY accepted body field — the sole home of URL-mode search;
877
+ * the structured endpoints above no longer accept `url`. The response is
878
+ * polymorphic, each item discriminated individually by its own `object`.
879
+ */
880
+ fromUrl(body) {
881
+ const { cursor, limit, offset, url } = body;
882
+ const hasQuery = cursor !== void 0 || limit !== void 0 || offset !== void 0;
883
+ return this.ctx.request({
884
+ method: "POST",
885
+ path: "/v1/{account_id}/search",
886
+ body: { url },
887
+ ...hasQuery ? {
888
+ query: {
889
+ ...cursor !== void 0 ? { cursor } : {},
890
+ ...limit !== void 0 ? { limit } : {},
891
+ ...offset !== void 0 ? { offset } : {}
892
+ }
893
+ } : {}
899
894
  });
900
895
  }
901
896
  };
902
897
 
903
898
  // src/resources/posts.ts
904
- function buildFormData2(scalars, attachments) {
905
- const form = new FormData();
906
- for (const [key, value] of Object.entries(scalars)) {
907
- if (value !== void 0 && value !== null) {
908
- form.append(key, String(value));
909
- }
910
- }
911
- for (const attachment of attachments ?? []) {
912
- if (attachment instanceof File) {
913
- form.append("attachments", attachment);
914
- } else {
915
- form.append("attachments", new Blob([attachment]));
916
- }
917
- }
918
- return form;
919
- }
920
899
  var PostsResource = class {
921
900
  constructor(ctx) {
922
901
  this.ctx = ctx;
923
902
  }
924
- /** List the account's own posts. `GET /v1/posts` */
925
- list(params) {
903
+ /** List comments on a post. `GET /v1/{account_id}/posts/{post_id}/comments` */
904
+ listComments(postId, params) {
926
905
  return this.ctx.request({
927
906
  method: "GET",
928
- path: "/v1/posts",
907
+ path: `/v1/{account_id}/posts/${postId}/comments`,
929
908
  ...params ? { query: params } : {}
930
909
  });
931
910
  }
911
+ /** Get a single post. `GET /v1/{account_id}/posts/{post_id}` */
912
+ get(postId) {
913
+ return this.ctx.request({
914
+ method: "GET",
915
+ path: `/v1/{account_id}/posts/${postId}`
916
+ });
917
+ }
918
+ /** Delete a post (bodyless, 204). `DELETE /v1/{account_id}/posts/{post_id}` */
919
+ delete(postId) {
920
+ return this.ctx.request({
921
+ method: "DELETE",
922
+ path: `/v1/{account_id}/posts/${postId}`
923
+ });
924
+ }
932
925
  /**
933
- * Create a new post. Always sent as multipart/form-data (the API only accepts
934
- * multipart for this endpoint). `POST /v1/posts`
926
+ * Publish a new post. Always `application/json` — attachments (if any) are
927
+ * base64-encoded objects, never `FormData`/multipart.
928
+ * `POST /v1/{account_id}/posts`
935
929
  */
936
930
  create(body) {
937
- const { attachments, video_thumbnail, ...scalars } = body;
938
- const form = buildFormData2(scalars, attachments);
939
- if (video_thumbnail) {
940
- if (video_thumbnail instanceof File) {
941
- form.append("video_thumbnail", video_thumbnail);
942
- } else {
943
- form.append("video_thumbnail", new Blob([video_thumbnail]));
944
- }
945
- }
946
931
  return this.ctx.request({
947
932
  method: "POST",
948
- path: "/v1/posts",
949
- body: form,
950
- accountIdIn: "body"
933
+ path: "/v1/{account_id}/posts",
934
+ body
951
935
  });
952
936
  }
953
- /** Get a single post. `GET /v1/posts/{post_id}` */
954
- get(postId) {
937
+ /**
938
+ * List a user's own posts. `GET /v1/{account_id}/users/{user_id}/posts`
939
+ * Was `profiles.listPosts`.
940
+ */
941
+ listUserPosts(userId, params) {
955
942
  return this.ctx.request({
956
943
  method: "GET",
957
- path: `/v1/posts/${postId}`
944
+ path: `/v1/{account_id}/users/${userId}/posts`,
945
+ ...params ? { query: params } : {}
958
946
  });
959
947
  }
960
- /** List comments on a post. `GET /v1/posts/{post_id}/comments` */
961
- listComments(postId, params) {
948
+ /** List reactions on a post. `GET /v1/{account_id}/posts/{post_id}/reactions` */
949
+ listReactions(postId, params) {
962
950
  return this.ctx.request({
963
951
  method: "GET",
964
- path: `/v1/posts/${postId}/comments`,
952
+ path: `/v1/{account_id}/posts/${postId}/reactions`,
965
953
  ...params ? { query: params } : {}
966
954
  });
967
955
  }
956
+ /** React to a post. `POST /v1/{account_id}/posts/{post_id}/reactions` */
957
+ react(postId, body) {
958
+ return this.ctx.request({
959
+ method: "POST",
960
+ path: `/v1/{account_id}/posts/${postId}/reactions`,
961
+ body
962
+ });
963
+ }
968
964
  /**
969
- * Comment on a post. Always sent as multipart/form-data. `POST /v1/posts/{post_id}/comments`
965
+ * Remove this account's reaction from a post — a **DELETE-with-body**:
966
+ * the reaction value to remove travels in the JSON body, not the path.
967
+ * `DELETE /v1/{account_id}/posts/{post_id}/reactions`
970
968
  */
971
- comment(postId, body) {
972
- const { attachments, ...scalars } = body;
969
+ unreact(postId, body) {
973
970
  return this.ctx.request({
974
- method: "POST",
975
- path: `/v1/posts/${postId}/comments`,
976
- body: buildFormData2(scalars, attachments),
977
- accountIdIn: "body"
971
+ method: "DELETE",
972
+ path: `/v1/{account_id}/posts/${postId}/reactions`,
973
+ body
978
974
  });
979
975
  }
980
- /** List reactions on a post. `GET /v1/posts/{post_id}/reactions` */
981
- listReactions(postId, params) {
976
+ /**
977
+ * List a user's reactions. `GET /v1/{account_id}/users/{user_id}/reactions`
978
+ * Was `profiles.listReactions`.
979
+ */
980
+ listUserReactions(userId, params) {
982
981
  return this.ctx.request({
983
982
  method: "GET",
984
- path: `/v1/posts/${postId}/reactions`,
983
+ path: `/v1/{account_id}/users/${userId}/reactions`,
985
984
  ...params ? { query: params } : {}
986
985
  });
987
986
  }
988
- /** React to a post. `POST /v1/posts/{post_id}/reactions` */
989
- react(postId, body) {
987
+ };
988
+
989
+ // src/resources/comments.ts
990
+ var CommentsResource = class {
991
+ constructor(ctx) {
992
+ this.ctx = ctx;
993
+ }
994
+ /**
995
+ * List comments authored by a user, each embedding the post it was made
996
+ * on. `GET /v1/{account_id}/users/{user_id}/comments`
997
+ * Was `profiles.listComments`.
998
+ */
999
+ listUserComments(userId, params) {
1000
+ return this.ctx.request({
1001
+ method: "GET",
1002
+ path: `/v1/{account_id}/users/${userId}/comments`,
1003
+ ...params ? { query: params } : {}
1004
+ });
1005
+ }
1006
+ /**
1007
+ * Publish a comment on a post. `POST /v1/{account_id}/posts/{post_id}/comments`
1008
+ * Was `posts.comment`. Attachments (at most one) travel as a base64
1009
+ * object, never `FormData`.
1010
+ */
1011
+ create(postId, body) {
990
1012
  return this.ctx.request({
991
1013
  method: "POST",
992
- path: `/v1/posts/${postId}/reactions`,
993
- body,
994
- accountIdIn: "body"
1014
+ path: `/v1/{account_id}/posts/${postId}/comments`,
1015
+ body
995
1016
  });
996
1017
  }
997
- };
998
-
999
- // src/resources/sales-navigator.ts
1000
- function buildFormData3(scalars, attachments, voice_message, video_message) {
1001
- const form = new FormData();
1002
- for (const [key, value] of Object.entries(scalars)) {
1003
- if (value !== void 0 && value !== null) {
1004
- if (Array.isArray(value)) {
1005
- for (const item of value) {
1006
- form.append(key, String(item));
1007
- }
1008
- } else {
1009
- form.append(key, String(value));
1010
- }
1011
- }
1018
+ /**
1019
+ * Edit the text of this account's own comment.
1020
+ * `PATCH /v1/{account_id}/posts/{post_id}/comments/{comment_id}`
1021
+ */
1022
+ edit(postId, commentId, body) {
1023
+ return this.ctx.request({
1024
+ method: "PATCH",
1025
+ path: `/v1/{account_id}/posts/${postId}/comments/${commentId}`,
1026
+ body
1027
+ });
1012
1028
  }
1013
- for (const attachment of attachments ?? []) {
1014
- if (attachment instanceof File) {
1015
- form.append("attachments", attachment);
1016
- } else {
1017
- form.append("attachments", new Blob([attachment]));
1018
- }
1029
+ /**
1030
+ * Delete this account's own comment (bodyless, 204).
1031
+ * `DELETE /v1/{account_id}/posts/{post_id}/comments/{comment_id}`
1032
+ */
1033
+ delete(postId, commentId) {
1034
+ return this.ctx.request({
1035
+ method: "DELETE",
1036
+ path: `/v1/{account_id}/posts/${postId}/comments/${commentId}`
1037
+ });
1019
1038
  }
1020
- if (voice_message) {
1021
- if (voice_message instanceof File) {
1022
- form.append("voice_message", voice_message);
1023
- } else {
1024
- form.append("voice_message", new Blob([voice_message]));
1025
- }
1039
+ /**
1040
+ * Reply to a comment. Shares its path with `edit` — POST creates a reply
1041
+ * under the target comment, PATCH edits the target comment's own text.
1042
+ * `POST /v1/{account_id}/posts/{post_id}/comments/{comment_id}`
1043
+ */
1044
+ reply(postId, commentId, body) {
1045
+ return this.ctx.request({
1046
+ method: "POST",
1047
+ path: `/v1/{account_id}/posts/${postId}/comments/${commentId}`,
1048
+ body
1049
+ });
1026
1050
  }
1027
- if (video_message) {
1028
- if (video_message instanceof File) {
1029
- form.append("video_message", video_message);
1030
- } else {
1031
- form.append("video_message", new Blob([video_message]));
1032
- }
1051
+ /**
1052
+ * List replies to a comment, most-recent-first.
1053
+ * `GET /v1/{account_id}/posts/{post_id}/comments/{comment_id}/replies`
1054
+ */
1055
+ listReplies(postId, commentId, params) {
1056
+ return this.ctx.request({
1057
+ method: "GET",
1058
+ path: `/v1/{account_id}/posts/${postId}/comments/${commentId}/replies`,
1059
+ ...params ? { query: params } : {}
1060
+ });
1033
1061
  }
1034
- return form;
1035
- }
1062
+ /**
1063
+ * List reactions on a comment.
1064
+ * `GET /v1/{account_id}/posts/{post_id}/comments/{comment_id}/reactions`
1065
+ */
1066
+ listReactions(postId, commentId, params) {
1067
+ return this.ctx.request({
1068
+ method: "GET",
1069
+ path: `/v1/{account_id}/posts/${postId}/comments/${commentId}/reactions`,
1070
+ ...params ? { query: params } : {}
1071
+ });
1072
+ }
1073
+ /**
1074
+ * React to a comment. `POST /v1/{account_id}/posts/{post_id}/comments/{comment_id}/reactions`
1075
+ */
1076
+ addReaction(postId, commentId, body) {
1077
+ return this.ctx.request({
1078
+ method: "POST",
1079
+ path: `/v1/{account_id}/posts/${postId}/comments/${commentId}/reactions`,
1080
+ body
1081
+ });
1082
+ }
1083
+ /**
1084
+ * Remove this account's reaction from a comment — a **DELETE-with-body**:
1085
+ * the reaction value to remove travels in the JSON body, not the path.
1086
+ * `DELETE /v1/{account_id}/posts/{post_id}/comments/{comment_id}/reactions`
1087
+ */
1088
+ removeReaction(postId, commentId, body) {
1089
+ return this.ctx.request({
1090
+ method: "DELETE",
1091
+ path: `/v1/{account_id}/posts/${postId}/comments/${commentId}/reactions`,
1092
+ body
1093
+ });
1094
+ }
1095
+ };
1096
+
1097
+ // src/resources/sales-navigator.ts
1036
1098
  var SalesNavigatorResource = class {
1037
1099
  constructor(ctx) {
1038
1100
  this.ctx = ctx;
1039
1101
  }
1040
1102
  /**
1041
1103
  * Search LinkedIn members using the full Sales Navigator filter set.
1042
- * `POST /v1/sales-navigator/search/people`
1104
+ * `POST /v1/{account_id}/sales-navigator/search/people`
1043
1105
  * Requires tier `sn`. Returns `TIER_NOT_ACTIVE` (403) when the seat lacks it.
1044
1106
  */
1045
- searchPeople(body, params) {
1107
+ searchPeople(body, query) {
1046
1108
  return this.ctx.request({
1047
1109
  method: "POST",
1048
- path: "/v1/sales-navigator/search/people",
1110
+ path: "/v1/{account_id}/sales-navigator/search/people",
1049
1111
  body,
1050
- ...params ? { query: params } : {}
1112
+ ...query ? { query } : {}
1051
1113
  });
1052
1114
  }
1053
1115
  /**
1054
1116
  * Search LinkedIn companies using the full Sales Navigator company filter set.
1055
- * `POST /v1/sales-navigator/search/companies`
1117
+ * `POST /v1/{account_id}/sales-navigator/search/companies`
1056
1118
  */
1057
- searchCompanies(body, params) {
1119
+ searchCompanies(body, query) {
1058
1120
  return this.ctx.request({
1059
1121
  method: "POST",
1060
- path: "/v1/sales-navigator/search/companies",
1122
+ path: "/v1/{account_id}/sales-navigator/search/companies",
1061
1123
  body,
1062
- ...params ? { query: params } : {}
1124
+ ...query ? { query } : {}
1063
1125
  });
1064
1126
  }
1065
1127
  /**
1066
1128
  * Resolve human-readable terms to opaque Sales Navigator filter IDs.
1067
- * `GET /v1/sales-navigator/search/parameters`
1129
+ * `GET /v1/{account_id}/sales-navigator/search/parameters`
1068
1130
  */
1069
- getParameters(params) {
1131
+ getParameters(query) {
1070
1132
  return this.ctx.request({
1071
1133
  method: "GET",
1072
- path: "/v1/sales-navigator/search/parameters",
1073
- query: params
1134
+ path: "/v1/{account_id}/sales-navigator/search/parameters",
1135
+ query
1074
1136
  });
1075
1137
  }
1076
1138
  /**
1077
- * Start a new Sales Navigator chat. Accepts optional `attachments[]`,
1078
- * `voice_message`, and `video_message` — when present, the request is sent
1079
- * as `multipart/form-data`. `POST /v1/sales-navigator/chats`
1139
+ * Start a new Sales Navigator chat. `attachments[]`, when supplied, carry
1140
+ * base64-encoded file bytes — always sent as JSON, never multipart.
1141
+ * `POST /v1/{account_id}/sales-navigator/chats`
1080
1142
  */
1081
1143
  startChat(body) {
1082
- const { attachments, voice_message, video_message, ...scalars } = body;
1083
- const hasFiles = attachments && attachments.length > 0 || voice_message || video_message;
1084
- if (hasFiles) {
1085
- return this.ctx.request({
1086
- method: "POST",
1087
- path: "/v1/sales-navigator/chats",
1088
- body: buildFormData3(
1089
- scalars,
1090
- attachments,
1091
- voice_message,
1092
- video_message
1093
- ),
1094
- accountIdIn: "body"
1095
- });
1096
- }
1097
1144
  return this.ctx.request({
1098
1145
  method: "POST",
1099
- path: "/v1/sales-navigator/chats",
1100
- body: scalars,
1101
- accountIdIn: "body"
1146
+ path: "/v1/{account_id}/sales-navigator/chats",
1147
+ body
1102
1148
  });
1103
1149
  }
1104
1150
  /**
1105
1151
  * Retrieve a LinkedIn profile with Sales Navigator enrichment.
1106
- * `GET /v1/sales-navigator/profiles/{identifier}`
1107
- */
1108
- getProfile(identifier, params) {
1109
- return this.ctx.request({
1110
- method: "GET",
1111
- path: `/v1/sales-navigator/profiles/${identifier}`,
1112
- // cast needed: linkedin_sections is string[] but transport encodes arrays as repeated params
1113
- ...params ? { query: params } : {}
1114
- });
1115
- }
1116
- /**
1117
- * Save a Sales Navigator member into a lead list.
1118
- * `POST /v1/sales-navigator/lead-lists/{list_id}/save`
1119
- *
1120
- * **BREAKING (2026-07-04):** replaces the retired v1
1121
- * `saveLead(userId, { account_id, list_id? })` — there is no alias. The
1122
- * list is now mandatory and addresses the path; the member id travels in
1123
- * the body alongside `account_id` (the save endpoints carry no query
1124
- * params, so `account_id` has nowhere else to go).
1152
+ * `GET /v1/{account_id}/sales-navigator/profiles/{identifier}`
1125
1153
  */
1126
- saveLead(input) {
1127
- const { list_id, ...body } = input;
1128
- return this.ctx.request({
1129
- method: "POST",
1130
- path: `/v1/sales-navigator/lead-lists/${list_id}/save`,
1131
- body,
1132
- accountIdIn: "body"
1133
- });
1134
- }
1135
- /**
1136
- * Trigger a re-sync of the account's Sales Navigator message history.
1137
- * `GET /v1/sales-navigator/messages/sync`
1138
- */
1139
- syncMessages(params) {
1154
+ getProfile(identifier, query) {
1140
1155
  return this.ctx.request({
1141
1156
  method: "GET",
1142
- path: "/v1/sales-navigator/messages/sync",
1143
- query: params
1157
+ path: `/v1/{account_id}/sales-navigator/profiles/${identifier}`,
1158
+ // cast needed: with_sections is string[] but transport encodes arrays as repeated params
1159
+ ...query ? { query } : {}
1144
1160
  });
1145
1161
  }
1146
- // ─── v2 list surface ──────────────────────────────────────────────────────
1147
1162
  /**
1148
1163
  * List the saved-account (company) lists on the operator's Sales Navigator seat.
1149
- * `GET /v1/sales-navigator/account-lists`
1164
+ * `GET /v1/{account_id}/sales-navigator/account-lists`
1150
1165
  */
1151
1166
  accountLists(query) {
1152
1167
  return this.ctx.request({
1153
1168
  method: "GET",
1154
- path: "/v1/sales-navigator/account-lists",
1169
+ path: "/v1/{account_id}/sales-navigator/account-lists",
1155
1170
  ...query ? { query } : {}
1156
1171
  });
1157
1172
  }
1158
1173
  /**
1159
1174
  * List the saved-lead (member) lists on the operator's Sales Navigator seat.
1160
- * `GET /v1/sales-navigator/lead-lists`
1175
+ * `GET /v1/{account_id}/sales-navigator/lead-lists`
1161
1176
  */
1162
1177
  leadLists(query) {
1163
1178
  return this.ctx.request({
1164
1179
  method: "GET",
1165
- path: "/v1/sales-navigator/lead-lists",
1180
+ path: "/v1/{account_id}/sales-navigator/lead-lists",
1166
1181
  ...query ? { query } : {}
1167
1182
  });
1168
1183
  }
1169
1184
  /**
1170
1185
  * Browse the saved accounts (companies) in one account list. Pass optional
1171
1186
  * `persona` / `filter` / `sort_by` / `sort_order` filters in the body.
1172
- * `POST /v1/sales-navigator/account-lists/{list_id}`
1187
+ * `POST /v1/{account_id}/sales-navigator/account-lists/{list_id}`
1173
1188
  */
1174
1189
  browseAccountList(listId, body, query) {
1175
1190
  return this.ctx.request({
1176
1191
  method: "POST",
1177
- path: `/v1/sales-navigator/account-lists/${listId}`,
1192
+ path: `/v1/{account_id}/sales-navigator/account-lists/${listId}`,
1178
1193
  body: body ?? {},
1179
1194
  ...query ? { query } : {}
1180
1195
  });
@@ -1182,19 +1197,20 @@ var SalesNavigatorResource = class {
1182
1197
  /**
1183
1198
  * Browse the saved leads (members) in one lead list. Pass optional
1184
1199
  * `spotlight` / `sort_by` / `sort_order` filters in the body.
1185
- * `POST /v1/sales-navigator/lead-lists/{list_id}`
1200
+ * `POST /v1/{account_id}/sales-navigator/lead-lists/{list_id}`
1186
1201
  */
1187
1202
  browseLeadList(listId, body, query) {
1188
1203
  return this.ctx.request({
1189
1204
  method: "POST",
1190
- path: `/v1/sales-navigator/lead-lists/${listId}`,
1205
+ path: `/v1/{account_id}/sales-navigator/lead-lists/${listId}`,
1191
1206
  body: body ?? {},
1192
1207
  ...query ? { query } : {}
1193
1208
  });
1194
1209
  }
1195
1210
  /**
1196
- * Save a LinkedIn company into an account list.
1197
- * `POST /v1/sales-navigator/account-lists/{list_id}/save`
1211
+ * Save a LinkedIn company into an account list. Body is just `{company_id}`
1212
+ * — `account_id` lives in the path, not the body.
1213
+ * `POST /v1/{account_id}/sales-navigator/account-lists/{list_id}/save`
1198
1214
  *
1199
1215
  * No `saved` boolean is invented — a `2xx` response body is the success
1200
1216
  * signal (the substrate returns no success flag).
@@ -1203,9 +1219,35 @@ var SalesNavigatorResource = class {
1203
1219
  const { list_id, ...body } = input;
1204
1220
  return this.ctx.request({
1205
1221
  method: "POST",
1206
- path: `/v1/sales-navigator/account-lists/${list_id}/save`,
1222
+ path: `/v1/{account_id}/sales-navigator/account-lists/${list_id}/save`,
1223
+ body
1224
+ });
1225
+ }
1226
+ /**
1227
+ * Save a Sales Navigator member into a lead list. Body is just `{user_id}`
1228
+ * — `account_id` lives in the path, not the body.
1229
+ * `POST /v1/{account_id}/sales-navigator/lead-lists/{list_id}/save`
1230
+ */
1231
+ saveLead(input) {
1232
+ const { list_id, ...body } = input;
1233
+ return this.ctx.request({
1234
+ method: "POST",
1235
+ path: `/v1/{account_id}/sales-navigator/lead-lists/${list_id}/save`,
1236
+ body
1237
+ });
1238
+ }
1239
+ /**
1240
+ * Run a pasted Sales Navigator search/list URL directly.
1241
+ * `POST /v1/{account_id}/sales-navigator/search`
1242
+ * `url` is the only accepted body field. Response items are polymorphic,
1243
+ * each discriminated individually by its own `object`.
1244
+ */
1245
+ searchFromUrl(body, query) {
1246
+ return this.ctx.request({
1247
+ method: "POST",
1248
+ path: "/v1/{account_id}/sales-navigator/search",
1207
1249
  body,
1208
- accountIdIn: "body"
1250
+ ...query ? { query } : {}
1209
1251
  });
1210
1252
  }
1211
1253
  };
@@ -1226,268 +1268,295 @@ function resolveJobId(idOrUrl) {
1226
1268
  }
1227
1269
 
1228
1270
  // src/resources/recruiter.ts
1229
- function buildFormData4(scalars, attachments, voice_message, video_message) {
1230
- const form = new FormData();
1231
- for (const [key, value] of Object.entries(scalars)) {
1232
- if (value !== void 0 && value !== null) {
1233
- if (Array.isArray(value)) {
1234
- for (const item of value) {
1235
- form.append(key, String(item));
1236
- }
1237
- } else {
1238
- form.append(key, String(value));
1239
- }
1240
- }
1241
- }
1242
- for (const attachment of attachments ?? []) {
1243
- if (attachment instanceof File) {
1244
- form.append("attachments", attachment);
1245
- } else {
1246
- form.append("attachments", new Blob([attachment]));
1247
- }
1248
- }
1249
- if (voice_message) {
1250
- if (voice_message instanceof File) {
1251
- form.append("voice_message", voice_message);
1252
- } else {
1253
- form.append("voice_message", new Blob([voice_message]));
1254
- }
1255
- }
1256
- if (video_message) {
1257
- if (video_message instanceof File) {
1258
- form.append("video_message", video_message);
1259
- } else {
1260
- form.append("video_message", new Blob([video_message]));
1261
- }
1262
- }
1263
- return form;
1264
- }
1265
1271
  var RecruiterResource = class {
1266
1272
  constructor(ctx) {
1267
1273
  this.ctx = ctx;
1268
1274
  }
1269
1275
  /**
1270
- * Trigger a re-sync of the account's Recruiter message history.
1271
- * `GET /v1/recruiter/messages/sync`
1276
+ * Retrieve a Recruiter-enriched profile. `{identifier}` is `'me'`, the
1277
+ * target's public identifier, or a member id. Request specific profile
1278
+ * sections via `with_sections` (repeatable query param).
1279
+ * `GET /v1/{account_id}/recruiter/profiles/{user_id}`
1272
1280
  */
1273
- syncMessages(params) {
1281
+ getProfile(identifier, params) {
1274
1282
  return this.ctx.request({
1275
1283
  method: "GET",
1276
- path: "/v1/recruiter/messages/sync",
1277
- query: params
1284
+ path: `/v1/{account_id}/recruiter/profiles/${identifier}`,
1285
+ ...params ? { query: params } : {}
1278
1286
  });
1279
1287
  }
1280
1288
  /**
1281
- * Start a Recruiter chat (InMail). Accepts optional `attachments[]`,
1282
- * `voice_message`, and `video_message` — when present, the request is sent
1283
- * as `multipart/form-data`. `POST /v1/recruiter/chats`
1289
+ * Start a Recruiter chat (InMail). JSON-only — `subject` and `signature`
1290
+ * are REQUIRED; optional attachments ride the body as base64-encoded
1291
+ * objects (no multipart). `POST /v1/{account_id}/recruiter/chats`
1284
1292
  */
1285
1293
  startChat(body) {
1286
- const { attachments, voice_message, video_message, ...scalars } = body;
1287
- const hasFiles = attachments && attachments.length > 0 || voice_message || video_message;
1288
- if (hasFiles) {
1289
- return this.ctx.request({
1290
- method: "POST",
1291
- path: "/v1/recruiter/chats",
1292
- body: buildFormData4(
1293
- scalars,
1294
- attachments,
1295
- voice_message,
1296
- video_message
1297
- ),
1298
- accountIdIn: "body"
1299
- });
1300
- }
1301
1294
  return this.ctx.request({
1302
1295
  method: "POST",
1303
- path: "/v1/recruiter/chats",
1304
- body: scalars,
1305
- accountIdIn: "body"
1296
+ path: "/v1/{account_id}/recruiter/chats",
1297
+ body
1306
1298
  });
1307
1299
  }
1308
1300
  /**
1309
- * Retrieve a LinkedIn profile with Recruiter enrichment.
1310
- * `GET /v1/recruiter/profiles/{identifier}`
1301
+ * Search LinkedIn members using Recruiter filters. `limit`/`cursor` stay
1302
+ * TOP-LEVEL query params. `POST /v1/{account_id}/recruiter/search/people`
1311
1303
  */
1312
- getProfile(identifier, params) {
1304
+ searchPeople(body, params) {
1313
1305
  return this.ctx.request({
1314
- method: "GET",
1315
- path: `/v1/recruiter/profiles/${identifier}`,
1316
- // cast needed: linkedin_sections is string[] but transport encodes arrays as repeated params
1306
+ method: "POST",
1307
+ path: "/v1/{account_id}/recruiter/search/people",
1308
+ body,
1317
1309
  ...params ? { query: params } : {}
1318
1310
  });
1319
1311
  }
1320
1312
  /**
1321
- * Search LinkedIn members using Recruiter filters.
1322
- * `POST /v1/recruiter/search/people`
1313
+ * Resolve human-readable terms to opaque Recruiter filter ids. POST (was
1314
+ * GET): the body is a `source`-discriminated oneOf — `APPLICANTS`/`PIPELINE`
1315
+ * require `project_id`. `POST /v1/{account_id}/recruiter/search/parameters`
1323
1316
  */
1324
- searchPeople(body, params) {
1317
+ searchParameters(body, params) {
1325
1318
  return this.ctx.request({
1326
1319
  method: "POST",
1327
- path: "/v1/recruiter/search/people",
1320
+ path: "/v1/{account_id}/recruiter/search/parameters",
1328
1321
  body,
1329
1322
  ...params ? { query: params } : {}
1330
1323
  });
1331
1324
  }
1332
1325
  /**
1333
- * Resolve human-readable terms to opaque Recruiter filter IDs.
1334
- * `GET /v1/recruiter/search/parameters`
1326
+ * Search a project's talent pool. `channel_id` (the project's own
1327
+ * `RECRUITER_SEARCH` talent-pool channel) is REQUIRED. `limit`/`cursor` stay
1328
+ * TOP-LEVEL query params.
1329
+ * `POST /v1/{account_id}/recruiter/projects/{project_id}/talent-pool/search`
1335
1330
  */
1336
- getParameters(params) {
1331
+ searchTalentPool(projectId, body, params) {
1337
1332
  return this.ctx.request({
1338
- method: "GET",
1339
- path: "/v1/recruiter/search/parameters",
1340
- query: params
1333
+ method: "POST",
1334
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/talent-pool/search`,
1335
+ body,
1336
+ ...params ? { query: params } : {}
1341
1337
  });
1342
1338
  }
1343
1339
  /**
1344
- * List Recruiter hiring projects. `GET /v1/recruiter/projects`
1340
+ * Search from a pasted Recruiter search / talent-pool / applicant URL —
1341
+ * nothing else in the body. The response is a 3-way oneOf (people-search,
1342
+ * job-applicant list, or pipeline-candidate list) keyed by the URL kind.
1343
+ * `POST /v1/{account_id}/recruiter/search`
1344
+ */
1345
+ searchFromUrl(body, params) {
1346
+ return this.ctx.request({
1347
+ method: "POST",
1348
+ path: "/v1/{account_id}/recruiter/search",
1349
+ body,
1350
+ ...params ? { query: params } : {}
1351
+ });
1352
+ }
1353
+ /**
1354
+ * List Recruiter hiring projects visible to the account.
1355
+ * `GET /v1/{account_id}/recruiter/projects`
1345
1356
  */
1346
1357
  listProjects(params) {
1347
1358
  return this.ctx.request({
1348
1359
  method: "GET",
1349
- path: "/v1/recruiter/projects",
1360
+ path: "/v1/{account_id}/recruiter/projects",
1350
1361
  ...params ? { query: params } : {}
1351
1362
  });
1352
1363
  }
1353
1364
  /**
1354
- * Get a single Recruiter hiring project. `GET /v1/recruiter/projects/{project_id}`
1365
+ * Get a single Recruiter hiring project (owner, metadata, talent_pool,
1366
+ * pipeline). `GET /v1/{account_id}/recruiter/projects/{project_id}`
1355
1367
  */
1356
1368
  getProject(projectId) {
1357
1369
  return this.ctx.request({
1358
1370
  method: "GET",
1359
- path: `/v1/recruiter/projects/${projectId}`
1371
+ path: `/v1/{account_id}/recruiter/projects/${projectId}`
1360
1372
  });
1361
1373
  }
1362
1374
  /**
1363
- * Add a member to a hiring project pipeline as a candidate.
1364
- * `POST /v1/recruiter/projects/candidates/{user_id}`
1375
+ * Edit a Recruiter project's config — all fields optional; omitted fields
1376
+ * are left unchanged. Returns a thin acknowledgement only.
1377
+ * `PATCH /v1/{account_id}/recruiter/projects/{project_id}`
1365
1378
  */
1366
- addCandidate(userId, body) {
1379
+ updateProject(projectId, body) {
1367
1380
  return this.ctx.request({
1368
- method: "POST",
1369
- path: `/v1/recruiter/projects/candidates/${userId}`,
1370
- body,
1371
- accountIdIn: "body"
1381
+ method: "PATCH",
1382
+ path: `/v1/{account_id}/recruiter/projects/${projectId}`,
1383
+ body
1372
1384
  });
1373
1385
  }
1374
1386
  /**
1375
- * Add a member to a hiring project pipeline as an applicant.
1376
- * `POST /v1/recruiter/projects/applicants/{user_id}`
1387
+ * List candidates in a project's pipeline (POST-as-list; the body carries
1388
+ * an all-optional filter set, no state mutates). `limit`/`cursor` stay
1389
+ * TOP-LEVEL query params.
1390
+ * `POST /v1/{account_id}/recruiter/projects/{project_id}/pipeline`
1377
1391
  */
1378
- addApplicant(userId, body) {
1392
+ listPipeline(projectId, body = {}, params) {
1379
1393
  return this.ctx.request({
1380
1394
  method: "POST",
1381
- path: `/v1/recruiter/projects/applicants/${userId}`,
1395
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/pipeline`,
1382
1396
  body,
1383
- accountIdIn: "body"
1397
+ ...params ? { query: params } : {}
1384
1398
  });
1385
1399
  }
1386
1400
  /**
1387
- * Reject an applicant from a hiring project.
1388
- * `POST /v1/recruiter/projects/applicants/{user_id}/reject`
1401
+ * Get the single job posting attached to a Recruiter project (the surface
1402
+ * returns one posting, not a list — a project with no attached job 404s).
1403
+ * `GET /v1/{account_id}/recruiter/projects/{project_id}/jobs`
1389
1404
  */
1390
- rejectApplicant(userId, body) {
1405
+ getProjectJob(projectId) {
1391
1406
  return this.ctx.request({
1392
- method: "POST",
1393
- path: `/v1/recruiter/projects/applicants/${userId}/reject`,
1394
- body,
1395
- accountIdIn: "body"
1407
+ method: "GET",
1408
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/jobs`
1396
1409
  });
1397
1410
  }
1398
1411
  /**
1399
- * List Recruiter job postings. `GET /v1/recruiter/jobs`
1412
+ * Create a job-posting DRAFT attached to an EXISTING project — `project_name`
1413
+ * is not accepted (the project comes from the path). Never publishes, never
1414
+ * spends money. `POST /v1/{account_id}/recruiter/projects/{project_id}/jobs`
1400
1415
  */
1401
- listJobs(params) {
1416
+ createProjectJob(projectId, body) {
1402
1417
  return this.ctx.request({
1403
- method: "GET",
1404
- path: "/v1/recruiter/jobs",
1405
- ...params ? { query: params } : {}
1418
+ method: "POST",
1419
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/jobs`,
1420
+ body
1406
1421
  });
1407
1422
  }
1408
1423
  /**
1409
- * Create a Recruiter job posting draft. `POST /v1/recruiter/jobs`
1424
+ * Get pricing to publish a project's job posting — price a publish before
1425
+ * committing any money.
1426
+ * `GET /v1/{account_id}/recruiter/projects/{project_id}/jobs/{job_id}/budget`
1410
1427
  */
1411
- createJob(body) {
1428
+ getProjectJobBudget(projectId, jobId) {
1412
1429
  return this.ctx.request({
1413
- method: "POST",
1414
- path: "/v1/recruiter/jobs",
1415
- body,
1416
- accountIdIn: "body"
1430
+ method: "GET",
1431
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/jobs/${jobId}/budget`
1417
1432
  });
1418
1433
  }
1419
1434
  /**
1420
- * Publish a Recruiter job posting draft.
1421
- * `POST /v1/recruiter/jobs/{job_id}/publish`
1435
+ * Create a job-posting DRAFT together with a brand-new hiring project —
1436
+ * `project_name` is REQUIRED; `description` must be ≥ 200 characters. Never
1437
+ * publishes, never spends money. `POST /v1/{account_id}/recruiter/jobs`
1422
1438
  */
1423
- publishJob(jobId, body) {
1439
+ createJob(body) {
1424
1440
  return this.ctx.request({
1425
1441
  method: "POST",
1426
- path: `/v1/recruiter/jobs/${jobId}/publish`,
1427
- body,
1428
- accountIdIn: "body"
1442
+ path: "/v1/{account_id}/recruiter/jobs",
1443
+ body
1429
1444
  });
1430
1445
  }
1431
1446
  /**
1432
- * Solve a publish verification checkpoint.
1433
- * `POST /v1/recruiter/jobs/{job_id}/checkpoint`
1447
+ * List Recruiter job postings. `limit`/`cursor` stay TOP-LEVEL query params.
1448
+ * `GET /v1/{account_id}/recruiter/jobs`
1434
1449
  */
1435
- solveJobCheckpoint(jobId, body) {
1450
+ listJobs(params) {
1436
1451
  return this.ctx.request({
1437
- method: "POST",
1438
- path: `/v1/recruiter/jobs/${jobId}/checkpoint`,
1439
- body,
1440
- accountIdIn: "body"
1452
+ method: "GET",
1453
+ path: "/v1/{account_id}/recruiter/jobs",
1454
+ ...params ? { query: params } : {}
1441
1455
  });
1442
1456
  }
1443
1457
  /**
1444
- * Get a job posting via the Recruiter lens (any public posting, not only
1445
- * the operator's own). `GET /v1/recruiter/jobs/{job_id}`
1458
+ * Get one Recruiter job posting's full detail (the recruiter-specific
1459
+ * `recruiter_job_posting` shape, carrying `project_id`).
1460
+ * `GET /v1/{account_id}/recruiter/jobs/{job_id}`
1446
1461
  *
1447
- * Accepts a bare numeric job id or a full job URL
1462
+ * Accepts a bare numeric job id or a full LinkedIn job URL
1448
1463
  * (`https://www.linkedin.com/jobs/view/{id}`) — the id is extracted
1449
- * client-side, mirroring `jobs.get()`. Throws
1464
+ * client-side; the wire request always carries the numeric id. Throws
1450
1465
  * `CurviateError({ code: 'INVALID_REQUEST' })` synchronously if neither
1451
- * form can be recognized. Returns the same `JobPosting` shape as
1452
- * `jobs.get()`.
1466
+ * form can be recognized.
1453
1467
  */
1454
1468
  getJob(jobIdOrUrl) {
1455
1469
  const jobId = resolveJobId(jobIdOrUrl);
1456
1470
  return this.ctx.request({
1457
1471
  method: "GET",
1458
- path: `/v1/recruiter/jobs/${jobId}`
1472
+ path: `/v1/{account_id}/recruiter/jobs/${jobId}`
1459
1473
  });
1460
1474
  }
1461
1475
  /**
1462
- * List applicants for a job posting.
1463
- * `GET /v1/recruiter/jobs/{job_id}/applicants`
1476
+ * Apply a partial update to a project's job posting — only included fields
1477
+ * change. MONEY WARNING: editing an already-published (LISTED) posting
1478
+ * mutates a live, money-spending listing.
1479
+ * `PATCH /v1/{account_id}/recruiter/projects/{project_id}/jobs/{job_id}`
1464
1480
  */
1465
- listApplicants(jobId, params) {
1481
+ updateProjectJob(projectId, jobId, body) {
1466
1482
  return this.ctx.request({
1467
- method: "GET",
1468
- path: `/v1/recruiter/jobs/${jobId}/applicants`,
1469
- // cast needed: include_degree / exclude_degree can be string[] but transport encodes arrays as repeated params
1483
+ method: "PATCH",
1484
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/jobs/${jobId}`,
1485
+ body
1486
+ });
1487
+ }
1488
+ /**
1489
+ * Publish a project's job posting draft. `mode` is a discriminated oneOf:
1490
+ * `FREE` (requires free-posting eligibility, spends nothing) or
1491
+ * `PROMOTED`/`PROMOTED_PLUS` (requires `budget` — THIS SPENDS REAL MONEY on
1492
+ * the connected account's LinkedIn payment method; supplying `budget` IS the
1493
+ * explicit opt-in).
1494
+ * `POST /v1/{account_id}/recruiter/projects/{project_id}/jobs/{job_id}/publish`
1495
+ */
1496
+ publishJob(projectId, jobId, body) {
1497
+ return this.ctx.request({
1498
+ method: "POST",
1499
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/jobs/${jobId}/publish`,
1500
+ body
1501
+ });
1502
+ }
1503
+ /**
1504
+ * Close a project's job posting so it stops accepting applications
1505
+ * (bodyless). Closing an already-published (LISTED) posting cannot be
1506
+ * undone — there is no re-open operation.
1507
+ * `POST /v1/{account_id}/recruiter/projects/{project_id}/jobs/{job_id}/close`
1508
+ */
1509
+ closeJob(projectId, jobId) {
1510
+ return this.ctx.request({
1511
+ method: "POST",
1512
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/jobs/${jobId}/close`
1513
+ });
1514
+ }
1515
+ /**
1516
+ * Save a candidate (or user profile) to a project's pipeline at the given
1517
+ * stage — the sole surviving pipeline write.
1518
+ * `POST /v1/{account_id}/recruiter/projects/{project_id}/pipeline/candidate/save`
1519
+ */
1520
+ saveCandidate(projectId, body) {
1521
+ return this.ctx.request({
1522
+ method: "POST",
1523
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/pipeline/candidate/save`,
1524
+ body
1525
+ });
1526
+ }
1527
+ /**
1528
+ * List applicants in a project's talent pool (POST-as-list; the body carries
1529
+ * filters, no state mutates). `channel_id` (a `JOB_POSTING` talent-pool
1530
+ * channel) is REQUIRED. `limit`/`cursor` stay TOP-LEVEL query params.
1531
+ * `POST /v1/{account_id}/recruiter/projects/{project_id}/talent-pool/applicants`
1532
+ */
1533
+ listApplicants(projectId, body, params) {
1534
+ return this.ctx.request({
1535
+ method: "POST",
1536
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/talent-pool/applicants`,
1537
+ body,
1470
1538
  ...params ? { query: params } : {}
1471
1539
  });
1472
1540
  }
1473
1541
  /**
1474
- * Get one job applicant. `GET /v1/recruiter/jobs/applicants/{applicant_id}`
1542
+ * Get full detail for one talent-pool applicant (profile guaranteed full,
1543
+ * includes PII). `GET /v1/{account_id}/recruiter/projects/{project_id}/talent-pool/applicants/{applicant_id}`
1475
1544
  */
1476
- getApplicant(applicantId) {
1545
+ getApplicant(projectId, applicantId) {
1477
1546
  return this.ctx.request({
1478
1547
  method: "GET",
1479
- path: `/v1/recruiter/jobs/applicants/${applicantId}`
1548
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/talent-pool/applicants/${applicantId}`
1480
1549
  });
1481
1550
  }
1482
1551
  /**
1483
- * Download an applicant's resume as raw binary.
1484
- * `GET /v1/recruiter/jobs/applicants/{applicant_id}/resume`
1485
- * Returns `ArrayBuffer` — binary response; the SDK does not cache or store it.
1552
+ * Download a talent-pool applicant's résumé as raw binary.
1553
+ * `GET /v1/{account_id}/recruiter/projects/{project_id}/talent-pool/applicants/{applicant_id}/resume`
1554
+ * Returns `ArrayBuffer` — the SDK does not cache or store it.
1486
1555
  */
1487
- downloadResume(applicantId) {
1556
+ downloadResume(projectId, applicantId) {
1488
1557
  return this.ctx.request({
1489
1558
  method: "GET",
1490
- path: `/v1/recruiter/jobs/applicants/${applicantId}/resume`
1559
+ path: `/v1/{account_id}/recruiter/projects/${projectId}/talent-pool/applicants/${applicantId}/resume`
1491
1560
  });
1492
1561
  }
1493
1562
  };
@@ -1498,24 +1567,137 @@ var JobsResource = class {
1498
1567
  this.ctx = ctx;
1499
1568
  }
1500
1569
  /**
1501
- * Retrieve one public LinkedIn job posting's full detail.
1502
- * `GET /v1/jobs/{job_id}`
1570
+ * List the connected account's own classic job postings.
1571
+ * `GET /v1/{account_id}/jobs`
1572
+ * `state` is REQUIRED — filtering is LinkedIn-side and best-effort (see
1573
+ * the generated type's own field description).
1574
+ */
1575
+ list(params) {
1576
+ return this.ctx.request({
1577
+ method: "GET",
1578
+ path: "/v1/{account_id}/jobs",
1579
+ query: params
1580
+ });
1581
+ }
1582
+ /**
1583
+ * Create a classic job posting DRAFT. Never publishes, never spends money.
1584
+ * `POST /v1/{account_id}/jobs`
1585
+ */
1586
+ create(body) {
1587
+ return this.ctx.request({
1588
+ method: "POST",
1589
+ path: "/v1/{account_id}/jobs",
1590
+ body
1591
+ });
1592
+ }
1593
+ /**
1594
+ * Retrieve one classic LinkedIn job posting's full detail.
1595
+ * `GET /v1/{account_id}/jobs/{job_id}`
1503
1596
  *
1504
1597
  * Accepts a bare numeric job id or a full job URL
1505
1598
  * (`https://www.linkedin.com/jobs/view/{id}`) — the id is extracted
1506
1599
  * client-side; the wire request always carries the numeric id. Throws
1507
1600
  * `CurviateError({ code: 'INVALID_REQUEST' })` synchronously if neither
1508
1601
  * form can be recognized.
1509
- * The `account_id` is injected by the account-scoped context.
1510
1602
  */
1511
1603
  get(jobIdOrUrl, params) {
1512
1604
  const jobId = resolveJobId(jobIdOrUrl);
1513
1605
  return this.ctx.request({
1514
1606
  method: "GET",
1515
- path: `/v1/jobs/${jobId}`,
1607
+ path: `/v1/{account_id}/jobs/${jobId}`,
1516
1608
  ...params ? { query: params } : {}
1517
1609
  });
1518
1610
  }
1611
+ /**
1612
+ * Apply a partial update to a job posting this account owns — only
1613
+ * included fields change. Can affect real money on an already-published
1614
+ * (LISTED) posting. `PATCH /v1/{account_id}/jobs/{job_id}`
1615
+ */
1616
+ update(jobId, body) {
1617
+ return this.ctx.request({
1618
+ method: "PATCH",
1619
+ path: `/v1/{account_id}/jobs/${jobId}`,
1620
+ body
1621
+ });
1622
+ }
1623
+ /**
1624
+ * Get pricing to publish a job posting — price a publish before
1625
+ * committing any money. `GET /v1/{account_id}/jobs/{job_id}/budget`
1626
+ */
1627
+ getBudget(jobId) {
1628
+ return this.ctx.request({
1629
+ method: "GET",
1630
+ path: `/v1/{account_id}/jobs/${jobId}/budget`
1631
+ });
1632
+ }
1633
+ /**
1634
+ * Publish a classic job posting draft. `mode` is a discriminated oneOf:
1635
+ * `FREE` (requires free-posting eligibility, spends nothing) or
1636
+ * `PROMOTED`/`PROMOTED_PLUS` (requires `budget` — THIS SPENDS REAL MONEY
1637
+ * on the connected account's LinkedIn payment method; supplying `budget`
1638
+ * IS the explicit opt-in). `POST /v1/{account_id}/jobs/{job_id}/publish`
1639
+ */
1640
+ publish(jobId, body) {
1641
+ return this.ctx.request({
1642
+ method: "POST",
1643
+ path: `/v1/{account_id}/jobs/${jobId}/publish`,
1644
+ body
1645
+ });
1646
+ }
1647
+ /**
1648
+ * Close a job posting so it stops accepting applications (bodyless).
1649
+ * Closing an already-published (LISTED) posting cannot be undone.
1650
+ * `POST /v1/{account_id}/jobs/{job_id}/close`
1651
+ */
1652
+ close(jobId) {
1653
+ return this.ctx.request({
1654
+ method: "POST",
1655
+ path: `/v1/{account_id}/jobs/${jobId}/close`
1656
+ });
1657
+ }
1658
+ /**
1659
+ * List applicants to a job posting this account owns — a read; POST
1660
+ * carries the filter body, matching the `/search/*` convention. Omit
1661
+ * `ratings` to see the full applicant funnel. `limit`/`cursor` stay
1662
+ * TOP-LEVEL query params, never in the body.
1663
+ * `POST /v1/{account_id}/jobs/{job_id}/applicants`
1664
+ */
1665
+ listApplicants(jobId, params = {}) {
1666
+ const { cursor, limit, ...body } = params;
1667
+ const hasQuery = cursor !== void 0 || limit !== void 0;
1668
+ return this.ctx.request({
1669
+ method: "POST",
1670
+ path: `/v1/{account_id}/jobs/${jobId}/applicants`,
1671
+ body,
1672
+ ...hasQuery ? {
1673
+ query: {
1674
+ ...cursor !== void 0 ? { cursor } : {},
1675
+ ...limit !== void 0 ? { limit } : {}
1676
+ }
1677
+ } : {}
1678
+ });
1679
+ }
1680
+ /**
1681
+ * Get full detail for one applicant, including contact information.
1682
+ * `GET /v1/{account_id}/jobs/{job_id}/applicants/{applicant_id}`
1683
+ */
1684
+ getApplicant(jobId, applicantId) {
1685
+ return this.ctx.request({
1686
+ method: "GET",
1687
+ path: `/v1/{account_id}/jobs/${jobId}/applicants/${applicantId}`
1688
+ });
1689
+ }
1690
+ /**
1691
+ * Download an applicant's résumé. Returns raw binary.
1692
+ * `GET /v1/{account_id}/jobs/{job_id}/applicants/{applicant_id}/resume`
1693
+ * Returns `ArrayBuffer` — the SDK does not cache or store it.
1694
+ */
1695
+ downloadResume(jobId, applicantId) {
1696
+ return this.ctx.request({
1697
+ method: "GET",
1698
+ path: `/v1/{account_id}/jobs/${jobId}/applicants/${applicantId}/resume`
1699
+ });
1700
+ }
1519
1701
  };
1520
1702
 
1521
1703
  // src/resources/companies.ts
@@ -1525,21 +1707,20 @@ var CompaniesResource = class {
1525
1707
  }
1526
1708
  /**
1527
1709
  * Retrieve a company's full LinkedIn profile.
1528
- * `GET /v1/companies/{identifier}`
1710
+ * `GET /v1/{account_id}/companies/{identifier}`
1529
1711
  *
1530
1712
  * Accepts a public handle (the slug in `linkedin.com/company/<handle>`,
1531
1713
  * e.g. `t-systems`) or a numeric id (e.g. `1234567`). A URN is not accepted.
1532
- * The `account_id` is injected by the account-scoped context.
1533
1714
  */
1534
1715
  get(identifier) {
1535
1716
  return this.ctx.request({
1536
1717
  method: "GET",
1537
- path: `/v1/companies/${identifier}`
1718
+ path: `/v1/{account_id}/companies/${identifier}`
1538
1719
  });
1539
1720
  }
1540
1721
  /**
1541
1722
  * List people who currently work at the company.
1542
- * `GET /v1/companies/{identifier}/employees`
1723
+ * `GET /v1/{account_id}/companies/{identifier}/employees`
1543
1724
  *
1544
1725
  * A facade over people search with the company filter applied — filter
1545
1726
  * further with `keywords` or `location`. `identifier` must be the
@@ -1549,13 +1730,13 @@ var CompaniesResource = class {
1549
1730
  employees(identifier, params) {
1550
1731
  return this.ctx.request({
1551
1732
  method: "GET",
1552
- path: `/v1/companies/${identifier}/employees`,
1733
+ path: `/v1/{account_id}/companies/${identifier}/employees`,
1553
1734
  ...params ? { query: params } : {}
1554
1735
  });
1555
1736
  }
1556
1737
  /**
1557
1738
  * List the company's posts.
1558
- * `GET /v1/companies/{identifier}/posts`
1739
+ * `GET /v1/{account_id}/companies/{identifier}/posts`
1559
1740
  *
1560
1741
  * A facade over post search with the company filter applied. `identifier`
1561
1742
  * must be the company's numeric provider_id.
@@ -1563,13 +1744,13 @@ var CompaniesResource = class {
1563
1744
  posts(identifier, params) {
1564
1745
  return this.ctx.request({
1565
1746
  method: "GET",
1566
- path: `/v1/companies/${identifier}/posts`,
1747
+ path: `/v1/{account_id}/companies/${identifier}/posts`,
1567
1748
  ...params ? { query: params } : {}
1568
1749
  });
1569
1750
  }
1570
1751
  /**
1571
1752
  * List the company's open job postings.
1572
- * `GET /v1/companies/{identifier}/jobs`
1753
+ * `GET /v1/{account_id}/companies/{identifier}/jobs`
1573
1754
  *
1574
1755
  * A facade over job search with the company filter applied — filter
1575
1756
  * further with `keywords`. An empty `items[]` is a valid result (the
@@ -1579,22 +1760,7 @@ var CompaniesResource = class {
1579
1760
  jobs(identifier, params) {
1580
1761
  return this.ctx.request({
1581
1762
  method: "GET",
1582
- path: `/v1/companies/${identifier}/jobs`,
1583
- ...params ? { query: params } : {}
1584
- });
1585
- }
1586
- /**
1587
- * List the company's followers.
1588
- * `GET /v1/companies/{identifier}/followers`
1589
- *
1590
- * Native — reuses the same seam that backs `profiles.listFollowers()`.
1591
- * You must be an administrator of the target company page.
1592
- * `identifier` must be the company's numeric provider_id.
1593
- */
1594
- followers(identifier, params) {
1595
- return this.ctx.request({
1596
- method: "GET",
1597
- path: `/v1/companies/${identifier}/followers`,
1763
+ path: `/v1/{account_id}/companies/${identifier}/jobs`,
1598
1764
  ...params ? { query: params } : {}
1599
1765
  });
1600
1766
  }
@@ -1671,29 +1837,19 @@ var WebhooksResource = class {
1671
1837
  path: `/v1/webhooks/${id}`
1672
1838
  });
1673
1839
  }
1674
- /**
1675
- * Return the set of changes since the last known version for a connected account.
1676
- * Enables event-driven state sync without polling the account endpoint.
1677
- * `GET /v1/accounts/{id}/state-diff`
1678
- */
1679
- getStateDiff(accountId, params) {
1680
- return this.ctx.request({
1681
- method: "GET",
1682
- path: `/v1/accounts/${accountId}/state-diff`,
1683
- ...params ? { query: params } : {}
1684
- });
1685
- }
1686
1840
  };
1687
1841
 
1688
1842
  // src/resources/index.ts
1689
1843
  function buildNamespaces(ctx) {
1690
1844
  return {
1691
1845
  accounts: new AccountsResource(ctx),
1846
+ auth: new AuthResource(ctx),
1692
1847
  messaging: new MessagingResource(ctx),
1693
- profiles: new ProfilesResource(ctx),
1848
+ users: new UsersResource(ctx),
1694
1849
  invites: new InvitesResource(ctx),
1695
1850
  search: new SearchResource(ctx),
1696
1851
  posts: new PostsResource(ctx),
1852
+ comments: new CommentsResource(ctx),
1697
1853
  salesNavigator: new SalesNavigatorResource(ctx),
1698
1854
  recruiter: new RecruiterResource(ctx),
1699
1855
  jobs: new JobsResource(ctx),
@@ -1701,9 +1857,23 @@ function buildNamespaces(ctx) {
1701
1857
  webhooks: new WebhooksResource(ctx)
1702
1858
  };
1703
1859
  }
1860
+ function buildRootNamespaces(ctx) {
1861
+ return {
1862
+ accounts: new AccountsResource(ctx),
1863
+ auth: new AuthResource(ctx),
1864
+ webhooks: new WebhooksResource(ctx)
1865
+ };
1866
+ }
1704
1867
  function buildAccountScopedNamespaces(ctx) {
1705
- const { accounts: _accounts, ...rest } = buildNamespaces(ctx);
1868
+ const {
1869
+ accounts: _accounts,
1870
+ auth: _auth,
1871
+ webhooks: _webhooks,
1872
+ ...rest
1873
+ } = buildNamespaces(ctx);
1706
1874
  void _accounts;
1875
+ void _auth;
1876
+ void _webhooks;
1707
1877
  return rest;
1708
1878
  }
1709
1879
 
@@ -1712,17 +1882,9 @@ var Curviate = class {
1712
1882
  constructor(config) {
1713
1883
  this.config = resolveConfig(config);
1714
1884
  const ctx = createContext(this.config);
1715
- const ns = buildNamespaces(ctx);
1885
+ const ns = buildRootNamespaces(ctx);
1716
1886
  this.accounts = ns.accounts;
1717
- this.messaging = ns.messaging;
1718
- this.profiles = ns.profiles;
1719
- this.invites = ns.invites;
1720
- this.search = ns.search;
1721
- this.posts = ns.posts;
1722
- this.salesNavigator = ns.salesNavigator;
1723
- this.recruiter = ns.recruiter;
1724
- this.jobs = ns.jobs;
1725
- this.companies = ns.companies;
1887
+ this.auth = ns.auth;
1726
1888
  this.webhooks = ns.webhooks;
1727
1889
  }
1728
1890
  /**
@@ -1753,15 +1915,15 @@ var Curviate = class {
1753
1915
  * Calls `fn` repeatedly, injecting the `cursor` from each response into the
1754
1916
  * next call, yielding individual items until `cursor` is null.
1755
1917
  *
1756
- * @param fn - a bound resource method (e.g. `profiles.listConnections.bind(profiles)`)
1918
+ * @param fn - a bound resource method (e.g. `users.listRelations.bind(users)`)
1757
1919
  * @param params - the initial params (minus cursor)
1758
1920
  *
1759
1921
  * @example
1760
- * for await (const profile of curviate.paginate(
1761
- * curviate.account('acc_123').profiles.listConnections,
1922
+ * for await (const relation of curviate.paginate(
1923
+ * curviate.account('acc_123').users.listRelations,
1762
1924
  * { limit: 50 }
1763
1925
  * )) {
1764
- * console.log(profile);
1926
+ * console.log(relation);
1765
1927
  * }
1766
1928
  */
1767
1929
  paginate(fn, params) {