@joymerrevent/porters-connect 0.23.0 → 0.24.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/CHANGELOG.md CHANGED
@@ -5,6 +5,85 @@
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.24.0] - 2026-09-24
9
+
10
+ **トークンの取り方と置き場所を別々に渡せるようにした版**です。**破壊的変更を 2 つ**含みます
11
+ (構築オプション `auth` の廃止と、日時(`DateTime`)に渡す値の制限)。あわせて、Refresh Token が拒否されたときに
12
+ 回復しなかった不具合を直し、使い方ドキュメントを実装と突き合わせて直しました。
13
+
14
+ ### Changed
15
+
16
+ - **(破壊的)トークンの取り方を `tokenProvider` で、置き場所を `tokenStore` で別々に渡すようになりました**
17
+ ([ADR-0091][adr91])。キャッシュ・期限の判断・失効時の取り直し・同時呼び出しの 1 本化・`tokenStore` への保存は、
18
+ 既定の取り方でも、渡した取り方でもクライアントが受け持ちます。これまで取り方を差し替えるには
19
+ `getAccessToken` を丸ごと自前で書くしかなく、期限の判断や同時呼び出しのまとめ方まで利用者の実装に任されていました。
20
+
21
+ ```ts
22
+ // 変更前
23
+ const porters = new PortersClient({
24
+ hostname,
25
+ auth: { getAccessToken: async () => await myTokenService.get() },
26
+ });
27
+
28
+ // 変更後
29
+ const porters = new PortersClient({
30
+ hostname,
31
+ tokenProvider: {
32
+ acquire: async () => ({
33
+ accessToken: { token: await myTokenService.get() },
34
+ }),
35
+ },
36
+ });
37
+ ```
38
+
39
+ - `TokenProvider` は `{ acquire, refresh?, exchange? }` です。`acquire` は必須、`refresh` と `exchange` は
40
+ 使うときだけ渡します。期限(`expiresAt`)を返せば、その 60 秒前に取り直します。
41
+ - **構築オプション `auth` は無くなりました**。`auth` や、`getAccessToken` だけを持つ古い形を渡すと、構築時に
42
+ `PortersConfigError`(`category: "config"`)で止まります(型でも弾きます)。
43
+ - **`StoredTokens` の形が変わりました**: `{ accessToken: { token, expiresAt? }, refreshToken?: { token, expiresAt? } }`。
44
+ `tokenStore` に以前の形で保存されていた値は「保存なし」として扱い、上げた直後の 1 回だけ `code_direct` で
45
+ 取り直します(保存先を手で消す必要はありません)。
46
+ - `tokenStore` は `tokenProvider` を渡したときも使われます。
47
+ - `porters.auth` の 6 メソッドは、どの取り方でも動きます。`exchangeAuthorizationCode` には `tokenProvider` の
48
+ `exchange` が、`authorizationUrl` / `revokeUrl` には `appId` が要ります。
49
+ - 既定の取り方で `appId` / `appSecret` が無いときは、PORTERS へ何も送らずに `PortersConfigError` になります。
50
+ - 保存済みの Access Token がまだ有効なら、起動直後にも取りに行きません。
51
+ - `GetAccessTokenOptions` を公開 API から外し、`IssuedToken`(`{ token, expiresAt? }`)を足しました。
52
+ - 書き方は[認証とトークン][oauth-guide]の「トークンの取り方を差し替える」にあります。
53
+
54
+ - **(破壊的)日時(`DateTime` / `System[DateTime]`)の項目に書く値と、`condition` に書く値は、時刻とタイムゾーンの
55
+ そろった ISO 8601 だけを受け付けるようになりました**。形は `YYYY-MM-DDTHH:MM[:SS[.sss]]` に `Z` か `±HH:MM` が
56
+ 付いたものです。`new Date().toISOString()` の出力はそのまま渡せます。
57
+
58
+ これまでは、次の値が送る前に止まらず、**ずれた値が PORTERS に届いていました**。
59
+
60
+ | 渡した値 | これまで(実行環境が日本時間のとき) | これから |
61
+ | ---------------------------------------- | ------------------------------------ | -------------------- |
62
+ | `"2026/09/10"`(PORTERS の形式) | `2026/09/09 15:00:00` として送る | `PortersConfigError` |
63
+ | `"2026-09-10T12:00:00"`(ゾーン無し) | 実行環境のタイムゾーンで読んで送る | `PortersConfigError` |
64
+ | `"2026-09-10"`(日付だけ) | UTC の 0 時として送る | `PortersConfigError` |
65
+ | `"2026-02-30T00:00:00Z"` / `…T24:00:00Z` | 3/2・翌日に繰り上げて送る | `PortersConfigError` |
66
+ - エラーは `PortersConfigError`(`category: "validation"`)で、`hint` がゾーンの要ることを示します。
67
+ - 日本時間で考えているなら、`"2026-09-10T09:00:00+09:00"` のようにオフセットを付けて渡します。
68
+ - `Date` / `Age` の項目(日付だけ)は変わりません。
69
+
70
+ ### Fixed
71
+
72
+ - **既定の取り方で、PORTERS が Refresh Token を受け付けなかったとき(期限切れ・無効)に、`code_direct` で取り直す
73
+ ようになりました**。手元に記録した期限がまだ先だと、これまでは同じ refresh を繰り返して `PortersAuthError` になり、
74
+ `porters.auth.clearTokens()` を呼ぶまで回復しませんでした。同じ `tokenStore` を使う別のプロセスが先に更新して、
75
+ 手元の Refresh Token が古くなったときにも起きていました。`PortersAuthError` が返るのは、`code_direct` でも
76
+ 取り直せないとき(初回の権限付与が済んでいない・取り消された、App ID / App Secret が違う、など)だけです。
77
+ 渡した `tokenProvider` の失敗は、これまでどおりそのまま届けます。
78
+ - トークンの取得が認証 API の 401 / 402 で失敗したときに、Access Token の期限切れと取り違えて、もう一度取り直しを
79
+ 強いていたのをやめました(失敗する取得を 2 回送っていました)。
80
+ - **使い方ドキュメントを実装と突き合わせ、挙動と食い違っていた記述を直しました**。主なもの:
81
+ `create` を自動で再送しないのは届いたか分からないときだけ/エラーの型と HTTP ステータスの対応/
82
+ Activity の `P_ResourceId` は `expand` できない/Attachment の `search` で絞れるのは `resourceId` だけ/
83
+ 一括書き込みは約 15000 字でも分ける/`base64ToBytes` は読めない文字列で例外を投げる、など。
84
+ トークンの取得や OAuth の URL 作成で出る `PortersConfigError` を、メッセージから
85
+ [トラブルシューティング][troubleshooting]で引けるようにしました。
86
+
8
87
  ## [0.23.0] - 2026-09-24
9
88
 
10
89
  **カスタム項目を宣言で `create` の必須にできるようにした版**です。あわせて、利用者の TypeScript の下限を
@@ -1377,7 +1456,8 @@ Attachment)あるのに、受け口の形が 3 つとも違っていました
1377
1456
  [ref]: docs/usage/reference/README.md
1378
1457
  [kac]: https://keepachangelog.com/en/1.1.0/
1379
1458
  [semver]: https://semver.org/
1380
- [unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.23.0...HEAD
1459
+ [unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.24.0...HEAD
1460
+ [0.24.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.23.0...v0.24.0
1381
1461
  [0.23.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.22.0...v0.23.0
1382
1462
  [0.22.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.21.0...v0.22.0
1383
1463
  [0.21.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.20.1...v0.21.0
@@ -1421,3 +1501,5 @@ Attachment)あるのに、受け口の形が 3 つとも違っていました
1421
1501
  [ref-department]: docs/usage/reference/resource-api/resources/department.md
1422
1502
  [adr89]: docs/adr/0089-custom-field-required-on-create.md
1423
1503
  [adr90]: docs/adr/0090-typescript-floor.md
1504
+ [adr91]: docs/adr/0091-token-provider-and-store.md
1505
+ [troubleshooting]: docs/usage/reference/troubleshooting.md
package/dist/index.d.cts CHANGED
@@ -1,22 +1,42 @@
1
- /** Options for {@link TokenProvider.getAccessToken}. */
2
- type GetAccessTokenOptions = {
3
- /** Force a refresh even if the cached token looks valid (reactive 401/402). */
4
- forceRefresh?: boolean;
1
+ /** One token and, when known, its absolute expiry (epoch ms). No `expiresAt` means "unknown". */
2
+ type IssuedToken = {
3
+ token: string;
4
+ expiresAt?: number;
5
5
  };
6
- /** Supplies a valid Access Token, refreshing transparently when expired. */
7
- type TokenProvider = {
8
- getAccessToken(opts?: GetAccessTokenOptions): Promise<string>;
9
- };
10
- /** Tokens persisted by a {@link TokenStore} (expiry is absolute epoch ms). */
6
+ /**
7
+ * Tokens as obtained from a {@link TokenProvider} and persisted by a {@link TokenStore}.
8
+ * `refreshToken` is present only when the issuer hands one out; a value and its expiry always
9
+ * travel together.
10
+ */
11
11
  type StoredTokens = {
12
- accessToken: string;
13
- refreshToken: string;
14
- accessTokenExpiresAt: number;
15
- refreshTokenExpiresAt: number;
12
+ accessToken: IssuedToken;
13
+ refreshToken?: IssuedToken;
14
+ };
15
+ /**
16
+ * Where tokens come from. Pass one as `tokenProvider` to obtain tokens elsewhere (for example
17
+ * from a central service that holds the App Secret); leave it out for the built-in `code_direct`
18
+ * flow. The client caches what these return, renews shortly before expiry, retries once on an
19
+ * expired-token response, collapses concurrent renewals into one, and saves to `tokenStore`.
20
+ */
21
+ type TokenProvider = {
22
+ /** Obtain tokens from scratch. Called first, and whenever renewal is not possible. */
23
+ acquire(): Promise<StoredTokens>;
24
+ /**
25
+ * Renew tokens. Called instead of {@link TokenProvider.acquire} while `current.refreshToken`
26
+ * is usable — or, when the issuer hands out no refresh token, whenever renewal is needed.
27
+ * Leave it out to renew by calling `acquire` again.
28
+ */
29
+ refresh?(current: StoredTokens): Promise<StoredTokens>;
30
+ /**
31
+ * Exchange an authorization `code` returned to your redirect URL after the browser grant.
32
+ * Needed only for `porters.auth.exchangeAuthorizationCode`. PORTERS expires a `code` 30 seconds
33
+ * after issuing it, so do not do slow work here.
34
+ */
35
+ exchange?(code: string): Promise<StoredTokens>;
16
36
  };
17
37
  /**
18
38
  * Pluggable token persistence (default: in-memory). Async so it can back onto
19
- * redis / DB / file for multi-instance server use.
39
+ * redis / DB / file for multi-instance server use. Used with every token provider.
20
40
  */
21
41
  type TokenStore = {
22
42
  get(): Promise<StoredTokens | undefined>;
@@ -146,18 +166,18 @@ type RevokeUrlOptions = AuthorizationUrlOptions;
146
166
  * The `porters.auth.*` surface. The initial per-Company-DB grant
147
167
  * needs a human to open {@link AuthApi.authorizationUrl} in a browser and consent; the
148
168
  * library only builds the URL and exchanges the returned `code`. Day-to-day token
149
- * acquisition/refresh stays transparent (the default strategy), so most callers never
150
- * touch this surface.
169
+ * acquisition and renewal are handled by the client, whichever token provider is in use, so
170
+ * most callers never touch this surface.
151
171
  */
152
172
  type AuthApi = {
153
173
  /** Build the browser `code`-grant URL to open for the initial permission grant. */
154
174
  authorizationUrl(opts: AuthorizationUrlOptions): string;
155
175
  /**
156
- * Exchange a redirect `?code=` for tokens and save them into the default strategy.
157
- * Resolves `void` on success (tokens are stored internally — inspect via
158
- * {@link AuthApi.getToken}); throws on failure: {@link PortersConfigError} (missing
159
- * credentials / custom strategy), `PortersAuthError` (token-endpoint error or expired
160
- * code), or `PortersNetworkError`.
176
+ * Exchange a redirect `?code=` for tokens through the token provider's `exchange`, and save
177
+ * them (cache and `tokenStore`). Resolves `void` on success (inspect via
178
+ * {@link AuthApi.getToken}); rejects with {@link PortersConfigError} when the provider has no
179
+ * `exchange` or the built-in one lacks `appId` / `appSecret`, `PortersAuthError` (token-endpoint
180
+ * error or expired code), or `PortersNetworkError`.
161
181
  */
162
182
  exchangeAuthorizationCode(code: string): Promise<void>;
163
183
  /**
@@ -2918,10 +2938,21 @@ type PortersClientOptions = {
2918
2938
  appId?: string;
2919
2939
  appSecret?: string;
2920
2940
  scopes?: Scope[];
2921
- /** Custom auth strategy; defaults to the transparent code_direct strategy. */
2922
- auth?: TokenProvider;
2923
- /** Token persistence; defaults to in-memory. */
2941
+ /**
2942
+ * Where tokens come from. Leave it out for the built-in flow (`code_direct` with `appId` /
2943
+ * `appSecret`); pass one to obtain tokens another way — for example from a central service that
2944
+ * holds the App Secret. Either way the client caches, renews before expiry, retries once on an
2945
+ * expired token, and saves to `tokenStore`.
2946
+ */
2947
+ tokenProvider?: TokenProvider;
2948
+ /** Token persistence, used with every token provider; defaults to in-memory. */
2924
2949
  tokenStore?: TokenStore;
2950
+ /**
2951
+ * **Not a client option any more.** Pass a `tokenProvider` (`{ acquire, refresh?, exchange? }`)
2952
+ * instead; the client manages caching and renewal for it. Typed `never` so a leftover `auth`
2953
+ * fails to compile; at runtime the constructor rejects it with {@link PortersConfigError}.
2954
+ */
2955
+ auth?: never;
2925
2956
  /** Injectable HTTP transport; defaults to a fetch-based transport. */
2926
2957
  transport?: Transport;
2927
2958
  /**
@@ -3160,4 +3191,4 @@ declare const decodeTimeOfDay: (iso: string) => string;
3160
3191
  */
3161
3192
  declare const encodeTimeOfDay: (time: string) => string;
3162
3193
 
3163
- export { type Activity, type ActivityCreateInput, type ActivityPage, type ActivityResource, type ActivitySearchQuery, type ActivityUpdateInput, type Attachment, type AttachmentAccessor, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AttachmentWalkQuery, type AuthApi, type AuthorizationUrlOptions, type BulkWriteResult, type BulkWriteResultItem, type Candidate, type CandidateCreateInput, type CandidatePage, type CandidateResource, type CandidateSearchQuery, type CandidateUpdateInput, type Client, type ClientCreateInput, type ClientPage, type ClientResource, type ClientSearchQuery, type ClientUpdateInput, type Condition, type Contact, type ContactCreateInput, type ContactPage, type ContactResource, type ContactSearchQuery, type ContactUpdateInput, type Contract, type ContractCreateInput, type ContractPage, type ContractResource, type ContractSearchQuery, type ContractUpdateInput, type CustomDataType, type CustomFieldResource, type CustomFor, type DeclaredCatalogs, type DeclaredRequiredOf, type DefinedFields, type Department, type DepartmentPage, type DepartmentRef, type DepartmentResource, type DepartmentSearchQuery, type ErrorCategory, type Expand, type ExpandedReadRecord, type FetchTransportOptions, type Field, type FieldAccessor, type FieldBuilder, type FieldCatalogSource, type FieldDecls, type FieldDef, type FieldOptions, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldTypeMismatch, type FieldValue, type FieldVerification, type GenerateFieldDeclsOptions, type GetAccessTokenOptions, type ImageContentType, type ImageOption, type ImageReadRecord, type ImageSelectedValue, type ImageSubField, type ImageValue, type ImageWriteValue, type ItemState, type Job, type JobCreateInput, type JobPage, type JobResource, type JobSearchQuery, type JobUpdateInput, type LinkValue, type MissingField, type MockHandler, type MockReply, type MockTransportOptions, type Opportunity, type OpportunityCreateInput, type OpportunityPage, type OpportunityResource, type OpportunitySearchQuery, type OpportunityUpdateInput, type Option, type OptionResource, type OptionSearchQuery, type Order, type Partition, type PartitionId, type PartitionPage, type PartitionResource, type PartitionSearchQuery, type Phase, type PhaseAccessor, type PhaseCreateInput, type PhasePage, type PhaseResource, type PhaseSearchQuery, type PhaseUpdateInput, PortersAuthError, PortersClient, type PortersClientOptions, PortersConfigError, PortersError, type PortersErrorContext, type PortersErrorOptions, PortersNetworkError, PortersResourceError, type Process, type ProcessCreateInput, type ProcessPage, type ProcessResource, type ProcessSearchQuery, type ProcessUpdateInput, type ReadCustomCatalogOptions, type ReadFieldAlias, type Recruiter, type RecruiterCreateInput, type RecruiterPage, type RecruiterResource, type RecruiterSearchQuery, type RecruiterUpdateInput, type ReferenceMap, type ReferenceRecord, type RequiredFor, type RequiredMismatch, type ResourceName, type ResourcePageOf, type ResourceType, type Resume, type ResumeCreateInput, type ResumePage, type ResumeResource, type ResumeSearchQuery, type ResumeUpdateInput, type RevokeUrlOptions, type Sales, type SalesCreateInput, type SalesPage, type SalesResource, type SalesSearchQuery, type SalesUpdateInput, type Scheme, type Scope, type SearchQuery, type StoredTokens, type TenantCustomCatalog, type TenantOptions, type TenantScope, type Throttle, type ThrottleOptions, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type UndeclarableField, type UndeclarableReason, type UndeclarableTenantField, type UndeclaredField, type UnverifiableResource, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, type VerifyFieldsOptions, assertFieldsMatch, base64ToBytes, bytesToBase64, createFetchTransport, createMockTransport, createThrottle, decodeTimeOfDay, defineFields, encodeTimeOfDay, generateFieldDecls, rawValue, readCustomCatalog, resourceNameOf, resourceValueOf, verifyFields };
3194
+ export { type Activity, type ActivityCreateInput, type ActivityPage, type ActivityResource, type ActivitySearchQuery, type ActivityUpdateInput, type Attachment, type AttachmentAccessor, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AttachmentWalkQuery, type AuthApi, type AuthorizationUrlOptions, type BulkWriteResult, type BulkWriteResultItem, type Candidate, type CandidateCreateInput, type CandidatePage, type CandidateResource, type CandidateSearchQuery, type CandidateUpdateInput, type Client, type ClientCreateInput, type ClientPage, type ClientResource, type ClientSearchQuery, type ClientUpdateInput, type Condition, type Contact, type ContactCreateInput, type ContactPage, type ContactResource, type ContactSearchQuery, type ContactUpdateInput, type Contract, type ContractCreateInput, type ContractPage, type ContractResource, type ContractSearchQuery, type ContractUpdateInput, type CustomDataType, type CustomFieldResource, type CustomFor, type DeclaredCatalogs, type DeclaredRequiredOf, type DefinedFields, type Department, type DepartmentPage, type DepartmentRef, type DepartmentResource, type DepartmentSearchQuery, type ErrorCategory, type Expand, type ExpandedReadRecord, type FetchTransportOptions, type Field, type FieldAccessor, type FieldBuilder, type FieldCatalogSource, type FieldDecls, type FieldDef, type FieldOptions, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldTypeMismatch, type FieldValue, type FieldVerification, type GenerateFieldDeclsOptions, type ImageContentType, type ImageOption, type ImageReadRecord, type ImageSelectedValue, type ImageSubField, type ImageValue, type ImageWriteValue, type IssuedToken, type ItemState, type Job, type JobCreateInput, type JobPage, type JobResource, type JobSearchQuery, type JobUpdateInput, type LinkValue, type MissingField, type MockHandler, type MockReply, type MockTransportOptions, type Opportunity, type OpportunityCreateInput, type OpportunityPage, type OpportunityResource, type OpportunitySearchQuery, type OpportunityUpdateInput, type Option, type OptionResource, type OptionSearchQuery, type Order, type Partition, type PartitionId, type PartitionPage, type PartitionResource, type PartitionSearchQuery, type Phase, type PhaseAccessor, type PhaseCreateInput, type PhasePage, type PhaseResource, type PhaseSearchQuery, type PhaseUpdateInput, PortersAuthError, PortersClient, type PortersClientOptions, PortersConfigError, PortersError, type PortersErrorContext, type PortersErrorOptions, PortersNetworkError, PortersResourceError, type Process, type ProcessCreateInput, type ProcessPage, type ProcessResource, type ProcessSearchQuery, type ProcessUpdateInput, type ReadCustomCatalogOptions, type ReadFieldAlias, type Recruiter, type RecruiterCreateInput, type RecruiterPage, type RecruiterResource, type RecruiterSearchQuery, type RecruiterUpdateInput, type ReferenceMap, type ReferenceRecord, type RequiredFor, type RequiredMismatch, type ResourceName, type ResourcePageOf, type ResourceType, type Resume, type ResumeCreateInput, type ResumePage, type ResumeResource, type ResumeSearchQuery, type ResumeUpdateInput, type RevokeUrlOptions, type Sales, type SalesCreateInput, type SalesPage, type SalesResource, type SalesSearchQuery, type SalesUpdateInput, type Scheme, type Scope, type SearchQuery, type StoredTokens, type TenantCustomCatalog, type TenantOptions, type TenantScope, type Throttle, type ThrottleOptions, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type UndeclarableField, type UndeclarableReason, type UndeclarableTenantField, type UndeclaredField, type UnverifiableResource, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, type VerifyFieldsOptions, assertFieldsMatch, base64ToBytes, bytesToBase64, createFetchTransport, createMockTransport, createThrottle, decodeTimeOfDay, defineFields, encodeTimeOfDay, generateFieldDecls, rawValue, readCustomCatalog, resourceNameOf, resourceValueOf, verifyFields };
package/dist/index.d.ts CHANGED
@@ -1,22 +1,42 @@
1
- /** Options for {@link TokenProvider.getAccessToken}. */
2
- type GetAccessTokenOptions = {
3
- /** Force a refresh even if the cached token looks valid (reactive 401/402). */
4
- forceRefresh?: boolean;
1
+ /** One token and, when known, its absolute expiry (epoch ms). No `expiresAt` means "unknown". */
2
+ type IssuedToken = {
3
+ token: string;
4
+ expiresAt?: number;
5
5
  };
6
- /** Supplies a valid Access Token, refreshing transparently when expired. */
7
- type TokenProvider = {
8
- getAccessToken(opts?: GetAccessTokenOptions): Promise<string>;
9
- };
10
- /** Tokens persisted by a {@link TokenStore} (expiry is absolute epoch ms). */
6
+ /**
7
+ * Tokens as obtained from a {@link TokenProvider} and persisted by a {@link TokenStore}.
8
+ * `refreshToken` is present only when the issuer hands one out; a value and its expiry always
9
+ * travel together.
10
+ */
11
11
  type StoredTokens = {
12
- accessToken: string;
13
- refreshToken: string;
14
- accessTokenExpiresAt: number;
15
- refreshTokenExpiresAt: number;
12
+ accessToken: IssuedToken;
13
+ refreshToken?: IssuedToken;
14
+ };
15
+ /**
16
+ * Where tokens come from. Pass one as `tokenProvider` to obtain tokens elsewhere (for example
17
+ * from a central service that holds the App Secret); leave it out for the built-in `code_direct`
18
+ * flow. The client caches what these return, renews shortly before expiry, retries once on an
19
+ * expired-token response, collapses concurrent renewals into one, and saves to `tokenStore`.
20
+ */
21
+ type TokenProvider = {
22
+ /** Obtain tokens from scratch. Called first, and whenever renewal is not possible. */
23
+ acquire(): Promise<StoredTokens>;
24
+ /**
25
+ * Renew tokens. Called instead of {@link TokenProvider.acquire} while `current.refreshToken`
26
+ * is usable — or, when the issuer hands out no refresh token, whenever renewal is needed.
27
+ * Leave it out to renew by calling `acquire` again.
28
+ */
29
+ refresh?(current: StoredTokens): Promise<StoredTokens>;
30
+ /**
31
+ * Exchange an authorization `code` returned to your redirect URL after the browser grant.
32
+ * Needed only for `porters.auth.exchangeAuthorizationCode`. PORTERS expires a `code` 30 seconds
33
+ * after issuing it, so do not do slow work here.
34
+ */
35
+ exchange?(code: string): Promise<StoredTokens>;
16
36
  };
17
37
  /**
18
38
  * Pluggable token persistence (default: in-memory). Async so it can back onto
19
- * redis / DB / file for multi-instance server use.
39
+ * redis / DB / file for multi-instance server use. Used with every token provider.
20
40
  */
21
41
  type TokenStore = {
22
42
  get(): Promise<StoredTokens | undefined>;
@@ -146,18 +166,18 @@ type RevokeUrlOptions = AuthorizationUrlOptions;
146
166
  * The `porters.auth.*` surface. The initial per-Company-DB grant
147
167
  * needs a human to open {@link AuthApi.authorizationUrl} in a browser and consent; the
148
168
  * library only builds the URL and exchanges the returned `code`. Day-to-day token
149
- * acquisition/refresh stays transparent (the default strategy), so most callers never
150
- * touch this surface.
169
+ * acquisition and renewal are handled by the client, whichever token provider is in use, so
170
+ * most callers never touch this surface.
151
171
  */
152
172
  type AuthApi = {
153
173
  /** Build the browser `code`-grant URL to open for the initial permission grant. */
154
174
  authorizationUrl(opts: AuthorizationUrlOptions): string;
155
175
  /**
156
- * Exchange a redirect `?code=` for tokens and save them into the default strategy.
157
- * Resolves `void` on success (tokens are stored internally — inspect via
158
- * {@link AuthApi.getToken}); throws on failure: {@link PortersConfigError} (missing
159
- * credentials / custom strategy), `PortersAuthError` (token-endpoint error or expired
160
- * code), or `PortersNetworkError`.
176
+ * Exchange a redirect `?code=` for tokens through the token provider's `exchange`, and save
177
+ * them (cache and `tokenStore`). Resolves `void` on success (inspect via
178
+ * {@link AuthApi.getToken}); rejects with {@link PortersConfigError} when the provider has no
179
+ * `exchange` or the built-in one lacks `appId` / `appSecret`, `PortersAuthError` (token-endpoint
180
+ * error or expired code), or `PortersNetworkError`.
161
181
  */
162
182
  exchangeAuthorizationCode(code: string): Promise<void>;
163
183
  /**
@@ -2918,10 +2938,21 @@ type PortersClientOptions = {
2918
2938
  appId?: string;
2919
2939
  appSecret?: string;
2920
2940
  scopes?: Scope[];
2921
- /** Custom auth strategy; defaults to the transparent code_direct strategy. */
2922
- auth?: TokenProvider;
2923
- /** Token persistence; defaults to in-memory. */
2941
+ /**
2942
+ * Where tokens come from. Leave it out for the built-in flow (`code_direct` with `appId` /
2943
+ * `appSecret`); pass one to obtain tokens another way — for example from a central service that
2944
+ * holds the App Secret. Either way the client caches, renews before expiry, retries once on an
2945
+ * expired token, and saves to `tokenStore`.
2946
+ */
2947
+ tokenProvider?: TokenProvider;
2948
+ /** Token persistence, used with every token provider; defaults to in-memory. */
2924
2949
  tokenStore?: TokenStore;
2950
+ /**
2951
+ * **Not a client option any more.** Pass a `tokenProvider` (`{ acquire, refresh?, exchange? }`)
2952
+ * instead; the client manages caching and renewal for it. Typed `never` so a leftover `auth`
2953
+ * fails to compile; at runtime the constructor rejects it with {@link PortersConfigError}.
2954
+ */
2955
+ auth?: never;
2925
2956
  /** Injectable HTTP transport; defaults to a fetch-based transport. */
2926
2957
  transport?: Transport;
2927
2958
  /**
@@ -3160,4 +3191,4 @@ declare const decodeTimeOfDay: (iso: string) => string;
3160
3191
  */
3161
3192
  declare const encodeTimeOfDay: (time: string) => string;
3162
3193
 
3163
- export { type Activity, type ActivityCreateInput, type ActivityPage, type ActivityResource, type ActivitySearchQuery, type ActivityUpdateInput, type Attachment, type AttachmentAccessor, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AttachmentWalkQuery, type AuthApi, type AuthorizationUrlOptions, type BulkWriteResult, type BulkWriteResultItem, type Candidate, type CandidateCreateInput, type CandidatePage, type CandidateResource, type CandidateSearchQuery, type CandidateUpdateInput, type Client, type ClientCreateInput, type ClientPage, type ClientResource, type ClientSearchQuery, type ClientUpdateInput, type Condition, type Contact, type ContactCreateInput, type ContactPage, type ContactResource, type ContactSearchQuery, type ContactUpdateInput, type Contract, type ContractCreateInput, type ContractPage, type ContractResource, type ContractSearchQuery, type ContractUpdateInput, type CustomDataType, type CustomFieldResource, type CustomFor, type DeclaredCatalogs, type DeclaredRequiredOf, type DefinedFields, type Department, type DepartmentPage, type DepartmentRef, type DepartmentResource, type DepartmentSearchQuery, type ErrorCategory, type Expand, type ExpandedReadRecord, type FetchTransportOptions, type Field, type FieldAccessor, type FieldBuilder, type FieldCatalogSource, type FieldDecls, type FieldDef, type FieldOptions, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldTypeMismatch, type FieldValue, type FieldVerification, type GenerateFieldDeclsOptions, type GetAccessTokenOptions, type ImageContentType, type ImageOption, type ImageReadRecord, type ImageSelectedValue, type ImageSubField, type ImageValue, type ImageWriteValue, type ItemState, type Job, type JobCreateInput, type JobPage, type JobResource, type JobSearchQuery, type JobUpdateInput, type LinkValue, type MissingField, type MockHandler, type MockReply, type MockTransportOptions, type Opportunity, type OpportunityCreateInput, type OpportunityPage, type OpportunityResource, type OpportunitySearchQuery, type OpportunityUpdateInput, type Option, type OptionResource, type OptionSearchQuery, type Order, type Partition, type PartitionId, type PartitionPage, type PartitionResource, type PartitionSearchQuery, type Phase, type PhaseAccessor, type PhaseCreateInput, type PhasePage, type PhaseResource, type PhaseSearchQuery, type PhaseUpdateInput, PortersAuthError, PortersClient, type PortersClientOptions, PortersConfigError, PortersError, type PortersErrorContext, type PortersErrorOptions, PortersNetworkError, PortersResourceError, type Process, type ProcessCreateInput, type ProcessPage, type ProcessResource, type ProcessSearchQuery, type ProcessUpdateInput, type ReadCustomCatalogOptions, type ReadFieldAlias, type Recruiter, type RecruiterCreateInput, type RecruiterPage, type RecruiterResource, type RecruiterSearchQuery, type RecruiterUpdateInput, type ReferenceMap, type ReferenceRecord, type RequiredFor, type RequiredMismatch, type ResourceName, type ResourcePageOf, type ResourceType, type Resume, type ResumeCreateInput, type ResumePage, type ResumeResource, type ResumeSearchQuery, type ResumeUpdateInput, type RevokeUrlOptions, type Sales, type SalesCreateInput, type SalesPage, type SalesResource, type SalesSearchQuery, type SalesUpdateInput, type Scheme, type Scope, type SearchQuery, type StoredTokens, type TenantCustomCatalog, type TenantOptions, type TenantScope, type Throttle, type ThrottleOptions, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type UndeclarableField, type UndeclarableReason, type UndeclarableTenantField, type UndeclaredField, type UnverifiableResource, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, type VerifyFieldsOptions, assertFieldsMatch, base64ToBytes, bytesToBase64, createFetchTransport, createMockTransport, createThrottle, decodeTimeOfDay, defineFields, encodeTimeOfDay, generateFieldDecls, rawValue, readCustomCatalog, resourceNameOf, resourceValueOf, verifyFields };
3194
+ export { type Activity, type ActivityCreateInput, type ActivityPage, type ActivityResource, type ActivitySearchQuery, type ActivityUpdateInput, type Attachment, type AttachmentAccessor, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AttachmentWalkQuery, type AuthApi, type AuthorizationUrlOptions, type BulkWriteResult, type BulkWriteResultItem, type Candidate, type CandidateCreateInput, type CandidatePage, type CandidateResource, type CandidateSearchQuery, type CandidateUpdateInput, type Client, type ClientCreateInput, type ClientPage, type ClientResource, type ClientSearchQuery, type ClientUpdateInput, type Condition, type Contact, type ContactCreateInput, type ContactPage, type ContactResource, type ContactSearchQuery, type ContactUpdateInput, type Contract, type ContractCreateInput, type ContractPage, type ContractResource, type ContractSearchQuery, type ContractUpdateInput, type CustomDataType, type CustomFieldResource, type CustomFor, type DeclaredCatalogs, type DeclaredRequiredOf, type DefinedFields, type Department, type DepartmentPage, type DepartmentRef, type DepartmentResource, type DepartmentSearchQuery, type ErrorCategory, type Expand, type ExpandedReadRecord, type FetchTransportOptions, type Field, type FieldAccessor, type FieldBuilder, type FieldCatalogSource, type FieldDecls, type FieldDef, type FieldOptions, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldTypeMismatch, type FieldValue, type FieldVerification, type GenerateFieldDeclsOptions, type ImageContentType, type ImageOption, type ImageReadRecord, type ImageSelectedValue, type ImageSubField, type ImageValue, type ImageWriteValue, type IssuedToken, type ItemState, type Job, type JobCreateInput, type JobPage, type JobResource, type JobSearchQuery, type JobUpdateInput, type LinkValue, type MissingField, type MockHandler, type MockReply, type MockTransportOptions, type Opportunity, type OpportunityCreateInput, type OpportunityPage, type OpportunityResource, type OpportunitySearchQuery, type OpportunityUpdateInput, type Option, type OptionResource, type OptionSearchQuery, type Order, type Partition, type PartitionId, type PartitionPage, type PartitionResource, type PartitionSearchQuery, type Phase, type PhaseAccessor, type PhaseCreateInput, type PhasePage, type PhaseResource, type PhaseSearchQuery, type PhaseUpdateInput, PortersAuthError, PortersClient, type PortersClientOptions, PortersConfigError, PortersError, type PortersErrorContext, type PortersErrorOptions, PortersNetworkError, PortersResourceError, type Process, type ProcessCreateInput, type ProcessPage, type ProcessResource, type ProcessSearchQuery, type ProcessUpdateInput, type ReadCustomCatalogOptions, type ReadFieldAlias, type Recruiter, type RecruiterCreateInput, type RecruiterPage, type RecruiterResource, type RecruiterSearchQuery, type RecruiterUpdateInput, type ReferenceMap, type ReferenceRecord, type RequiredFor, type RequiredMismatch, type ResourceName, type ResourcePageOf, type ResourceType, type Resume, type ResumeCreateInput, type ResumePage, type ResumeResource, type ResumeSearchQuery, type ResumeUpdateInput, type RevokeUrlOptions, type Sales, type SalesCreateInput, type SalesPage, type SalesResource, type SalesSearchQuery, type SalesUpdateInput, type Scheme, type Scope, type SearchQuery, type StoredTokens, type TenantCustomCatalog, type TenantOptions, type TenantScope, type Throttle, type ThrottleOptions, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type UndeclarableField, type UndeclarableReason, type UndeclarableTenantField, type UndeclaredField, type UnverifiableResource, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, type VerifyFieldsOptions, assertFieldsMatch, base64ToBytes, bytesToBase64, createFetchTransport, createMockTransport, createThrottle, decodeTimeOfDay, defineFields, encodeTimeOfDay, generateFieldDecls, rawValue, readCustomCatalog, resourceNameOf, resourceValueOf, verifyFields };