@joymerrevent/porters-connect 0.2.0 → 0.3.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 +36 -1
- package/README.md +19 -2
- package/dist/index.d.ts +52 -7
- package/dist/index.js +159 -33
- package/dist/index.js.map +1 -1
- package/package.json +6 -14
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.3.0] - 2026-06-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **OAuth 公開面 `porters.auth.*`**(ADR-0007 SD-3/SD-6 / ADR-0034・F-1)。初回のブラウザ権限付与とトークン運用を補助します。
|
|
13
|
+
- `authorizationUrl(opts)` / `revokeUrl(opts)` — ブラウザの `code` / `remove` グラント URL を生成(App Secret は URL に出さない)。
|
|
14
|
+
- `exchangeAuthorizationCode(code)` — redirect の `?code=` をトークンに交換し内部保存(成功時 `void`・失敗時 throw)。
|
|
15
|
+
- `clearTokens()` — ローカルの cache + トークンストアを破棄。
|
|
16
|
+
- `ensureAuthenticated()` / `getToken()` — トークンのウォームアップ/取得(Refresh Token は返さない)。カスタム auth ストラテジでも動作。
|
|
17
|
+
- カスタムストラテジ下では credential 依存メソッドが `PortersConfigError`。新規 export 型 `AuthApi` / `AuthorizationUrlOptions` / `RevokeUrlOptions`。利用手順は [docs/guide/oauth.md][oauth-guide]。
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- `PortersClientOptions.partition` の JSDoc 誤記(「overridable per call」)を訂正。per-call 上書きは未対応・予定(ADR-0033)で、partition は構築時に固定です(実行時の挙動変更なし)。
|
|
22
|
+
|
|
23
|
+
## [0.2.1] - 2026-06-22
|
|
24
|
+
|
|
25
|
+
メンテナンスリリース。**公開 API・実行コードの変更はありません**(`src/` 変更なし)。
|
|
26
|
+
主にリリース自動化・CI 整備とドキュメント拡充です。
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- README の Node バッジ表記を `Node >= 18` → `Node >= 20` に修正(`engines` は 0.2.0 で既に `>=20`。バッジの追従漏れを解消し、以後は `check:release` でドリフトを検知)。
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- サポート方針を「最新の `0.1.x` のみ」から「**最新のリリース版のみ**」に更新(SECURITY.md)。
|
|
35
|
+
- リリースを半自動化:`main` マージで自動タグ(`tag.yml`)+ GitHub Release 公開で OIDC publish(`release.yml`)(ADR-0029)。
|
|
36
|
+
- リリース前ゲートを CI に追加:version/CHANGELOG/README バッジのドリフト検査と版番号検証(`check:release`・ADR-0027/0031/0032)。
|
|
37
|
+
- 公開物の健全性検査 `check:publish`(publint/are-the-types-wrong)を追加。
|
|
38
|
+
- docs-only PR の CI を軽量化(ADR-0028)。
|
|
39
|
+
|
|
8
40
|
## [0.2.0] - 2026-06-20
|
|
9
41
|
|
|
10
42
|
### Changed
|
|
@@ -46,9 +78,12 @@
|
|
|
46
78
|
- **配布**: ESM / Node.js 18+ / 型定義同梱 / MIT。`X-P-ConnectAPI-Version: 2` を既定送信(PORTERS 8.x・9.x 想定)。
|
|
47
79
|
|
|
48
80
|
[guide]: docs/guide/error-handling.md
|
|
81
|
+
[oauth-guide]: docs/guide/oauth.md
|
|
49
82
|
[kac]: https://keepachangelog.com/en/1.1.0/
|
|
50
83
|
[semver]: https://semver.org/
|
|
51
|
-
[unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.
|
|
84
|
+
[unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.3.0...HEAD
|
|
85
|
+
[0.3.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.2.1...v0.3.0
|
|
86
|
+
[0.2.1]: https://github.com/Joymerrevent/porters-connect/compare/v0.2.0...v0.2.1
|
|
52
87
|
[0.2.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.1.1...v0.2.0
|
|
53
88
|
[0.1.1]: https://github.com/Joymerrevent/porters-connect/compare/v0.1.0...v0.1.1
|
|
54
89
|
[0.1.0]: https://github.com/Joymerrevent/porters-connect/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @joymerrevent/porters-connect
|
|
2
2
|
|
|
3
|
-
[![npm version][npm-badge]][npm] [![License: MIT][mit-badge]][mit] ![Node >=
|
|
3
|
+
[![npm version][npm-badge]][npm] [![License: MIT][mit-badge]][mit] ![Node >= 20][node-badge]
|
|
4
4
|
|
|
5
5
|
PORTERS Connect API(旧 HRBC)を **TypeScript から型安全・簡単に**扱うための、
|
|
6
6
|
[Joymerrevent(ジョイメリベント)][joymerrevent] 製の **非公式(unofficial)** ラッパーです。
|
|
@@ -29,7 +29,7 @@ XML レスポンスを型付きオブジェクトに変換し、独自仕様の
|
|
|
29
29
|
1. **PORTERS 契約 + Connect API オプション契約**。ホスト名・App ID・App Secret が通知されます。
|
|
30
30
|
2. **初回のみブラウザで権限付与**(人手・1 回)。`response_type=code` で対象 Company DB の権限を付与します。
|
|
31
31
|
これを済ませれば、以降はライブラリが `code_direct`(サーバ間・ブラウザ不要)で無人運用できます。
|
|
32
|
-
|
|
32
|
+
手順は [OAuth 認証ガイド][oauth-guide] を参照(API 仕様は [認証 API のフロー][auth-flow])。
|
|
33
33
|
|
|
34
34
|
## インストール
|
|
35
35
|
|
|
@@ -137,6 +137,22 @@ new PortersClient({ host, appId, appSecret, partition, tokenStore });
|
|
|
137
137
|
|
|
138
138
|
`transport`(HTTP 注入)や `auth`(独自 `TokenProvider`)も差し替え可能です。
|
|
139
139
|
|
|
140
|
+
### 初回の権限付与(`porters.auth.*`)
|
|
141
|
+
|
|
142
|
+
初回だけは人手でブラウザでの権限付与が必要です(「前提」を参照)。ライブラリは認可 URL の生成と `code` 交換を補助します。
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
// 1) 認可 URL を生成 → ユーザーのブラウザで開く(ログイン → 承諾)
|
|
146
|
+
const url = porters.auth.authorizationUrl({
|
|
147
|
+
redirectUrl: "https://app.example.com/porters/callback",
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// 2) redirect で戻る ?code= を交換(30 秒以内)。以後は透過運用に乗る
|
|
151
|
+
await porters.auth.exchangeAuthorizationCode(code);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> 起動時確認 `ensureAuthenticated()`、利用終了 `revokeUrl()` + `clearTokens()`、カスタムストラテジ時の挙動など `porters.auth.*` の全手順は [OAuth 認証ガイド][oauth-guide] にまとめています。
|
|
155
|
+
|
|
140
156
|
## リソースと操作
|
|
141
157
|
|
|
142
158
|
すべてのデータ系リソースは同じ形のアクセサを持ちます。
|
|
@@ -341,6 +357,7 @@ try {
|
|
|
341
357
|
[coc]: ./CODE_OF_CONDUCT.md
|
|
342
358
|
[issues]: https://github.com/Joymerrevent/porters-connect/issues
|
|
343
359
|
[auth-flow]: ./docs/reference/authentication-api/README.md
|
|
360
|
+
[oauth-guide]: ./docs/guide/oauth.md
|
|
344
361
|
[error-handling]: ./docs/guide/error-handling.md
|
|
345
362
|
[sandbox]: ./examples/offline-sandbox.ts
|
|
346
363
|
[adr]: ./docs/adr/README.md
|
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,54 @@ type MockTransportOptions = {
|
|
|
75
75
|
*/
|
|
76
76
|
declare const createMockTransport: (handler: MockHandler, options?: MockTransportOptions) => Transport;
|
|
77
77
|
|
|
78
|
+
/** OAuth scope string: `<resource>_r` (read) or `<resource>_w` (write). */
|
|
79
|
+
type Scope = `${string}_r` | `${string}_w`;
|
|
80
|
+
/** A PORTERS partition (Company DB) id. */
|
|
81
|
+
type PartitionId = number;
|
|
82
|
+
|
|
83
|
+
/** Shared options for the browser `code` / `remove` OAuth URLs (oauth.md). */
|
|
84
|
+
type AuthorizationUrlOptions = {
|
|
85
|
+
/** Registered Redirect URL the browser returns to (required for code/remove). */
|
|
86
|
+
redirectUrl: string;
|
|
87
|
+
/** Scopes to grant/remove; defaults to the client's configured `scopes`. */
|
|
88
|
+
scopes?: Scope[];
|
|
89
|
+
/** Opaque value echoed back on redirect (e.g. CSRF defense). */
|
|
90
|
+
state?: string;
|
|
91
|
+
};
|
|
92
|
+
/** Options for the `remove` (de-authorization) browser URL. */
|
|
93
|
+
type RevokeUrlOptions = AuthorizationUrlOptions;
|
|
94
|
+
/**
|
|
95
|
+
* The `porters.auth.*` surface (ADR-0007 SD-3/SD-6). The initial per-Company-DB grant
|
|
96
|
+
* needs a human to open {@link AuthApi.authorizationUrl} in a browser and consent; the
|
|
97
|
+
* library only builds the URL and exchanges the returned `code`. Day-to-day token
|
|
98
|
+
* acquisition/refresh stays transparent (the default strategy), so most callers never
|
|
99
|
+
* touch this surface.
|
|
100
|
+
*/
|
|
101
|
+
type AuthApi = {
|
|
102
|
+
/** Build the browser `code`-grant URL to open for the initial permission grant. */
|
|
103
|
+
authorizationUrl(opts: AuthorizationUrlOptions): string;
|
|
104
|
+
/**
|
|
105
|
+
* Exchange a redirect `?code=` for tokens and save them into the default strategy.
|
|
106
|
+
* Resolves `void` on success (tokens are stored internally — inspect via
|
|
107
|
+
* {@link AuthApi.getToken}); throws on failure: {@link PortersConfigError} (missing
|
|
108
|
+
* credentials / custom strategy), `PortersAuthError` (token-endpoint error or expired
|
|
109
|
+
* code), or `PortersNetworkError`.
|
|
110
|
+
*/
|
|
111
|
+
exchangeAuthorizationCode(code: string): Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* Build the browser `remove`-grant URL to open for server-side de-authorization.
|
|
114
|
+
* PORTERS has no server-to-server removal, so completing it stays a browser step;
|
|
115
|
+
* pair with {@link AuthApi.clearTokens} to drop the local copy.
|
|
116
|
+
*/
|
|
117
|
+
revokeUrl(opts: RevokeUrlOptions): string;
|
|
118
|
+
/** Forget cached + stored tokens locally. Does not de-authorize server-side. */
|
|
119
|
+
clearTokens(): Promise<void>;
|
|
120
|
+
/** Acquire a token now (startup fail-fast / warm-up); throws if auth is unavailable. */
|
|
121
|
+
ensureAuthenticated(): Promise<void>;
|
|
122
|
+
/** Return the current valid Access Token (debug). The Refresh Token is never exposed. */
|
|
123
|
+
getToken(): Promise<string>;
|
|
124
|
+
};
|
|
125
|
+
|
|
78
126
|
type DataType = "System[Id]" | "Number" | "DateTime" | "System[DateTime]" | "Date" | "Age" | "SinglelineText" | "MultilineText" | "Mail" | "Telephone" | "URL" | "User" | "Option" | "System[Reference]";
|
|
79
127
|
/** A referenced User (Read is nested; Write is `User.P_Id` only). */
|
|
80
128
|
type UserRef = {
|
|
@@ -577,11 +625,6 @@ type CustomFor<C extends DeclaredCatalogs, K extends CustomFieldResource> = K ex
|
|
|
577
625
|
*/
|
|
578
626
|
declare const defineFields: <D extends FieldDecls>(decls: D) => DefinedFields<DeclaredCatalogsOf<D>>;
|
|
579
627
|
|
|
580
|
-
/** OAuth scope string: `<resource>_r` (read) or `<resource>_w` (write). */
|
|
581
|
-
type Scope = `${string}_r` | `${string}_w`;
|
|
582
|
-
/** A PORTERS partition (Company DB) id. */
|
|
583
|
-
type PartitionId = number;
|
|
584
|
-
|
|
585
628
|
/** Options for constructing a {@link PortersClient}. `C` is inferred from `fields` (ADR-0023). */
|
|
586
629
|
type PortersClientOptions<C extends DeclaredCatalogs = EmptyCatalog> = {
|
|
587
630
|
/**
|
|
@@ -592,7 +635,7 @@ type PortersClientOptions<C extends DeclaredCatalogs = EmptyCatalog> = {
|
|
|
592
635
|
appId?: string;
|
|
593
636
|
appSecret?: string;
|
|
594
637
|
scopes?: Scope[];
|
|
595
|
-
/**
|
|
638
|
+
/** Partition (Company DB) used for every call. Per-call override is not yet supported (planned — see ADR-0033). */
|
|
596
639
|
partition?: PartitionId;
|
|
597
640
|
/** Custom auth strategy; defaults to the transparent code_direct strategy. */
|
|
598
641
|
auth?: TokenProvider;
|
|
@@ -620,6 +663,8 @@ declare class PortersClient<C extends DeclaredCatalogs = EmptyCatalog> {
|
|
|
620
663
|
readonly process: ProcessResource<CustomFor<C, "process">>;
|
|
621
664
|
readonly resume: ResumeResource<CustomFor<C, "resume">>;
|
|
622
665
|
readonly attachment: AttachmentResource;
|
|
666
|
+
/** OAuth surface: initial browser grant, token warm-up/inspection, local revoke (ADR-0007/0034). */
|
|
667
|
+
readonly auth: AuthApi;
|
|
623
668
|
/** Master Read: accessible partitions (ADR-0021/0022). */
|
|
624
669
|
readonly partition: PartitionResource;
|
|
625
670
|
/** Master Read: users, plus `current()` self-identification (ADR-0021/0022). */
|
|
@@ -681,4 +726,4 @@ declare const bytesToBase64: (bytes: Uint8Array) => string;
|
|
|
681
726
|
/** Decode a Base64 string back to raw bytes. */
|
|
682
727
|
declare const base64ToBytes: (b64: string) => Uint8Array;
|
|
683
728
|
|
|
684
|
-
export { type Attachment, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, 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 CustomDataType, type DefinedFields, type ErrorCategory, type Field, type FieldBuilder, type FieldDecls, type FieldDef, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldValue, type GetAccessTokenOptions, type Job, type JobCreateInput, type JobPage, type JobResource, type JobSearchQuery, type JobUpdateInput, type MockHandler, type MockReply, type MockTransportOptions, type Option, type OptionResource, type OptionSearchQuery, type Partition, type PartitionId, type PartitionPage, type PartitionResource, type PartitionSearchQuery, 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 ResourceType, type Resume, type ResumeCreateInput, type ResumePage, type ResumeResource, type ResumeSearchQuery, type ResumeUpdateInput, type Scope, type StoredTokens, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, base64ToBytes, bytesToBase64, createMockTransport, defineFields };
|
|
729
|
+
export { type Attachment, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AuthApi, type AuthorizationUrlOptions, 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 CustomDataType, type DefinedFields, type ErrorCategory, type Field, type FieldBuilder, type FieldDecls, type FieldDef, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldValue, type GetAccessTokenOptions, type Job, type JobCreateInput, type JobPage, type JobResource, type JobSearchQuery, type JobUpdateInput, type MockHandler, type MockReply, type MockTransportOptions, type Option, type OptionResource, type OptionSearchQuery, type Partition, type PartitionId, type PartitionPage, type PartitionResource, type PartitionSearchQuery, 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 ResourceType, type Resume, type ResumeCreateInput, type ResumePage, type ResumeResource, type ResumeSearchQuery, type ResumeUpdateInput, type RevokeUrlOptions, type Scope, type StoredTokens, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, base64ToBytes, bytesToBase64, createMockTransport, defineFields };
|
package/dist/index.js
CHANGED
|
@@ -188,6 +188,34 @@ var createMemoryTokenStore = () => {
|
|
|
188
188
|
};
|
|
189
189
|
};
|
|
190
190
|
|
|
191
|
+
// src/auth/token-exchange.ts
|
|
192
|
+
var exchangeToken = async (deps, grantType, code) => {
|
|
193
|
+
const body = new URLSearchParams({
|
|
194
|
+
app_id: deps.appId,
|
|
195
|
+
secret: deps.appSecret,
|
|
196
|
+
grant_type: grantType,
|
|
197
|
+
code
|
|
198
|
+
}).toString();
|
|
199
|
+
const res = await deps.transport.send({
|
|
200
|
+
method: "POST",
|
|
201
|
+
url: `https://${deps.host}/v1/token`,
|
|
202
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
203
|
+
body
|
|
204
|
+
});
|
|
205
|
+
const a = parseAuthentication(res.body);
|
|
206
|
+
if (a.accessToken === void 0 || a.refreshToken === void 0) {
|
|
207
|
+
throw new PortersAuthError("token response missing tokens", {
|
|
208
|
+
category: "auth"
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
accessToken: a.accessToken,
|
|
213
|
+
refreshToken: a.refreshToken,
|
|
214
|
+
accessTokenExpiresAt: deps.now() + (a.accessTokenExpiresIn ?? 0),
|
|
215
|
+
refreshTokenExpiresAt: deps.now() + (a.refreshTokenExpiresIn ?? 0)
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
|
|
191
219
|
// src/auth/token-provider.ts
|
|
192
220
|
var DEFAULT_MARGIN_MS = 6e4;
|
|
193
221
|
var createDefaultTokenProvider = (opts) => {
|
|
@@ -198,35 +226,24 @@ var createDefaultTokenProvider = (opts) => {
|
|
|
198
226
|
let inflight;
|
|
199
227
|
const accessValid = (t) => t !== void 0 && now() < t.accessTokenExpiresAt - margin;
|
|
200
228
|
const canRefresh = (t) => t !== void 0 && now() < t.refreshTokenExpiresAt - margin;
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
grant_type: grantType,
|
|
206
|
-
code
|
|
207
|
-
}).toString();
|
|
208
|
-
const res = await opts.transport.send({
|
|
209
|
-
method: "POST",
|
|
210
|
-
url: `https://${opts.host}/v1/token`,
|
|
211
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
212
|
-
body
|
|
213
|
-
});
|
|
214
|
-
const a = parseAuthentication(res.body);
|
|
215
|
-
if (a.accessToken === void 0 || a.refreshToken === void 0) {
|
|
216
|
-
throw new PortersAuthError("token response missing tokens", {
|
|
217
|
-
category: "auth"
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
const t = {
|
|
221
|
-
accessToken: a.accessToken,
|
|
222
|
-
refreshToken: a.refreshToken,
|
|
223
|
-
accessTokenExpiresAt: now() + (a.accessTokenExpiresIn ?? 0),
|
|
224
|
-
refreshTokenExpiresAt: now() + (a.refreshTokenExpiresIn ?? 0)
|
|
225
|
-
};
|
|
226
|
-
cached = t;
|
|
227
|
-
await store.set(t);
|
|
228
|
-
return t;
|
|
229
|
+
const save = async (tokens) => {
|
|
230
|
+
cached = tokens;
|
|
231
|
+
await store.set(tokens);
|
|
232
|
+
return tokens;
|
|
229
233
|
};
|
|
234
|
+
const exchange = async (grantType, code) => save(
|
|
235
|
+
await exchangeToken(
|
|
236
|
+
{
|
|
237
|
+
host: opts.host,
|
|
238
|
+
appId: opts.appId,
|
|
239
|
+
appSecret: opts.appSecret,
|
|
240
|
+
transport: opts.transport,
|
|
241
|
+
now
|
|
242
|
+
},
|
|
243
|
+
grantType,
|
|
244
|
+
code
|
|
245
|
+
)
|
|
246
|
+
);
|
|
230
247
|
const acquire = async () => {
|
|
231
248
|
const url = `https://${opts.host}/v1/oauth?app_id=${encodeURIComponent(opts.appId)}&response_type=code_direct`;
|
|
232
249
|
const res = await opts.transport.send({ method: "GET", url, headers: {} });
|
|
@@ -252,7 +269,97 @@ var createDefaultTokenProvider = (opts) => {
|
|
|
252
269
|
});
|
|
253
270
|
};
|
|
254
271
|
return {
|
|
255
|
-
getAccessToken: async (o) => (await ensure(o?.forceRefresh ?? false)).accessToken
|
|
272
|
+
getAccessToken: async (o) => (await ensure(o?.forceRefresh ?? false)).accessToken,
|
|
273
|
+
cache: async (tokens) => {
|
|
274
|
+
await save(tokens);
|
|
275
|
+
},
|
|
276
|
+
clear: async () => {
|
|
277
|
+
cached = void 0;
|
|
278
|
+
await store.clear();
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// src/auth/auth-api.ts
|
|
284
|
+
var createAuthApi = (opts) => {
|
|
285
|
+
const now = opts.now ?? (() => Date.now());
|
|
286
|
+
const requireAppId = () => {
|
|
287
|
+
if (!opts.appId) {
|
|
288
|
+
throw new PortersConfigError("appId is required to build an OAuth URL", {
|
|
289
|
+
category: "config",
|
|
290
|
+
hint: "Set appId on PortersClient. A custom auth strategy that supplies its own tokens cannot run the browser grant."
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return opts.appId;
|
|
294
|
+
};
|
|
295
|
+
const requireDefaultStrategy = (method) => {
|
|
296
|
+
if (opts.controls === void 0) {
|
|
297
|
+
throw new PortersConfigError(
|
|
298
|
+
`${method} is only available with the default auth strategy`,
|
|
299
|
+
{
|
|
300
|
+
category: "config",
|
|
301
|
+
hint: "Remove the custom `auth` strategy to let the library manage tokens, or perform this step in your own strategy."
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return opts.controls;
|
|
306
|
+
};
|
|
307
|
+
const requireCredentials = () => {
|
|
308
|
+
if (!opts.appId || !opts.appSecret) {
|
|
309
|
+
throw new PortersConfigError(
|
|
310
|
+
"appId and appSecret are required to exchange an authorization code",
|
|
311
|
+
{
|
|
312
|
+
category: "config",
|
|
313
|
+
hint: "Set appId/appSecret on PortersClient (the Token endpoint needs both)."
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return { appId: opts.appId, appSecret: opts.appSecret };
|
|
318
|
+
};
|
|
319
|
+
const resolveScopes = (scopes) => {
|
|
320
|
+
const resolved = scopes ?? opts.scopes ?? [];
|
|
321
|
+
if (resolved.length === 0) {
|
|
322
|
+
throw new PortersConfigError(
|
|
323
|
+
"at least one scope is required for the code/remove grant",
|
|
324
|
+
{
|
|
325
|
+
category: "config",
|
|
326
|
+
hint: "Pass `scopes` to this call or configure `scopes` on PortersClient."
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
return resolved;
|
|
331
|
+
};
|
|
332
|
+
const buildOAuthUrl = (responseType, o) => {
|
|
333
|
+
const params = new URLSearchParams({
|
|
334
|
+
app_id: requireAppId(),
|
|
335
|
+
redirect_url: o.redirectUrl,
|
|
336
|
+
response_type: responseType,
|
|
337
|
+
scope: resolveScopes(o.scopes).join(",")
|
|
338
|
+
});
|
|
339
|
+
if (o.state !== void 0) params.set("state", o.state);
|
|
340
|
+
return `https://${opts.host}/v1/oauth?${params.toString()}`;
|
|
341
|
+
};
|
|
342
|
+
return {
|
|
343
|
+
authorizationUrl: (o) => buildOAuthUrl("code", o),
|
|
344
|
+
revokeUrl: (o) => buildOAuthUrl("remove", o),
|
|
345
|
+
exchangeAuthorizationCode: async (code) => {
|
|
346
|
+
const controls = requireDefaultStrategy("exchangeAuthorizationCode");
|
|
347
|
+
const { appId, appSecret } = requireCredentials();
|
|
348
|
+
const tokens = await exchangeToken(
|
|
349
|
+
{ host: opts.host, appId, appSecret, transport: opts.transport, now },
|
|
350
|
+
"oauth_code",
|
|
351
|
+
code
|
|
352
|
+
);
|
|
353
|
+
await controls.cache(tokens);
|
|
354
|
+
},
|
|
355
|
+
clearTokens: async () => {
|
|
356
|
+
const controls = requireDefaultStrategy("clearTokens");
|
|
357
|
+
await controls.clear();
|
|
358
|
+
},
|
|
359
|
+
ensureAuthenticated: async () => {
|
|
360
|
+
await opts.provider.getAccessToken();
|
|
361
|
+
},
|
|
362
|
+
getToken: () => opts.provider.getAccessToken()
|
|
256
363
|
};
|
|
257
364
|
};
|
|
258
365
|
|
|
@@ -1135,6 +1242,8 @@ var PortersClient = class {
|
|
|
1135
1242
|
process;
|
|
1136
1243
|
resume;
|
|
1137
1244
|
attachment;
|
|
1245
|
+
/** OAuth surface: initial browser grant, token warm-up/inspection, local revoke (ADR-0007/0034). */
|
|
1246
|
+
auth;
|
|
1138
1247
|
/** Master Read: accessible partitions (ADR-0021/0022). */
|
|
1139
1248
|
partition;
|
|
1140
1249
|
/** Master Read: users, plus `current()` self-identification (ADR-0021/0022). */
|
|
@@ -1146,12 +1255,29 @@ var PortersClient = class {
|
|
|
1146
1255
|
#host;
|
|
1147
1256
|
constructor(options) {
|
|
1148
1257
|
const transport = options.transport ?? createFetchTransport();
|
|
1149
|
-
|
|
1258
|
+
let auth;
|
|
1259
|
+
let controls = void 0;
|
|
1260
|
+
if (options.auth) {
|
|
1261
|
+
auth = options.auth;
|
|
1262
|
+
} else {
|
|
1263
|
+
const provider = createDefaultTokenProvider({
|
|
1264
|
+
host: options.host,
|
|
1265
|
+
appId: options.appId ?? "",
|
|
1266
|
+
appSecret: options.appSecret ?? "",
|
|
1267
|
+
transport,
|
|
1268
|
+
tokenStore: options.tokenStore
|
|
1269
|
+
});
|
|
1270
|
+
auth = provider;
|
|
1271
|
+
controls = provider;
|
|
1272
|
+
}
|
|
1273
|
+
this.auth = createAuthApi({
|
|
1150
1274
|
host: options.host,
|
|
1151
|
-
appId: options.appId
|
|
1152
|
-
appSecret: options.appSecret
|
|
1275
|
+
appId: options.appId,
|
|
1276
|
+
appSecret: options.appSecret,
|
|
1277
|
+
scopes: options.scopes,
|
|
1153
1278
|
transport,
|
|
1154
|
-
|
|
1279
|
+
provider: auth,
|
|
1280
|
+
controls
|
|
1155
1281
|
});
|
|
1156
1282
|
const requester = createRequester({
|
|
1157
1283
|
transport,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors/porters-error.ts","../src/errors/classify.ts","../src/xml/parser.ts","../src/xml/raw.ts","../src/auth/memory-store.ts","../src/auth/token-provider.ts","../src/http/fetch-transport.ts","../src/http/mock-transport.ts","../src/http/throttle.ts","../src/http/retry.ts","../src/http/requester.ts","../src/util/datetime.ts","../src/xml/encode.ts","../src/xml/decode.ts","../src/resources/read-core.ts","../src/resources/resource.ts","../src/resources/candidate.ts","../src/resources/job.ts","../src/resources/client.ts","../src/resources/process.ts","../src/resources/resume.ts","../src/resources/attachment.ts","../src/resources/partition.ts","../src/resources/user.ts","../src/resources/field.ts","../src/resources/option.ts","../src/client.ts","../src/fields/define-fields.ts","../src/util/base64.ts"],"sourcesContent":["// PortersError hierarchy (ADR-0006): source-split subclasses + a cross-cutting\n// `category`. Never swallow errors; always surface a PortersError.\n\n/** Cross-cutting classification shared by every PORTERS error. */\nexport type ErrorCategory =\n | \"auth\"\n | \"permission\"\n | \"validation\"\n | \"notFound\"\n | \"conflict\"\n // 予約(現状どの分類関数も produce しない)。PORTERS はレート超過時に判別可能なコードを\n // 返さず接続を切るため、強制切断は PortersNetworkError(category \"network\")として表面化する。\n // 将来 429 相当の判別手段が得られたら配線するため型には残す(RV-3)。\n | \"rateLimit\"\n | \"transient\"\n | \"network\"\n | \"server\"\n | \"config\"\n | \"unknown\";\n\n/** Where the failing call was aimed (for self-service debugging). */\nexport type PortersErrorContext = {\n resource?: string;\n operation?: string;\n partition?: number;\n};\n\n/** Construction options for {@link PortersError}. */\nexport type PortersErrorOptions = {\n category: ErrorCategory;\n /** PORTERS raw code; `null` for network/transport failures. */\n code?: number | null;\n retryable?: boolean;\n /** Actionable hint (English by default). */\n hint?: string;\n httpStatus?: number;\n context?: PortersErrorContext;\n cause?: unknown;\n};\n\n/** Base class for every PORTERS-originated error (catch-all). */\nexport class PortersError extends Error {\n readonly category: ErrorCategory;\n readonly code: number | null;\n readonly retryable: boolean;\n readonly hint?: string;\n readonly httpStatus?: number;\n readonly context?: PortersErrorContext;\n\n constructor(message: string, options: PortersErrorOptions) {\n super(\n message,\n options.cause === undefined ? undefined : { cause: options.cause },\n );\n this.name = new.target.name;\n this.category = options.category;\n this.code = options.code ?? null;\n this.retryable = options.retryable ?? false;\n this.hint = options.hint;\n this.httpStatus = options.httpStatus;\n this.context = options.context;\n }\n}\n\n/** OAuth / Token errors. */\nexport class PortersAuthError extends PortersError {}\n\n/** Resource API errors. */\nexport class PortersResourceError extends PortersError {}\n\n/** Connection / timeout / forced rate-limit disconnect. */\nexport class PortersNetworkError extends PortersError {}\n\n/** Misconfiguration / misuse — not PORTERS-originated; thrown synchronously. */\nexport class PortersConfigError extends PortersError {}\n","// Code -> category -> retryable classification and PortersError factories\n// (ADR-0006 / result-codes.md). Unknown codes fall through to `category:\n// \"unknown\"` — never swallowed (fail-safe).\n\nimport {\n PortersAuthError,\n PortersNetworkError,\n PortersResourceError,\n type ErrorCategory,\n type PortersErrorContext,\n} from \"./porters-error\";\n\nconst RESOURCE_VALIDATION = new Set([8, 124, 126, 127, 133, 146, 500]);\n\n/** Resource API `<Code>` -> category (ADR-0006). */\nexport const resourceCategory = (code: number): ErrorCategory => {\n if (code === 9 || code === 302) return \"transient\";\n if (code === 401 || code === 402) return \"auth\";\n if (\n code === 6 ||\n code === 400 ||\n code === 403 ||\n code === 406 ||\n code === 601\n )\n return \"permission\";\n if (code === 7 || code === 404) return \"notFound\";\n if (code === 301 || code === 303 || code === 304) return \"conflict\";\n if (code === 1000) return \"server\";\n if (RESOURCE_VALIDATION.has(code) || (code >= 100 && code <= 116))\n return \"validation\";\n return \"unknown\";\n};\n\n/** Authentication API `<Error>` -> category (ADR-0006). */\nexport const authCategory = (code: number): ErrorCategory => {\n if (code === 400) return \"auth\";\n if ([401, 103, 104, 105, 106, 107, 109, 114, 117].includes(code))\n return \"auth\";\n if ([100, 101, 102, 110, 112].includes(code)) return \"validation\";\n if ([111, 115, 116, 402].includes(code)) return \"permission\";\n if (code === 108) return \"server\";\n return \"unknown\";\n};\n\nconst resourceHint = (code: number): string | undefined => {\n if (code === 403)\n return \"No data permission. Run the initial browser `code` grant for this Company DB, or check scopes.\";\n if (code === 404)\n return \"Partition not found or outside the contract period. Verify the partition id.\";\n return undefined;\n};\n\n/** Build a PortersResourceError from a Resource API `<Code>`. */\nexport const resourceError = (\n code: number,\n message: string,\n context?: PortersErrorContext,\n): PortersResourceError => {\n const category = resourceCategory(code);\n return new PortersResourceError(message, {\n category,\n code,\n retryable: category === \"transient\",\n hint: resourceHint(code),\n context,\n });\n};\n\n/** Build a PortersAuthError from an Authentication API `<Error>`. */\nexport const authError = (code: number, message: string): PortersAuthError => {\n const category = authCategory(code);\n return new PortersAuthError(message, {\n category,\n code,\n retryable: false,\n hint:\n category === \"auth\"\n ? \"Authentication failed; re-authenticate (browser `code` grant) or check app credentials.\"\n : undefined,\n });\n};\n\n/** Build a PortersNetworkError (no PORTERS code; retryable for idempotent ops). */\nexport const networkError = (\n message: string,\n cause?: unknown,\n): PortersNetworkError =>\n new PortersNetworkError(message, {\n category: \"network\",\n retryable: true,\n cause,\n });\n","// XML parsing + error routing (ADR-0011). The parser returns raw strings\n// (`parseTagValue: false`); all type coercion happens in `decode.ts`.\n\nimport { XMLParser } from \"fast-xml-parser\";\n\nimport { authError, resourceError } from \"../errors/classify\";\nimport { PortersAuthError, PortersResourceError } from \"../errors/index\";\nimport { asArray, asRecord, asString } from \"./raw\";\n\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n ignoreDeclaration: true,\n parseTagValue: false,\n parseAttributeValue: false,\n trimValues: true,\n // asArray() already normalizes a single/missing/repeated <Item> into an array,\n // so isArray is belt-and-suspenders: these mutants are equivalent (no test can\n // observe the difference once asArray() runs).\n // Stryker disable next-line ArrowFunction,ConditionalExpression,StringLiteral: equivalent — asArray() normalizes regardless\n isArray: (name) => name === \"Item\",\n});\n\n// fast-xml-parser yields raw strings; coerce an attribute/code node to an int,\n// treating a missing node as 0. The explicit `undefined` check keeps the\n// fallback observable — `Number(\"\") === 0`, so a `?? \"0\"` default would be an\n// equivalent mutant.\nconst toInt = (v: unknown): number => {\n const s = asString(v);\n return s === undefined ? 0 : Number(s);\n};\n\n/** One `<Item>`: a map of field alias -> raw node (string or nested object). */\nexport type RawItem = Record<string, unknown>;\n\nexport type ResourcePage = {\n total: number;\n count: number;\n start: number;\n items: RawItem[];\n};\n\n/**\n * Parse a Resource Read response. Reads `<Code>` first and, if non-zero, throws\n * the mapped PortersError (ADR-0006) — HTTP 200 + `<Code>≠0` is an error, not\n * data.\n */\nexport const parseResourcePage = (xml: string): ResourcePage => {\n const root = asRecord(parser.parse(xml) as unknown);\n const rootKey = root ? Object.keys(root)[0] : undefined;\n // `root` is always a record here and `root[rootKey]` is undefined exactly when\n // rootKey is, so dropping/forcing either guard collapses to the same throw.\n // Stryker disable next-line ConditionalExpression,LogicalOperator: equivalent — both branches converge on the unparseable throw\n const body = root && rootKey ? asRecord(root[rootKey]) : undefined;\n if (!body) {\n throw new PortersResourceError(\"unparseable resource response\", {\n category: \"unknown\",\n });\n }\n\n const code = toInt(body.Code);\n if (code !== 0) {\n throw resourceError(code, `resource returned code ${code}`, {\n resource: rootKey,\n });\n }\n\n return {\n total: toInt(body[\"@_Total\"]),\n count: toInt(body[\"@_Count\"]),\n start: toInt(body[\"@_Start\"]),\n items: asArray(body.Item).map((it) => asRecord(it) ?? {}),\n };\n};\n\n/** One written record's outcome: the assigned/updated `Id` and its Result `Code`. */\nexport type WriteResultItem = {\n id: number;\n code: number;\n};\n\n/**\n * Parse a Resource Write response. Unlike Read there is no root `<Code>` nor\n * Total/Count/Start: each `<Item>` carries its own `<Id>` (assigned on create /\n * echoed on update) and `<Code>` (per-item Result Code). Applying the per-item\n * code policy (throw on `!= 0`) is the accessor's job, since a bulk write mixes\n * successes and failures — see write-format.md.\n */\nexport const parseWriteResult = (xml: string): WriteResultItem[] => {\n const root = asRecord(parser.parse(xml) as unknown);\n const rootKey = root ? Object.keys(root)[0] : undefined;\n // Same equivalence as parseResourcePage: both guards converge on the throw.\n // Stryker disable next-line ConditionalExpression,LogicalOperator: equivalent — both branches converge on the unparseable throw\n const body = root && rootKey ? asRecord(root[rootKey]) : undefined;\n if (!body) {\n throw new PortersResourceError(\"unparseable write response\", {\n category: \"unknown\",\n });\n }\n\n return asArray(body.Item).map((it) => {\n const item = asRecord(it) ?? {};\n return { id: toInt(item.Id), code: toInt(item.Code) };\n });\n};\n\n/** Parsed `<Authentication>` response (OAuth `code_direct` / Token). */\nexport type AuthResponse = {\n code?: string;\n accessToken?: string;\n accessTokenExpiresIn?: number;\n refreshToken?: string;\n refreshTokenExpiresIn?: number;\n};\n\n/**\n * Parse an `<Authentication>` response. Reads `<Error>` first and, if non-zero,\n * throws the mapped PortersAuthError (ADR-0006).\n */\nexport const parseAuthentication = (xml: string): AuthResponse => {\n const root = asRecord(parser.parse(xml) as unknown);\n const body = root ? asRecord(root.Authentication) : undefined;\n if (!body) {\n throw new PortersAuthError(\"unparseable authentication response\", {\n category: \"unknown\",\n });\n }\n\n const error = toInt(body.Error);\n if (error !== 0) {\n throw authError(\n error,\n asString(body.Message) ?? `authentication error ${error}`,\n );\n }\n\n const num = (v: unknown): number | undefined => {\n const s = asString(v);\n return s === undefined ? undefined : Number(s);\n };\n return {\n code: asString(body.Code),\n accessToken: asString(body.AccessToken),\n accessTokenExpiresIn: num(body.AccessTokenExpiresIn),\n refreshToken: asString(body.RefreshToken),\n refreshTokenExpiresIn: num(body.RefreshTokenExpiresIn),\n };\n};\n","// Narrowing helpers for fast-xml-parser output. The parser is typed as `any`;\n// we launder it through `unknown` and narrow here so we never spread `any`.\n\nexport const asRecord = (v: unknown): Record<string, unknown> | undefined =>\n typeof v === \"object\" && v !== null && !Array.isArray(v)\n ? (v as Record<string, unknown>)\n : undefined;\n\nexport const asString = (v: unknown): string | undefined =>\n typeof v === \"string\" ? v : undefined;\n\n/** Normalize a node that may be missing, single, or repeated into an array. */\nexport const asArray = (v: unknown): unknown[] => {\n if (Array.isArray(v)) return v;\n return v === undefined || v === null ? [] : [v];\n};\n","import type { StoredTokens, TokenStore } from \"./types\";\n\n/** Default in-process token store (single instance; lost on restart). */\nexport const createMemoryTokenStore = (): TokenStore => {\n let tokens: StoredTokens | undefined;\n return {\n get: () => Promise.resolve(tokens),\n set: (t) => {\n tokens = t;\n return Promise.resolve();\n },\n clear: () => {\n tokens = undefined;\n return Promise.resolve();\n },\n };\n};\n","// Default transparent TokenProvider (ADR-0007 / ADR-0012): code_direct -> token,\n// cache, hybrid refresh (proactive margin + on-demand), in-process single-flight.\n// Factory style per ADR-0013.\n\nimport { PortersAuthError } from \"../errors/index\";\nimport type { Transport } from \"../http/index\";\nimport { parseAuthentication } from \"../xml/parser\";\nimport { createMemoryTokenStore } from \"./memory-store\";\nimport type { StoredTokens, TokenProvider, TokenStore } from \"./types\";\n\nexport type DefaultTokenProviderOptions = {\n host: string;\n appId: string;\n appSecret: string;\n transport: Transport;\n /** Token persistence; defaults to in-memory. */\n tokenStore?: TokenStore;\n /** Refresh this many ms before expiry (proactive). Default 60s. */\n refreshMarginMs?: number;\n /** Injectable clock (tests). Default `Date.now`. */\n now?: () => number;\n};\n\nconst DEFAULT_MARGIN_MS = 60_000;\n\nexport const createDefaultTokenProvider = (\n opts: DefaultTokenProviderOptions,\n): TokenProvider => {\n const store = opts.tokenStore ?? createMemoryTokenStore();\n const margin = opts.refreshMarginMs ?? DEFAULT_MARGIN_MS;\n const now = opts.now ?? (() => Date.now());\n\n let cached: StoredTokens | undefined;\n let inflight: Promise<StoredTokens> | undefined;\n\n const accessValid = (t: StoredTokens | undefined): t is StoredTokens =>\n t !== undefined && now() < t.accessTokenExpiresAt - margin;\n\n const canRefresh = (t: StoredTokens | undefined): t is StoredTokens =>\n t !== undefined && now() < t.refreshTokenExpiresAt - margin;\n\n const exchange = async (\n grantType: \"oauth_code\" | \"refresh_token\",\n code: string,\n ): Promise<StoredTokens> => {\n const body = new URLSearchParams({\n app_id: opts.appId,\n secret: opts.appSecret,\n grant_type: grantType,\n code,\n }).toString();\n const res = await opts.transport.send({\n method: \"POST\",\n url: `https://${opts.host}/v1/token`,\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n const a = parseAuthentication(res.body);\n if (a.accessToken === undefined || a.refreshToken === undefined) {\n throw new PortersAuthError(\"token response missing tokens\", {\n category: \"auth\",\n });\n }\n const t: StoredTokens = {\n accessToken: a.accessToken,\n refreshToken: a.refreshToken,\n accessTokenExpiresAt: now() + (a.accessTokenExpiresIn ?? 0),\n refreshTokenExpiresAt: now() + (a.refreshTokenExpiresIn ?? 0),\n };\n cached = t;\n await store.set(t);\n return t;\n };\n\n // code_direct -> token (initial acquisition; requires prior browser grant).\n const acquire = async (): Promise<StoredTokens> => {\n const url =\n `https://${opts.host}/v1/oauth` +\n `?app_id=${encodeURIComponent(opts.appId)}&response_type=code_direct`;\n const res = await opts.transport.send({ method: \"GET\", url, headers: {} });\n const { code } = parseAuthentication(res.body);\n if (code === undefined) {\n throw new PortersAuthError(\"code_direct returned no code\", {\n category: \"auth\",\n });\n }\n return exchange(\"oauth_code\", code);\n };\n\n const renew = async (): Promise<StoredTokens> => {\n if (cached === undefined) cached = await store.get();\n if (canRefresh(cached)) {\n return exchange(\"refresh_token\", cached.refreshToken);\n }\n return acquire();\n };\n\n const ensure = (forceRefresh: boolean): Promise<StoredTokens> => {\n if (!forceRefresh && accessValid(cached)) return Promise.resolve(cached);\n return (inflight ??= renew().finally(() => {\n inflight = undefined;\n }));\n };\n\n return {\n getAccessToken: async (o) =>\n (await ensure(o?.forceRefresh ?? false)).accessToken,\n };\n};\n","// Default fetch-based transport (ADR-0009). Thin: one request -> one response;\n// throttle/retry/auth live above it. Network/timeout -> PortersNetworkError.\n\nimport { PortersNetworkError } from \"../errors/index\";\nimport type { Transport } from \"./types\";\n\nexport type FetchTransportOptions = {\n timeoutMs?: number;\n /** Injectable fetch (tests / custom dispatcher). Default global fetch. */\n fetchImpl?: typeof fetch;\n};\n\nexport const createFetchTransport = (\n opts: FetchTransportOptions = {},\n): Transport => {\n const doFetch = opts.fetchImpl ?? fetch;\n const timeoutMs = opts.timeoutMs ?? 30_000;\n return {\n send: async (req) => {\n try {\n const res = await doFetch(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n signal: AbortSignal.timeout(timeoutMs),\n });\n return { status: res.status, body: await res.text() };\n } catch (cause) {\n throw new PortersNetworkError(\"transport request failed\", {\n category: \"network\",\n retryable: true,\n cause,\n });\n }\n },\n };\n};\n","// Public mock transport for offline evaluation / unit tests (ADR-0024 / R-17 / R-12).\n// It targets the stable public `Transport` seam (not `fetch`), so it survives an internal\n// transport change. By default the OAuth code_direct + token endpoints are auto-answered,\n// so callers only mock resource XML; an unmocked route fails loud (fail-safe).\n\nimport { PortersConfigError } from \"../errors/index\";\nimport type { Transport, TransportRequest, TransportResponse } from \"./types\";\n\n/** A mock reply: an XML body string (HTTP 200), or an explicit status + body. */\nexport type MockReply = string | { status?: number; body: string };\n\n/**\n * Maps a request to a {@link MockReply}, or returns `undefined` for \"not mocked\". When `undefined`\n * is returned (and the request is not an auto-answered auth endpoint), the transport throws a\n * {@link PortersConfigError} naming the request, so an unmocked route surfaces instead of silently\n * returning an empty response.\n */\nexport type MockHandler = (request: TransportRequest) => MockReply | undefined;\n\n/** Options for {@link createMockTransport}. */\nexport type MockTransportOptions = {\n /**\n * Auto-answer the OAuth `code_direct` (`/v1/oauth`) and token (`/v1/token`) endpoints with valid\n * demo tokens, so callers only mock resource XML. Default `true`. Set `false` to handle the auth\n * endpoints in your own handler.\n */\n auth?: boolean;\n};\n\n// Default auth responses (mirrors the live envelope; expiry values are ms — see token-provider).\nconst AUTH_CODE_XML = `<Authentication><Code>mock-code</Code><Error>0</Error></Authentication>`;\nconst AUTH_TOKEN_XML =\n `<Authentication>` +\n `<AccessToken>mock-access-token</AccessToken><AccessTokenExpiresIn>1800000</AccessTokenExpiresIn>` +\n `<RefreshToken>mock-refresh-token</RefreshToken><RefreshTokenExpiresIn>7200000</RefreshTokenExpiresIn>` +\n `<Error>0</Error></Authentication>`;\n\nconst toResponse = (reply: MockReply): TransportResponse =>\n typeof reply === \"string\"\n ? { status: 200, body: reply }\n : { status: reply.status ?? 200, body: reply.body };\n\n// method + path だけで「どの route を足すか」は十分。既定 field を載せた Read URL の\n// クエリは長大でノイズなので落とす(不正な URL はそのまま出す=フェイルセーフ)。\nconst routeLabel = (method: string, url: string): string => {\n try {\n return `${method} ${new URL(url).pathname}`;\n } catch {\n return `${method} ${url}`;\n }\n};\n\n/**\n * Build a {@link Transport} that answers from a handler instead of the network — run the library\n * fully offline, with no PORTERS contract (R-17). Pass it as `new PortersClient({ transport })`.\n *\n * @example\n * const transport = createMockTransport((req) =>\n * req.url.includes(\"/v1/candidate\")\n * ? `<Candidate Total=\"0\" Count=\"0\" Start=\"0\"><Code>0</Code></Candidate>`\n * : undefined, // unmocked -> a clear PortersConfigError\n * );\n */\nexport const createMockTransport = (\n handler: MockHandler,\n options: MockTransportOptions = {},\n): Transport => {\n const autoAuth = options.auth ?? true;\n // Non-async on purpose: always return a Promise (resolve/reject) so an unmocked route rejects\n // rather than throwing synchronously — faithful to the Transport contract.\n return {\n send: (req) => {\n if (autoAuth && req.url.includes(\"/v1/token\")) {\n return Promise.resolve({ status: 200, body: AUTH_TOKEN_XML });\n }\n if (autoAuth && req.url.includes(\"/v1/oauth\")) {\n return Promise.resolve({ status: 200, body: AUTH_CODE_XML });\n }\n const reply = handler(req);\n if (reply === undefined) {\n return Promise.reject(\n new PortersConfigError(\n `createMockTransport: no mock response for ${routeLabel(req.method, req.url)} — add a case to your handler` +\n ` (or pass { auth: false } to mock the auth endpoints too)`,\n { category: \"config\" },\n ),\n );\n }\n return Promise.resolve(toResponse(reply));\n },\n };\n};\n","// Token-bucket throttle (ADR-0010): per-minute Read/Write limits at ~90% safety.\n// Bursts are allowed up to capacity; the average stays under the limit.\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport type Throttle = {\n take(write: boolean): Promise<void>;\n};\n\nexport type ThrottleOptions = {\n readPerMin?: number;\n writePerMin?: number;\n /** Fraction of the limit to actually use (headroom). Default 0.9. */\n safety?: number;\n now?: () => number;\n};\n\nconst makeBucket = (\n capacity: number,\n now: () => number,\n): (() => Promise<void>) => {\n const ratePerMs = capacity / 60_000;\n let tokens = capacity;\n let last = now();\n return async () => {\n for (;;) {\n const t = now();\n tokens = Math.min(capacity, tokens + (t - last) * ratePerMs);\n last = t;\n if (tokens >= 1) {\n tokens -= 1;\n return;\n }\n await sleep(Math.ceil((1 - tokens) / ratePerMs));\n }\n };\n};\n\nexport const createThrottle = (opts: ThrottleOptions = {}): Throttle => {\n const safety = opts.safety ?? 0.9;\n const now = opts.now ?? (() => Date.now());\n const read = makeBucket(Math.floor((opts.readPerMin ?? 2000) * safety), now);\n const write = makeBucket(Math.floor((opts.writePerMin ?? 500) * safety), now);\n return { take: (isWrite) => (isWrite ? write() : read()) };\n};\n","// Exponential backoff with full jitter (ADR-0010).\n\nexport type Backoff = (attempt: number) => number;\n\nexport const expoBackoff =\n (baseMs = 200, maxMs = 8_000): Backoff =>\n (attempt) =>\n Math.floor(Math.random() * Math.min(maxMs, baseMs * 2 ** attempt));\n","// Request pipeline (ADR-0009/0010/0012): throttle -> auth header -> transport,\n// with reactive token refresh (401/402) and bounded backoff retry. The\n// idempotency guard keeps non-idempotent writes (create) from double-applying.\n\nimport type { TokenProvider } from \"../auth/types\";\nimport {\n PortersConfigError,\n PortersError,\n PortersNetworkError,\n} from \"../errors/index\";\nimport type { Backoff } from \"./retry\";\nimport type { Throttle } from \"./throttle\";\nimport type { Transport, TransportRequest } from \"./types\";\n\nconst API_VERSION = \"2\";\n\n// docs/reference: keep a *whole* request under ~15000 chars (a larger payload 400s).\n// \"Whole\" is load-bearing: a write's body dominates, but a read's length lives in the\n// URL (field / condition) — and ADR-0020 makes a fieldless Read send the catalog default\n// field set, so that URL grew. A future 16KB cap is planned but undetermined — follow the\n// canonical value.\nconst MAX_REQUEST_LENGTH = 15000;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst withAuth = (\n req: TransportRequest,\n token: string,\n write: boolean,\n): TransportRequest => ({\n ...req,\n headers: {\n ...req.headers,\n \"X-porters-hrbc-oauth-token\": token,\n \"X-P-ConnectAPI-Version\": API_VERSION,\n ...(write ? { \"Content-Type\": \"application/xml; charset=UTF-8\" } : {}),\n },\n});\n\nexport type RequesterOptions = {\n transport: Transport;\n auth: TokenProvider;\n throttle: Throttle;\n backoff: Backoff;\n maxRetries?: number;\n};\n\nexport type RequestSpec = {\n /** Write (POST) uses the write throttle bucket. */\n write?: boolean;\n /** false for non-idempotent ops (create); not auto-retried on network uncertainty. */\n idempotent?: boolean;\n /** Skip the ~15000-char size guard (file uploads have their own limit; ADR-0018). */\n unboundedBody?: boolean;\n};\n\nexport type Requester = {\n request<T>(\n req: TransportRequest,\n parse: (body: string) => T,\n spec?: RequestSpec,\n ): Promise<T>;\n};\n\nexport const createRequester = (o: RequesterOptions): Requester => {\n const maxRetries = o.maxRetries ?? 3;\n\n const request = async <T>(\n req: TransportRequest,\n parse: (body: string) => T,\n spec: RequestSpec = {},\n ): Promise<T> => {\n // Eager size guard: block an oversized request before throttle / auth / transport.\n // A clear config error beats an opaque server 400, and we don't burn a throttle token\n // or a token refresh on a request that cannot succeed (fail-safe). PORTERS limits the\n // whole request, so measure URL + body: a write's body or a read's field/condition\n // query string can blow the cap (RV-5). File uploads opt out via `unboundedBody` (the\n // body has its own limit — ADR-0018; their write URL is short, so skipping is safe).\n const requestLength = req.url.length + (req.body?.length ?? 0);\n if (!spec.unboundedBody && requestLength > MAX_REQUEST_LENGTH) {\n throw new PortersConfigError(\n `request is ${requestLength} characters, over the ~${MAX_REQUEST_LENGTH}-character limit`,\n {\n category: \"config\",\n hint: \"Shorten the request: narrow a read's field/condition, or split a write into batches of 200 or fewer records (PORTERS caps a request at ~15000 characters).\",\n },\n );\n }\n const write = spec.write ?? false;\n const idempotent = spec.idempotent ?? !write;\n let authRetried = false;\n let forceRefresh = false;\n let attempt = 0;\n\n for (;;) {\n await o.throttle.take(write);\n try {\n const token = await o.auth.getAccessToken(\n forceRefresh ? { forceRefresh: true } : undefined,\n );\n forceRefresh = false;\n const res = await o.transport.send(withAuth(req, token, write));\n return parse(res.body);\n } catch (e) {\n if (!(e instanceof PortersError)) throw e;\n // reactive: token expired -> refresh once and retry (safe even for create).\n if ((e.code === 401 || e.code === 402) && !authRetried) {\n authRetried = true;\n forceRefresh = true;\n continue;\n }\n // idempotency guard: non-idempotent write + network-uncertain -> surface.\n if (e instanceof PortersNetworkError && write && !idempotent) throw e;\n // transient (9/302) / network -> bounded backoff.\n if (e.retryable && attempt < maxRetries) {\n attempt += 1;\n await sleep(o.backoff(attempt - 1));\n continue;\n }\n throw e;\n }\n }\n };\n\n return { request };\n};\n","// PORTERS datetime <-> ISO 8601 (UTC) normalization (PRD R-10 / ADR-0011).\n// DateTime `yyyy/mm/dd HH:MM:SS` (UTC) <-> ISO `...Z`\n// Date `yyyy/mm/dd` <-> date-only (no `Z`)\n// No business-timezone (e.g. JST) conversion — that is the caller's responsibility.\n\nconst DATETIME_RE = /^(\\d{4})\\/(\\d{2})\\/(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})$/;\nconst DATE_RE = /^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/;\nconst ISO_DATE_RE = /^(\\d{4})-(\\d{2})-(\\d{2})/;\n\n/** PORTERS `yyyy/mm/dd HH:MM:SS` (UTC) -> ISO 8601 `...Z`. */\nexport const portersDateTimeToIso = (value: string): string => {\n const m = DATETIME_RE.exec(value);\n if (!m) throw new RangeError(`invalid PORTERS DateTime: \"${value}\"`);\n const iso = `${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}Z`;\n if (Number.isNaN(Date.parse(iso))) {\n throw new RangeError(`invalid PORTERS DateTime: \"${value}\"`);\n }\n return iso;\n};\n\n/** ISO 8601 (with `Z` or offset) -> PORTERS `yyyy/mm/dd HH:MM:SS` (UTC). */\nexport const isoToPortersDateTime = (value: string): string => {\n const t = Date.parse(value);\n if (Number.isNaN(t)) throw new RangeError(`invalid ISO datetime: \"${value}\"`);\n const d = new Date(t);\n const pad = (n: number): string => String(n).padStart(2, \"0\");\n return (\n `${d.getUTCFullYear()}/${pad(d.getUTCMonth() + 1)}/${pad(d.getUTCDate())} ` +\n `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`\n );\n};\n\n/** PORTERS `yyyy/mm/dd` -> ISO date `yyyy-mm-dd` (no timezone). */\nexport const portersDateToIso = (value: string): string => {\n const m = DATE_RE.exec(value);\n if (!m) throw new RangeError(`invalid PORTERS Date: \"${value}\"`);\n return `${m[1]}-${m[2]}-${m[3]}`;\n};\n\n/** ISO date (or datetime) -> PORTERS `yyyy/mm/dd` (calendar date as-is, no shift). */\nexport const isoToPortersDate = (value: string): string => {\n const m = ISO_DATE_RE.exec(value);\n if (!m) throw new RangeError(`invalid ISO date: \"${value}\"`);\n return `${m[1]}/${m[2]}/${m[3]}`;\n};\n","// Data-Type-driven value encoding for Write (ADR-0011). Read and Write\n// representations are asymmetric: User/System[Reference] write the ID only, Option writes\n// `<Field><OptionAlias/></Field>`, and DateTime/Date go ISO -> PORTERS. This is the\n// mirror of decode.ts; it builds the request body so XML stays out of resources/.\n\nimport { isoToPortersDate, isoToPortersDateTime } from \"../util/datetime\";\nimport type { DataType } from \"./decode\";\n\n/**\n * A value to write. Scalars cover the string Data Types / Number / Id and the\n * ID-only User / Reference. An **Option** value is an array of selected aliases\n * (`string[]`) — symmetric with the Option read shape (ADR-0017); a lone string\n * is tolerated as a 1-element selection (fail-safe). `null` / `undefined` omits the\n * field (leaves it unchanged) — send `\"\"` to clear a string field.\n *\n * Per-field static typing (Option fields as `string[]`, etc.) is future work — the\n * precise static Write type (SD-3).\n */\nexport type WriteValue = string | number | string[] | null | undefined;\n\n/** One record to write: field alias (bare, e.g. `P_Name`) -> value. */\nexport type WriteItem = Record<string, WriteValue>;\n\n// Data Types a user may write. `System[Id]` is library-supplied (`P_Id=-1`/target id) and\n// `System[DateTime]` (registration/update) is Write-restricted by PORTERS — both are excluded\n// from the static Write input so they cannot be set (ADR-0016 promise, realized in ADR-0019).\nexport type WritableDataType = Exclude<\n DataType,\n \"System[Id]\" | \"System[DateTime]\"\n>;\n\n// Per-Data-Type write value (mirror of `encodeField`): User / System[Reference] / Number take a\n// number, Option an alias array, the rest a scalar string. Drives the static Write type (ADR-0019).\nexport type WriteValueOf<D extends DataType> = D extends\n | \"User\"\n | \"System[Reference]\"\n | \"Number\"\n ? number\n : D extends \"Option\"\n ? string[]\n : string;\n\n// Element-content escaping. Only `& < >` are significant in PCDATA; we never emit\n// attributes, so quotes are left as-is.\nconst escapeXml = (s: string): string =>\n s.replace(/[&<>]/g, (c) =>\n c === \"&\" ? \"&\" : c === \"<\" ? \"<\" : \">\",\n );\n\nconst scalar = (v: string | number | string[]): string => escapeXml(String(v));\n\n/** Encode one field's value into the inner XML of its element. */\nexport const encodeField = (\n type: DataType,\n value: string | number | string[],\n): string => {\n switch (type) {\n // Option: the selected aliases as empty child elements. Canonical input is an\n // array (ADR-0017, symmetric with read); a lone string is wrapped as a 1-element\n // selection (fail-safe).\n case \"Option\":\n return (Array.isArray(value) ? value : [value])\n .map((alias) => `<${alias}/>`)\n .join(\"\");\n // System[DateTime] (registration/update) is Write-restricted by PORTERS; we still\n // serialize it identically — rejecting the write is the input type's job (SD-3).\n case \"DateTime\":\n case \"System[DateTime]\":\n return scalar(isoToPortersDateTime(String(value)));\n // Age shares Date's wire format (`yyyy/mm/dd`): we write the birthdate.\n case \"Date\":\n case \"Age\":\n return scalar(isoToPortersDate(String(value)));\n // System[Id] / Number / User & System[Reference] (ID-only) / string Data Types all\n // serialize as a scalar (the string types stay distinct labels per ADR-0016).\n case \"System[Id]\":\n case \"Number\":\n case \"User\":\n case \"System[Reference]\":\n case \"SinglelineText\":\n case \"MultilineText\":\n case \"Mail\":\n case \"Telephone\":\n case \"URL\":\n return scalar(value);\n }\n};\n\n// One `<Item>…</Item>` body. Unknown aliases (custom U_/A_, no catalog entry) fall\n// back to Text — symmetric with decode's raw-string passthrough (fail-safe).\nconst encodeItem = (\n prefix: string,\n fields: ReadonlyMap<string, DataType>,\n item: WriteItem,\n): string => {\n const parts: string[] = [];\n for (const [alias, value] of Object.entries(item)) {\n // null / undefined -> omit (leave unchanged); \"\" is kept (clears a Text field).\n if (value === null || value === undefined) continue;\n const type = fields.get(alias);\n const inner = type === undefined ? scalar(value) : encodeField(type, value);\n parts.push(`<${prefix}.${alias}>${inner}</${prefix}.${alias}>`);\n }\n return parts.join(\"\");\n};\n\n/** Build a Write request body: `<{Resource}><Item>…</Item>…</{Resource}>`. */\nexport const buildWriteXml = (config: {\n resource: string;\n prefix: string;\n fields: ReadonlyMap<string, DataType>;\n items: WriteItem[];\n}): string => {\n const items = config.items\n .map(\n (item) =>\n `<Item>${encodeItem(config.prefix, config.fields, item)}</Item>`,\n )\n .join(\"\");\n return `<${config.resource}>${items}</${config.resource}>`;\n};\n","// Data-Type-driven value decoding (ADR-0011). Input is the raw node (string or\n// nested object) from the parser; output is the typed value. Empty -> null.\n\nimport { portersDateToIso, portersDateTimeToIso } from \"../util/datetime\";\nimport { asRecord, asString } from \"./raw\";\n\n// Granularity = PORTERS Data Type (ADR-0016). Labels are the literal Data Type\n// strings, incl. the System family (`System[Id]` / `System[DateTime]` / `System[Reference]`).\n// Currency collapses to Number and the three Option subtypes to Option (PORTERS' own\n// Data Type does the same); the string Data Types stay distinct (room for future\n// validation / normalisation). The `System[…]` qualifier marks system-managed values\n// (auto-assigned, often Write-restricted); that lifecycle is enforced via input types,\n// not here — decoding is by value shape.\nexport type DataType =\n | \"System[Id]\"\n | \"Number\"\n | \"DateTime\"\n | \"System[DateTime]\"\n | \"Date\"\n | \"Age\"\n | \"SinglelineText\"\n | \"MultilineText\"\n | \"Mail\"\n | \"Telephone\"\n | \"URL\"\n | \"User\"\n | \"Option\"\n | \"System[Reference]\";\n\n/** A referenced User (Read is nested; Write is `User.P_Id` only). */\nexport type UserRef = {\n P_Id: number | null;\n P_Type: string | null;\n P_Name: string | null;\n P_Mail: string | null;\n};\n\n// `string[]` is the Option read value (a set of selected aliases — ADR-0017).\nexport type FieldValue = string | number | string[] | UserRef | null;\n\n// Per-Data-Type decoded value (the non-null shape). A read value is `DecodedValue<D> | null`\n// (empty -> null). Mirrors `decodeField`'s branches and drives the static resource Read type\n// (ADR-0019): id/number/reference -> number, User -> UserRef, Option -> string[], rest -> string.\nexport type DecodedValue<D extends DataType> = D extends\n | \"System[Id]\"\n | \"Number\"\n | \"System[Reference]\"\n ? number\n : D extends \"User\"\n ? UserRef\n : D extends \"Option\"\n ? string[]\n : string;\n\n// alias タグは接頭辞付き想定(例 `User.P_Id`)だが、接頭辞無しにも両対応(ADR-0011)。\n// 全 arrow(ADR-0013)=巻き上げ無しのため、ヘルパーを decodeField より前に定義する。\nconst pickPrefixed = (\n obj: Record<string, unknown>,\n prefix: string,\n key: string,\n): string | undefined =>\n asString(obj[`${prefix}.${key}`]) ?? asString(obj[key]);\n\nconst decodeUser = (raw: unknown): UserRef | null => {\n const outer = asRecord(raw);\n const user = outer ? asRecord(outer.User) : undefined;\n if (!user) return null;\n const id = pickPrefixed(user, \"User\", \"P_Id\");\n return {\n P_Id: id === undefined ? null : Number(id),\n P_Type: pickPrefixed(user, \"User\", \"P_Type\") ?? null,\n P_Name: pickPrefixed(user, \"User\", \"P_Name\") ?? null,\n P_Mail: pickPrefixed(user, \"User\", \"P_Mail\") ?? null,\n };\n};\n\n// Read: the selected leaf aliases (e.g. `<Option.P_Tokyo/>`) sit under `<OptionRoot>`.\n// PORTERS represents single/multi alike as a set, so return every selected alias verbatim\n// — incl. the `Option.` prefix (ADR-0017). None / empty -> null.\n// VERIFY(live): the `Option.` prefix and the `OptionRoot` wrapper come from the Read API\n// doc, not a live contract; we tolerate a missing wrapper. See docs/live-verification.md (LV-1, LV-2).\nconst decodeOption = (raw: unknown): string[] | null => {\n const outer = asRecord(raw);\n if (!outer) return null;\n // Aliases live under `<OptionRoot>` when present; the doc's sample omits it, so fall\n // back to the field's own children.\n const root = \"OptionRoot\" in outer ? asRecord(outer.OptionRoot) : outer;\n if (!root) return null;\n const keys = Object.keys(root);\n return keys.length > 0 ? keys : null;\n};\n\n// System[Reference] Read mirrors User: <Field><Resource>...</Resource></Field>, but the\n// inner tag varies (Client/Recruiter/...). Write is ID-only, so we decode the referenced\n// record's id — enough to round-trip. Richer reference reading is future work (SD-3).\n// NB: the label is literally `System[Reference]` (a nested record). It is NOT the\n// display-only Field-Type-16 \"Reference\" (a scalar mirror, Data Type `—`), left uncatalogued.\nconst decodeReference = (raw: unknown): number | null => {\n const outer = asRecord(raw);\n if (!outer) return null;\n // The nested resource is the first record-valued child (skip attributes / siblings,\n // which decodeUser avoids via a fixed key — here the tag varies). Read that record's\n // own `{Tag}.P_Id` (prefix-less also accepted), not just any key ending in P_Id.\n for (const [tag, value] of Object.entries(outer)) {\n const inner = asRecord(value);\n if (!inner) continue;\n const id = asString(inner[`${tag}.P_Id`]) ?? asString(inner.P_Id);\n return id === undefined ? null : Number(id);\n }\n return null;\n};\n\n/** Decode one field's raw node by its Data Type. */\nexport const decodeField = (type: DataType, raw: unknown): FieldValue => {\n // `raw === \"\"` is load-bearing (a Text \"\" must become null, not stay \"\");\n // `=== undefined` / `=== null` are defense-in-depth — every switch branch below\n // also maps them to null, so dropping either is an equivalent mutant.\n // Stryker disable next-line ConditionalExpression: see above (undefined/null are redundant with the switch)\n if (raw === \"\" || raw === undefined || raw === null) return null;\n switch (type) {\n case \"System[Id]\":\n case \"Number\": {\n // raw is neither \"\" nor non-string here (guarded above), so `s` is a\n // non-empty string or undefined — `s === \"\"` would be dead.\n const s = asString(raw);\n return s === undefined ? null : Number(s);\n }\n // String Data Types share one decode (a plain string); they stay distinct\n // labels for fidelity / future per-type validation (ADR-0016).\n case \"SinglelineText\":\n case \"MultilineText\":\n case \"Mail\":\n case \"Telephone\":\n case \"URL\":\n return asString(raw) ?? null;\n // FT-12 DateTime and the system timestamps (registration/update) share the wire\n // format; System[DateTime] is Write-restricted, but that is a write-time concern.\n case \"DateTime\":\n case \"System[DateTime]\": {\n const s = asString(raw);\n return s === undefined ? null : portersDateTimeToIso(s);\n }\n // Age shares Date's wire format (`yyyy/mm/dd`); PORTERS transmits the birthdate\n // and derives the age in its UI, so the faithful value is the date itself.\n case \"Date\":\n case \"Age\": {\n const s = asString(raw);\n return s === undefined ? null : portersDateToIso(s);\n }\n case \"User\":\n return decodeUser(raw);\n case \"Option\":\n return decodeOption(raw);\n case \"System[Reference]\":\n return decodeReference(raw);\n }\n};\n","// Shared Read internals for every resource — data (resource.ts) and master\n// (partition/user/field/option). Owns catalog typing, the catalog-driven item decoder, the\n// GET+parse+decode runner, and offset pagination. Data resources add Write on top; master\n// resources add bespoke query/URL building (ADR-0021/0022). XML stays in xml/ — this only\n// wires parse + decode together.\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decodeField,\n type DataType,\n type DecodedValue,\n type FieldValue,\n} from \"../xml/decode\";\nimport { parseResourcePage, type RawItem } from \"../xml/parser\";\n\n// A field catalog: bare alias -> Data Type. Declared `as const` per resource so the static\n// Read/Write types derive from it — the catalog is the single source of truth (ADR-0019).\nexport type FieldCatalog = Record<string, DataType>;\n\n/**\n * \"No custom fields\": the intersection-identity default for the generic catalog params (ADR-0023).\n * A bare `{}` is flagged by `no-empty-object-type`; `Record<never, never>` is the same empty object,\n * lint-clean, adds no keys in `static & C`, and satisfies both `FieldCatalog` and `DeclaredCatalogs`.\n * Lives here (with `FieldCatalog`) so resources need not import from the higher-level `fields/` (RV-8).\n */\nexport type EmptyCatalog = Record<never, never>;\n\n/**\n * A decoded record: every known field, each `DecodedValue | null`, and **optional** because a\n * field not named in `field` is simply absent (SD-3 \"simple\" type — ADR-0005/0019). Custom\n * `U_`/`A_` aliases are not in the catalog, so they are not typed here (access via a cast until\n * the declaration DSL lands — ADR-0005 SD-2); at runtime they still pass through as raw values.\n */\nexport type ReadRecord<F extends FieldCatalog> = {\n [K in keyof F]?: DecodedValue<F[K]> | null;\n};\n\nexport type ResourcePage<F extends FieldCatalog> = {\n items: ReadRecord<F>[];\n total: number;\n count: number;\n start: number;\n};\n\n// `includes(\".\")` -> `includes(\"\")` is an equivalent mutant: for a dotless key,\n// slice(indexOf(\".\") + 1) is slice(0), which equals the key — same as the else.\n// Stryker disable StringLiteral\nconst bareAlias = (key: string): string =>\n key.includes(\".\") ? key.slice(key.indexOf(\".\") + 1) : key;\n// Stryker restore StringLiteral\n\n/**\n * Build a catalog-driven item decoder: known `P_` fields decode by their Data Type, unknown\n * `U_`/`A_` aliases pass through (raw string, or null when nested). `bareAlias` strips the\n * `{prefix}.` so `Person.P_Name` and `P_Name` both hit the catalog.\n */\nexport const decoderFor = <F extends FieldCatalog>(\n fields: F,\n): ((item: RawItem) => ReadRecord<F>) => {\n const fieldMap = new Map<string, DataType>(Object.entries(fields));\n return (item) => {\n const out: Record<string, FieldValue> = {};\n for (const [key, raw] of Object.entries(item)) {\n const alias = bareAlias(key);\n const type = fieldMap.get(alias);\n out[alias] = type\n ? decodeField(type, raw)\n : typeof raw === \"string\"\n ? raw\n : null;\n }\n return out as ReadRecord<F>;\n };\n};\n\n/** GET a Read URL, parse the standard envelope (Total/Count/Start + Items), decode each item. */\nexport const runRead = <F extends FieldCatalog>(\n requester: Requester,\n url: string,\n decode: (item: RawItem) => ReadRecord<F>,\n): Promise<ResourcePage<F>> =>\n requester.request({ method: \"GET\", url, headers: {} }, (body) => {\n const page = parseResourcePage(body);\n return {\n items: page.items.map(decode),\n total: page.total,\n count: page.count,\n start: page.start,\n };\n });\n\n// Read max page size (docs/reference: count 1–200). searchAll pages by this.\nconst PAGE_SIZE = 200;\n\n/**\n * Offset pagination shared by every `searchAll`. Advances by the items actually returned and\n * stops at `total` — or on an empty page (defensive against a stuck offset / infinite loop).\n * A generator can't be an arrow; a function expression still satisfies func-style:expression.\n */\nexport const paginate = async function* <T>(\n fetchPage: (\n count: number,\n start: number,\n ) => Promise<{ items: T[]; total: number }>,\n): AsyncGenerator<T> {\n let start = 0;\n for (;;) {\n const page = await fetchPage(PAGE_SIZE, start);\n for (const item of page.items) yield item;\n start += page.items.length;\n if (page.items.length === 0 || start >= page.total) return;\n }\n};\n","// Generic resource accessor (ADR-0004/0005/0011): the Read (search / searchAll /\n// get) + Write (create / update) shape shared by every PORTERS resource. A resource\n// module supplies its names + Data-Type catalog; this owns the wiring and keeps XML\n// out of resources/ (parse/encode live in xml/). Standard `P_` fields use the catalog;\n// custom `U_`/`A_` pass through (decode: raw string / encode: Text).\n\nimport { PortersResourceError, resourceError } from \"../errors\";\nimport type { Requester } from \"../http/requester\";\nimport type { DataType } from \"../xml/decode\";\nimport {\n buildWriteXml,\n type WritableDataType,\n type WriteItem,\n type WriteValueOf,\n} from \"../xml/encode\";\nimport { parseWriteResult } from \"../xml/parser\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\n// Shared Read types/internals live in read-core (reused by master resources). Re-export the\n// types so the data-resource modules keep importing them from \"./resource\".\nexport type {\n EmptyCatalog,\n FieldCatalog,\n ReadRecord,\n ResourcePage,\n} from \"./read-core\";\n\nexport type SearchQuery = {\n /**\n * Output fields as prefixed aliases (e.g. `Person.P_Name`). **Omit** to fetch every catalogued\n * field by default (ADR-0020): PORTERS returns only the primary key for a fieldless request, so\n * the library sends a catalog-derived default field set instead. Pass `[]` to opt into that\n * API-native \"primary key only\" response (e.g. counting). A non-empty list is sent verbatim.\n */\n field?: string[];\n condition?: Record<string, string>;\n count?: number;\n start?: number;\n};\n\n// Writable aliases: every field whose Data Type a user may write (excludes System[Id] /\n// System[DateTime] — ADR-0016/0019).\ntype WritableKeys<F extends FieldCatalog> = {\n [K in keyof F]: F[K] extends WritableDataType ? K : never;\n}[keyof F];\n\n/**\n * Create input (ADR-0019 W2): the `requiredOnCreate` aliases are **required** (non-null); every\n * other writable field is optional (`null` omits). `P_Id` is supplied by the library — not here.\n */\nexport type CreateInput<F extends FieldCatalog, Req extends keyof F> = {\n [K in Req]: WriteValueOf<F[K]>;\n} & {\n [K in Exclude<WritableKeys<F>, Req>]?: WriteValueOf<F[K]> | null;\n};\n\n/** Update input (ADR-0019 W2): every writable field optional (`null` omits, `\"\"` clears). */\nexport type UpdateInput<F extends FieldCatalog> = {\n [K in WritableKeys<F>]?: WriteValueOf<F[K]> | null;\n};\n\n/** Static description of a resource: names + `as const` catalog + required-on-create aliases. */\nexport type ResourceConfig<\n F extends FieldCatalog,\n Req extends readonly (keyof F)[],\n> = {\n /** Root element + Write resource name, e.g. `\"Candidate\"`. */\n name: string;\n /** URL path segment, e.g. `\"candidate\"`. */\n path: string;\n /** Field alias prefix, e.g. `\"Person\"`. */\n prefix: string;\n /** Data-Type catalog (`as const`): bare alias -> Data Type. */\n fields: F;\n /** Aliases required on `create` (PORTERS new-record requirements — ADR-0019 W2). */\n requiredOnCreate: Req;\n};\n\nexport type Resource<F extends FieldCatalog, Req extends keyof F> = {\n search(query?: SearchQuery): Promise<ResourcePage<F>>;\n /** Auto-paginating search: yields every matching record (200 per page). */\n searchAll(\n query?: Omit<SearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<ReadRecord<F>>;\n get(id: number): Promise<ReadRecord<F> | undefined>;\n /** Create one record; resolves to the newly assigned id. */\n create(input: CreateInput<F, Req>): Promise<number>;\n /** Update one record by id; resolves to that id. */\n update(id: number, input: UpdateInput<F>): Promise<number>;\n};\n\n// The 4 readable sub-fields of a User-type field (docs/reference: only these are returned).\nconst USER_SUBFIELDS = [\"P_Id\", \"P_Type\", \"P_Name\", \"P_Mail\"] as const;\n\n// Default Read `field` list derived from the catalog (ADR-0020, 案A+2a). PORTERS returns only\n// `{Resource}.P_Id` for a fieldless request, so a typed-record read would otherwise drop every\n// known field despite the type promising them. We send every catalog alias as `{prefix}.{alias}`,\n// expanding User to its 4 readable sub-fields and leaving System[Reference] ID-only (`()` omitted)\n// so the wire shape matches decode.ts. The API-native \"primary key only\" stays reachable via\n// `field: []` (透明化 — see SearchQuery.field).\nconst defaultFieldList = (prefix: string, fields: FieldCatalog): string[] =>\n Object.entries(fields).map(([alias, type]) =>\n type === \"User\"\n ? `${prefix}.${alias}(${USER_SUBFIELDS.map((s) => `User.${s}`).join(\",\")})`\n : `${prefix}.${alias}`,\n );\n\n/**\n * A single-Item Write response -> the assigned/updated id. A non-zero per-item Code is a\n * resource error (mapped, not swallowed); a missing result Item is unparseable. Shared by\n * the generic factory and the bespoke Attachment accessor. `path` names the error code\n * message, `name` the error context resource.\n */\nexport const firstWriteResultId = (\n body: string,\n path: string,\n name: string,\n): number => {\n const first = parseWriteResult(body)[0];\n if (first === undefined) {\n throw new PortersResourceError(\"write returned no result item\", {\n category: \"unknown\",\n });\n }\n if (first.code !== 0) {\n throw resourceError(\n first.code,\n `${path} write returned code ${first.code}`,\n {\n resource: name,\n },\n );\n }\n return first.id;\n};\n\n/** Build a Read URL: `https://{host}/v1/{path}?partition=…&field=…&condition=…&count=…&start=…`. */\nexport const buildReadUrl = (\n host: string,\n partition: number,\n path: string,\n q: SearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n if (q.field && q.field.length > 0) p.set(\"field\", q.field.join(\",\"));\n if (q.condition) {\n const conds = Object.entries(q.condition).map(([k, v]) => `${k}=${v}`);\n if (conds.length > 0) p.set(\"condition\", conds.join(\",\"));\n }\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/${path}?${p.toString()}`;\n};\n\n/** Build a Write URL: `https://{host}/v1/{path}?partition=…`. */\nexport const buildWriteUrl = (\n host: string,\n partition: number,\n path: string,\n): string => `https://${host}/v1/${path}?partition=${partition}`;\n\nexport const createResource = <\n const F extends FieldCatalog,\n const Req extends readonly (keyof F)[],\n>(\n config: ResourceConfig<F, Req>,\n deps: { requester: Requester; host: string; partition: number },\n): Resource<F, Req[number]> => {\n // The catalog is `as const` for the types; encode needs a runtime lookup, decode gets its own.\n const fieldMap = new Map<string, DataType>(Object.entries(config.fields));\n const decode = decoderFor(config.fields);\n // Computed once: the default field set sent when a caller omits `field` (ADR-0020).\n const defaultFields = defaultFieldList(config.prefix, config.fields);\n\n const readUrl = (q: SearchQuery): string =>\n buildReadUrl(deps.host, deps.partition, config.path, q);\n\n const writeUrl = (): string =>\n buildWriteUrl(deps.host, deps.partition, config.path);\n\n const firstWriteId = (body: string): number =>\n firstWriteResultId(body, config.path, config.name);\n\n // `field` omitted -> send the catalog default; `[]` stays empty (API-native primary key\n // only); a provided list is sent verbatim (ADR-0020).\n const search = (query: SearchQuery = {}): Promise<ResourcePage<F>> =>\n runRead(\n deps.requester,\n readUrl({ ...query, field: query.field ?? defaultFields }),\n decode,\n );\n\n const searchAll = (\n query: Omit<SearchQuery, \"count\" | \"start\"> = {},\n ): AsyncIterable<ReadRecord<F>> =>\n paginate((count, start) => search({ ...query, count, start }));\n\n const get = async (id: number): Promise<ReadRecord<F> | undefined> => {\n const page = await search({\n condition: { [`${config.prefix}.P_Id:eq`]: String(id) },\n count: 1,\n });\n return page.items[0];\n };\n\n // create forces P_Id=-1 (non-idempotent: a retry would duplicate); update forces\n // the target id (idempotent: re-applying the same write is safe). Forcing P_Id\n // after the spread means a caller-supplied P_Id never overrides it.\n const write = (item: WriteItem, idempotent: boolean): Promise<number> =>\n deps.requester.request(\n {\n method: \"POST\",\n url: writeUrl(),\n headers: {},\n body: buildWriteXml({\n resource: config.name,\n prefix: config.prefix,\n fields: fieldMap,\n items: [item],\n }),\n },\n firstWriteId,\n { write: true, idempotent },\n );\n\n const create = (input: CreateInput<F, Req[number]>): Promise<number> =>\n write({ ...input, P_Id: -1 }, false);\n\n const update = (id: number, input: UpdateInput<F>): Promise<number> =>\n write({ ...input, P_Id: id }, true);\n\n return { search, searchAll, get, create, update };\n};\n","// Candidate accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Only the Data-Type catalog and names\n// are Candidate-specific; the static Candidate / input types derive from the catalog\n// (single source of truth — ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_Name: \"SinglelineText\",\n P_Reading: \"SinglelineText\",\n P_Mail: \"Mail\",\n P_MobileMail: \"Mail\",\n P_Telephone: \"Telephone\",\n P_Mobile: \"Telephone\",\n P_Country: \"SinglelineText\",\n P_Prefecture: \"SinglelineText\",\n P_City: \"SinglelineText\",\n P_Zipcode: \"SinglelineText\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/candidate.md「新規必須」列): P_Owner。\n// (System[Id] の P_Id も新規必須だが lib が -1 を供給するため型からは除外。LV-5 は reference で確定。)\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Candidate: known `P_` fields, each requested field `value | null`. */\nexport type Candidate = ReadRecord<typeof FIELDS>;\nexport type CandidatePage = ResourcePage<typeof FIELDS>;\nexport type CandidateSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` is required; `P_Id` / system timestamps are not settable. */\nexport type CandidateCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type CandidateUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Candidate accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type CandidateResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createCandidateResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): CandidateResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Candidate\",\n path: \"candidate\",\n prefix: \"Person\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Job accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Only the Data-Type catalog and\n// names are Job-specific. P_Client / P_Recruiter are System[Reference] (Write = ID).\n//\n// Display-only Reference fields (P_Mail, P_*Reference — they mirror a Recruiter value and\n// are not writable) are intentionally left out of the catalog: they read through as raw\n// strings. Multi-select Option read returns every selected alias as `string[]` (ADR-0017).\n// The static Job / input types derive from the catalog (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_Client: \"System[Reference]\",\n P_Recruiter: \"System[Reference]\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Position: \"SinglelineText\",\n P_Publish: \"Option\",\n P_JobCategorySummary: \"MultilineText\",\n P_JobCategory: \"Option\",\n P_IndustrySummary: \"MultilineText\",\n P_Industry: \"Option\",\n P_SalarySummary: \"MultilineText\",\n P_MinSalary: \"Number\",\n P_MaxSalary: \"Number\",\n P_AreaSummary: \"MultilineText\",\n P_Area: \"Option\",\n P_PayrollsText: \"SinglelineText\",\n P_Memo: \"MultilineText\",\n P_EmploymentPeriod: \"MultilineText\",\n // \"P_WokingHours\" is the alias as published by PORTERS (source typo); keep verbatim.\n P_WokingHours: \"MultilineText\",\n P_Holidays: \"MultilineText\",\n P_Benefits: \"MultilineText\",\n P_PubliclyTraded: \"Option\",\n P_SalesAmountText: \"SinglelineText\",\n P_EstablishmentDateText: \"SinglelineText\",\n P_CapitalText: \"SinglelineText\",\n P_EmploymentType: \"Option\",\n P_ExpectedAgeReason: \"Option\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/job.md「新規必須」列): P_Owner / P_Client /\n// P_Recruiter(P_Id は System[Id]=lib 供給のため除外)。LV-5 は reference で確定。\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n \"P_Client\",\n \"P_Recruiter\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Job: known `P_` fields, each requested field `value | null`. */\nexport type Job = ReadRecord<typeof FIELDS>;\nexport type JobPage = ResourcePage<typeof FIELDS>;\nexport type JobSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type JobCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type JobUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Job accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type JobResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createJobResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): JobResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Job\",\n path: \"job\",\n prefix: \"Job\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Client accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Only the Data-Type catalog and\n// names are Client-specific; the static Client / input types derive from the catalog\n// (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Name: \"SinglelineText\",\n P_Memo: \"MultilineText\",\n P_Country: \"SinglelineText\",\n P_Prefecture: \"SinglelineText\",\n P_City: \"SinglelineText\",\n P_Street: \"MultilineText\",\n P_Zipcode: \"SinglelineText\",\n P_Telephone: \"Telephone\",\n P_Fax: \"Telephone\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/client.md「新規必須」列): P_Owner。\n// (P_Id は System[Id]=lib 供給のため除外。LV-5 は reference で確定。)\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Client (company): known `P_` fields, each requested field `value | null`. */\nexport type Client = ReadRecord<typeof FIELDS>;\nexport type ClientPage = ResourcePage<typeof FIELDS>;\nexport type ClientSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type ClientCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type ClientUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Client accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type ClientResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createClientResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): ClientResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Client\",\n path: \"client\",\n prefix: \"Client\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Process accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Process is the relational\n// resource linking a Candidate to a Job; P_Client / P_Recruiter / P_Job / P_Candidate /\n// P_Resume are System[Reference] (Write = the related record's id; P_Candidate is the\n// Person id).\n//\n// Display-only Reference fields (P_JobOwner, P_Job*Reference, P_ResumeOwner,\n// P_Resume*Reference — they mirror a Job/Recruiter/Person value and are not writable) are\n// intentionally left out of the catalog: scalar mirrors read through as raw strings,\n// nested ones (e.g. P_JobOwner -> a User) read as null. Multi-select Option read returns every\n// selected alias as `string[]` (ADR-0017). The static Process / input types derive from the catalog (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_Client: \"System[Reference]\",\n P_Recruiter: \"System[Reference]\",\n P_Job: \"System[Reference]\",\n P_Candidate: \"System[Reference]\",\n P_Resume: \"System[Reference]\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Close: \"Option\",\n P_CloseReason: \"Option\",\n P_ExpectedSalesAmount: \"Number\",\n P_ExpectedClosingDate: \"Date\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/process.md「新規必須」列): P_Owner と関連 5 項目\n// (P_Client / P_Recruiter / P_Job / P_Candidate / P_Resume)。P_Id は System[Id]=lib 供給で除外。\n// LV-5 は reference で確定。\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n \"P_Client\",\n \"P_Recruiter\",\n \"P_Job\",\n \"P_Candidate\",\n \"P_Resume\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Process (a Candidate's progress through a Job): known `P_` fields, each\n * requested field `value | null`. */\nexport type Process = ReadRecord<typeof FIELDS>;\nexport type ProcessPage = ResourcePage<typeof FIELDS>;\nexport type ProcessSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type ProcessCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type ProcessUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Process accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type ProcessResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createProcessResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): ProcessResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Process\",\n path: \"process\",\n prefix: \"Process\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Resume accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. A Resume belongs to a Candidate;\n// P_Candidate is System[Reference] (Write = the Person id).\n//\n// P_DateOfBirth is the Age Data Type — catalogued as \"Age\". Its wire value is the\n// birthdate (`yyyy/mm/dd`, same as Date); PORTERS derives the displayed age in its UI.\n// Display-only Reference fields (P_Mail, P_*Reference — they mirror a Person value and are\n// not writable) are intentionally left out of the catalog: scalar mirrors read through as\n// raw strings. Multi-select Option read returns every selected alias as `string[]` (ADR-0017).\n// Image-typed custom fields (U_) are future work. The static Resume / input types derive from the catalog (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_Candidate: \"System[Reference]\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Name: \"SinglelineText\",\n P_RegisterChannel: \"Option\",\n P_Memo: \"MultilineText\",\n P_CurrentStatus: \"Option\",\n P_Education: \"MultilineText\",\n P_CarrierSummary: \"MultilineText\",\n P_CurrentSalary: \"Number\",\n P_ExperiencedJobCategory: \"Option\",\n P_ExperiencedIndustry: \"Option\",\n P_ChangeJobsCount: \"Number\",\n P_Gender: \"Option\",\n P_DateOfBirth: \"Age\",\n P_ExpectEmploymentType: \"Option\",\n P_ExpectArea: \"Option\",\n P_ExpectJobCategory: \"Option\",\n P_ExpectIndustry: \"Option\",\n P_ExpectCondition: \"MultilineText\",\n P_ExpectSalary: \"Number\",\n P_DesiredHourlyRate: \"Number\",\n P_HourlyRate: \"Number\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/resume.md「新規必須」列): P_Owner / P_Candidate\n// (P_Id は System[Id]=lib 供給のため除外)。LV-5 は reference で確定。\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n \"P_Candidate\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Resume (a Candidate's CV / profile): known `P_` fields, each requested field\n * `value | null`. */\nexport type Resume = ReadRecord<typeof FIELDS>;\nexport type ResumePage = ResourcePage<typeof FIELDS>;\nexport type ResumeSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type ResumeCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type ResumeUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Resume accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type ResumeResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createResumeResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): ResumeResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Resume\",\n path: \"resume\",\n prefix: \"Resume\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Attachment accessor (ADR-0018, bespoke): Read (search / get) + Write (create / update)\n// for file attachments. Attachment is unlike the other resources — no alias prefix, fixed\n// short field names (Id / Resource / ResourceId / ContentType / FileName / Content), and\n// `Content` is the Base64 file body (up to 10MB). It does not fit the generic factory but\n// reuses the requester, parsers, and `firstWriteResultId`. Turn raw bytes into the Base64\n// `content` with `util/base64`.\n\nimport { PortersConfigError } from \"../errors\";\nimport type { Requester } from \"../http/requester\";\nimport { encodeField } from \"../xml/encode\";\nimport { parseResourcePage } from \"../xml/parser\";\nimport { asString } from \"../xml/raw\";\nimport { buildReadUrl, buildWriteUrl, firstWriteResultId } from \"./resource\";\n\n// A 10MB file is ~13.98M Base64 chars; cap the encoded Content length before send\n// (fail-safe — the ~15000-char request guard is bypassed for uploads). docs/reference.\nconst MAX_CONTENT_CHARS = 14_000_000;\n\nconst ALL_FIELDS = [\n \"Id\",\n \"Resource\",\n \"ResourceId\",\n \"ContentType\",\n \"FileName\",\n \"Content\",\n];\n\n// Default for search() when `field` is omitted (ADR-0020): metadata only — exclude the (large,\n// up to ~14MB Base64) `Content` so listing attachments doesn't download every file body. Fetch\n// `Content` explicitly via `field` or per-record via get(). Mirrors PORTERS' Image default\n// (FileName only). `field: []` still opts into the API-native primary-key-only response.\nconst DEFAULT_FIELDS = [\n \"Id\",\n \"Resource\",\n \"ResourceId\",\n \"ContentType\",\n \"FileName\",\n];\n\n/** A decoded Attachment. A field is `null` unless it was returned (see `field`). */\nexport type Attachment = {\n id: number | null;\n /** Related resource type code (see the PORTERS Resource List). */\n resource: number | null;\n /** Related record id. */\n resourceId: number | null;\n contentType: string | null;\n fileName: string | null;\n /** Base64 file body. */\n content: string | null;\n};\n\nexport type AttachmentPage = {\n items: Attachment[];\n total: number;\n count: number;\n start: number;\n};\n\nexport type AttachmentSearchQuery = {\n /**\n * Output fields. **Omit** to fetch metadata by default (Id / Resource / ResourceId /\n * ContentType / FileName) — the large Base64 `Content` is excluded so listing doesn't download\n * every file body (ADR-0020); request `[\"Content\", …]` or use `get()` for the body. Pass `[]`\n * for the API-native primary-key-only response. A non-empty list is sent verbatim.\n */\n field?: string[];\n condition?: Record<string, string>;\n count?: number;\n start?: number;\n};\n\n/** Fields for creating an Attachment. `content` is the Base64 file body. */\nexport type AttachmentCreate = {\n resource: number;\n resourceId: number;\n contentType: string;\n fileName: string;\n content: string;\n};\n\n/** Fields for updating an Attachment. `Resource` / `ResourceId` are not updatable. */\nexport type AttachmentUpdate = {\n contentType?: string;\n fileName?: string;\n content?: string;\n};\n\nexport type AttachmentResource = {\n search(query?: AttachmentSearchQuery): Promise<AttachmentPage>;\n get(id: number): Promise<Attachment | undefined>;\n /** Create an Attachment; resolves to the newly assigned id. */\n create(input: AttachmentCreate): Promise<number>;\n /** Update an Attachment by id; resolves to that id. */\n update(id: number, input: AttachmentUpdate): Promise<number>;\n};\n\nconst numOrNull = (v: unknown): number | null => {\n const s = asString(v);\n return s === undefined ? null : Number(s);\n};\n\nconst decodeAttachment = (item: Record<string, unknown>): Attachment => ({\n id: numOrNull(item.Id),\n resource: numOrNull(item.Resource),\n resourceId: numOrNull(item.ResourceId),\n contentType: asString(item.ContentType) ?? null,\n fileName: asString(item.FileName) ?? null,\n content: asString(item.Content) ?? null,\n});\n\n// Bare `<Tag>value</Tag>` (Attachment has no alias prefix). encodeField escapes the value.\nconst tag = (name: string, value: string | number): string =>\n `<${name}>${encodeField(\"SinglelineText\", String(value))}</${name}>`;\n\n// Reject an over-10MB file before send (the request size guard is bypassed for uploads).\nconst guardContent = (content: string | undefined): void => {\n if (content !== undefined && content.length > MAX_CONTENT_CHARS) {\n throw new PortersConfigError(\n `attachment content is ${content.length} characters, over the ~10MB file limit`,\n { category: \"config\", hint: \"Attachment files must be 10MB or less.\" },\n );\n }\n};\n\nexport const createAttachmentResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): AttachmentResource => {\n // `field` omitted -> metadata default (no Content); `[]` -> API-native primary key only;\n // a provided list is sent verbatim (ADR-0020).\n const search = (query: AttachmentSearchQuery = {}): Promise<AttachmentPage> =>\n deps.requester.request(\n {\n method: \"GET\",\n url: buildReadUrl(deps.host, deps.partition, \"attachment\", {\n ...query,\n field: query.field ?? DEFAULT_FIELDS,\n }),\n headers: {},\n },\n (body) => {\n const page = parseResourcePage(body);\n return {\n items: page.items.map(decodeAttachment),\n total: page.total,\n count: page.count,\n start: page.start,\n };\n },\n );\n\n // VERIFY(live): Attachment has no alias prefix; the `Id:eq` condition and requesting all\n // fields (incl. Content) are taken from the field list, not a live contract.\n // See docs/live-verification.md (LV-3, LV-4).\n const get = async (id: number): Promise<Attachment | undefined> => {\n const page = await search({\n field: ALL_FIELDS,\n condition: { \"Id:eq\": String(id) },\n count: 1,\n });\n return page.items[0];\n };\n\n const write = (inner: string, idempotent: boolean): Promise<number> =>\n deps.requester.request(\n {\n method: \"POST\",\n url: buildWriteUrl(deps.host, deps.partition, \"attachment\"),\n headers: {},\n body: `<Attachment><Item>${inner}</Item></Attachment>`,\n },\n (body) => firstWriteResultId(body, \"attachment\", \"Attachment\"),\n { write: true, idempotent, unboundedBody: true },\n );\n\n // create forces Id=-1 (non-idempotent). All fields are required.\n const create = (input: AttachmentCreate): Promise<number> => {\n guardContent(input.content);\n const inner =\n tag(\"Id\", -1) +\n tag(\"Resource\", input.resource) +\n tag(\"ResourceId\", input.resourceId) +\n tag(\"ContentType\", input.contentType) +\n tag(\"FileName\", input.fileName) +\n tag(\"Content\", input.content);\n return write(inner, false);\n };\n\n // update targets the id (idempotent). Resource / ResourceId can't change; only the\n // provided fields are sent.\n const update = (id: number, input: AttachmentUpdate): Promise<number> => {\n guardContent(input.content);\n let inner = tag(\"Id\", id);\n if (input.contentType !== undefined) {\n inner += tag(\"ContentType\", input.contentType);\n }\n if (input.fileName !== undefined) inner += tag(\"FileName\", input.fileName);\n if (input.content !== undefined) inner += tag(\"Content\", input.content);\n return write(inner, true);\n };\n\n return { search, get, create, update };\n};\n","// Partition master accessor (read-only — ADR-0021/0022). Partition Read discovers the\n// partitions an App can access. It takes neither `partition` nor `field`/`condition`, only\n// `request_type`: 1 = the accessible-partition list (works under code_direct; the default),\n// 0 = the login partition (only under the browser `code` grant — 403s under code_direct, so\n// it is not exposed; ADR-0022 D3b). No `get(id)`: the API has no id/condition filter.\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Name: \"SinglelineText\",\n P_CompanyId: \"SinglelineText\",\n} as const satisfies FieldCatalog;\n\n/** A decoded Partition (a PORTERS contract company / Company DB). */\nexport type Partition = ReadRecord<typeof FIELDS>;\nexport type PartitionPage = ResourcePage<typeof FIELDS>;\n\n/** Partition Read query. `requestType` 1 = partitions this App can access (default). */\nexport type PartitionSearchQuery = {\n /** 1 = accessible partitions (default). 0 = login partition (browser `code` grant only). */\n requestType?: 0 | 1;\n count?: number;\n start?: number;\n};\n\nexport type PartitionResource = {\n search(query?: PartitionSearchQuery): Promise<PartitionPage>;\n /** Auto-paginating search: yields every accessible partition. */\n searchAll(\n query?: Omit<PartitionSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<Partition>;\n};\n\n// VERIFY(live): Partition Read taking no `partition` param is doc-only (every other read\n// requires it). See docs/live-verification.md (LV-8).\nconst buildUrl = (host: string, q: PartitionSearchQuery): string => {\n const p = new URLSearchParams();\n p.set(\"request_type\", String(q.requestType ?? 1));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/partition?${p.toString()}`;\n};\n\nexport const createPartitionResource = (deps: {\n requester: Requester;\n host: string;\n}): PartitionResource => {\n const decode = decoderFor(FIELDS);\n const search = (query: PartitionSearchQuery = {}): Promise<PartitionPage> =>\n runRead(deps.requester, buildUrl(deps.host, query), decode);\n const searchAll = (\n query: Omit<PartitionSearchQuery, \"count\" | \"start\"> = {},\n ): AsyncIterable<Partition> =>\n paginate((count, start) => search({ ...query, count, start }));\n return { search, searchAll };\n};\n","// User master accessor (read-only — ADR-0021/0022). User Read requires `partition` and\n// `request_type` (1 = all users; 0 = the current user — under code_direct this is the App's\n// own user, i.e. self-identification). `field` defaults to the 4 readable core fields, which\n// is exactly this catalog, so we omit it unless the caller narrows. No `condition`/`get(id)`:\n// the API has no id filter. Extended HR fields (department/telephone/dates/…) are deferred —\n// their read availability/decode shape is unconfirmed (see docs/live-verification.md).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Type: \"Number\",\n P_Name: \"SinglelineText\",\n P_Mail: \"Mail\",\n} as const satisfies FieldCatalog;\n\n/** A decoded User (PORTERS operator). `P_Type`: 0 = standard user, 1 = system admin. */\nexport type User = ReadRecord<typeof FIELDS>;\nexport type UserPage = ResourcePage<typeof FIELDS>;\n\n/** User Read query. `requestType` 1 = all users (default); `userType` -1 = any (default). */\nexport type UserSearchQuery = {\n /** 1 = all users (default). 0 = the current user (code_direct → the App's own user). */\n requestType?: 0 | 1;\n /** -1 = any (default), 0 = system admins, 1 = standard users. */\n userType?: -1 | 0 | 1;\n /** Output fields (prefixed aliases). Omit to get the 4 core fields (this catalog). */\n field?: string[];\n count?: number;\n start?: number;\n};\n\nexport type UserResource = {\n search(query?: UserSearchQuery): Promise<UserPage>;\n /** Auto-paginating search: yields every matching user. */\n searchAll(\n query?: Omit<UserSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<User>;\n /**\n * The current API user (`request_type=0`). Under the library's default `code_direct` auth\n * this resolves to the App's own user (username = app name) — useful for self-identification.\n * Under the browser `code` grant it is the logged-in user. Resolves `undefined` if none.\n */\n current(): Promise<User | undefined>;\n};\n\nconst buildUrl = (\n host: string,\n partition: number,\n q: UserSearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n p.set(\"request_type\", String(q.requestType ?? 1));\n p.set(\"user_type\", String(q.userType ?? -1));\n if (q.field && q.field.length > 0) p.set(\"field\", q.field.join(\",\"));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/user?${p.toString()}`;\n};\n\nexport const createUserResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): UserResource => {\n const decode = decoderFor(FIELDS);\n const search = (query: UserSearchQuery = {}): Promise<UserPage> =>\n runRead(deps.requester, buildUrl(deps.host, deps.partition, query), decode);\n const searchAll = (\n query: Omit<UserSearchQuery, \"count\" | \"start\"> = {},\n ): AsyncIterable<User> =>\n paginate((count, start) => search({ ...query, count, start }));\n // VERIFY(live): code_direct + request_type=0 returning the App's own user is doc-only.\n // See docs/live-verification.md (LV-7).\n const current = async (): Promise<User | undefined> =>\n (await search({ requestType: 0, count: 1 })).items[0];\n return { search, searchAll, current };\n};\n","// Field master accessor (read-only — ADR-0021/0022). Field Read introspects a resource's\n// field catalog (standard `P_` + tenant `U_`/`A_`). It requires `partition` and `resource`\n// (a resource-type Value code), plus optional `active`. No `field`/`condition`/`get(id)`.\n// `P_ReferTo` is a nested alias (the option group for Option-type fields, the parent field for\n// Reference-type) — decoded like an Option value to the referenced alias(es) (ADR-0022).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\n// Resource-type selector -> Value code (docs/reference resources-list). Master/Phase/Attachment\n// have no Value, so only the R/W data resources are selectable here.\nconst RESOURCE_VALUE = {\n candidate: 1,\n job: 3,\n client: 5,\n recruiter: 9,\n sales: 11,\n contract: 13,\n resume: 17,\n activity: 19,\n opportunity: 25,\n contact: 27,\n} as const;\n\n/** A resource whose field catalog can be read (Field Read `resource` selector). */\nexport type ResourceType = keyof typeof RESOURCE_VALUE;\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Name: \"SinglelineText\",\n P_Alias: \"SinglelineText\",\n P_Type: \"Number\",\n P_Required: \"Number\",\n P_Max: \"Number\",\n P_Min: \"Number\",\n P_DecimalFraction: \"Number\",\n // Nested alias(es): the referenced option group / parent field. Reuse Option decode -> the\n // referenced alias(es) as string[] (usually one); empty -> null (ADR-0017/0022).\n // VERIFY(live): Reference-type P_ReferTo nesting is doc-only. See docs/live-verification.md (LV-6).\n P_ReferTo: \"Option\",\n P_ResourceType: \"Number\",\n} as const satisfies FieldCatalog;\n\n/** A decoded Field definition. `P_Required`: 0 = normal, 1 = required. */\nexport type Field = ReadRecord<typeof FIELDS>;\nexport type FieldPage = ResourcePage<typeof FIELDS>;\n\n/** Field Read query. `resource` selects which resource's fields to read (required). */\nexport type FieldSearchQuery = {\n resource: ResourceType;\n /** -1 = all (default), 0 = unused only, 1 = in-use only. */\n active?: -1 | 0 | 1;\n count?: number;\n start?: number;\n};\n\nexport type FieldResource = {\n search(query: FieldSearchQuery): Promise<FieldPage>;\n /** Auto-paginating search: yields every field of the resource. */\n searchAll(\n query: Omit<FieldSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<Field>;\n};\n\nconst buildUrl = (\n host: string,\n partition: number,\n q: FieldSearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n p.set(\"resource\", String(RESOURCE_VALUE[q.resource]));\n p.set(\"active\", String(q.active ?? -1));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/field?${p.toString()}`;\n};\n\nexport const createFieldResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): FieldResource => {\n const decode = decoderFor(FIELDS);\n const search = (query: FieldSearchQuery): Promise<FieldPage> =>\n runRead(deps.requester, buildUrl(deps.host, deps.partition, query), decode);\n const searchAll = (\n query: Omit<FieldSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<Field> =>\n paginate((count, start) => search({ ...query, count, start }));\n return { search, searchAll };\n};\n","// Option master accessor (read-only — ADR-0021/0022). Option Read returns a tenant's choice\n// master as a recursive tree: each <Item> nests child <Item>s under <Items>. We flatten the\n// tree depth-first into one array — every node present, parent linkage kept via `P_ParentId`\n// and ordering via `P_Order` (ADR-0021 軸3, case 3a). It requires `partition` and takes\n// `alias`/`level`/`enabled`/`count` — no `start` (no offset paging → no searchAll), no\n// `field`/`condition`/`get(id)`.\n\nimport type { Requester } from \"../http/requester\";\nimport { parseResourcePage, type RawItem } from \"../xml/parser\";\nimport { asArray, asRecord } from \"../xml/raw\";\nimport { decoderFor, type FieldCatalog, type ReadRecord } from \"./read-core\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Name: \"SinglelineText\",\n P_Alias: \"SinglelineText\",\n P_ParentId: \"Number\",\n P_Type: \"Number\",\n P_Order: \"Number\",\n} as const satisfies FieldCatalog;\n\n/** A decoded Option (one choice). `P_ParentId` links to the parent; `P_Type` 0 = normal, 1–11 = a phase kind. */\nexport type Option = ReadRecord<typeof FIELDS>;\n\n/** Option Read query. `alias` selects a subtree root; `level` its depth (-1 all). */\nexport type OptionSearchQuery = {\n /** Root alias of the subtree to read (e.g. `Option.P_Gender`). Omit for all. */\n alias?: string;\n /** Depth: -1 all (default), 0 = siblings of `alias`, 1+ = descendants. */\n level?: number;\n /** -1 = all (default), 0 = unused only, 1 = in-use only. */\n enabled?: -1 | 0 | 1;\n count?: number;\n};\n\nexport type OptionResource = {\n /** Read options, flattened depth-first (all nodes; tree is reconstructable via `P_ParentId`). */\n search(query?: OptionSearchQuery): Promise<Option[]>;\n};\n\nconst buildUrl = (\n host: string,\n partition: number,\n q: OptionSearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n if (q.alias !== undefined) p.set(\"alias\", q.alias);\n if (q.level !== undefined) p.set(\"level\", String(q.level));\n if (q.enabled !== undefined) p.set(\"enabled\", String(q.enabled));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n return `https://${host}/v1/option?${p.toString()}`;\n};\n\n// Decode one node's own fields, dropping the nested `Items` collection (handled by the walk).\nconst withoutItems = (raw: RawItem): RawItem =>\n Object.fromEntries(Object.entries(raw).filter(([k]) => k !== \"Items\"));\n\nexport const createOptionResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): OptionResource => {\n const decode = decoderFor(FIELDS);\n // Depth-first flatten: push each node, then recurse into its <Items><Item>… children.\n const flatten = (items: RawItem[], out: Option[]): void => {\n for (const raw of items) {\n out.push(decode(withoutItems(raw)));\n const children = asArray(asRecord(raw.Items)?.Item).map(\n (it) => asRecord(it) ?? {},\n );\n flatten(children, out);\n }\n };\n const search = (query: OptionSearchQuery = {}): Promise<Option[]> =>\n deps.requester.request(\n {\n method: \"GET\",\n url: buildUrl(deps.host, deps.partition, query),\n headers: {},\n },\n (body) => {\n const out: Option[] = [];\n flatten(parseResourcePage(body).items, out);\n return out;\n },\n );\n return { search };\n};\n","import { createDefaultTokenProvider } from \"./auth\";\nimport type { TokenProvider, TokenStore } from \"./auth\";\nimport {\n createFetchTransport,\n createRequester,\n createThrottle,\n expoBackoff,\n} from \"./http\";\nimport type { Transport } from \"./http\";\nimport {\n createAttachmentResource,\n createCandidateResource,\n createClientResource,\n createFieldResource,\n createJobResource,\n createOptionResource,\n createPartitionResource,\n createProcessResource,\n createResumeResource,\n createUserResource,\n} from \"./resources\";\nimport type {\n AttachmentResource,\n CandidateResource,\n ClientResource,\n FieldResource,\n JobResource,\n OptionResource,\n PartitionResource,\n ProcessResource,\n ResumeResource,\n UserResource,\n} from \"./resources\";\nimport type { CustomFor, DeclaredCatalogs, DefinedFields } from \"./fields\";\nimport type { EmptyCatalog } from \"./resources/read-core\";\nimport type { PartitionId, Scope } from \"./types\";\n\n/** Options for constructing a {@link PortersClient}. `C` is inferred from `fields` (ADR-0023). */\nexport type PortersClientOptions<C extends DeclaredCatalogs = EmptyCatalog> = {\n /**\n * API host. Required and supplied via `PORTERS_HOST` — never hard-code it.\n * (A representative value lives in docs/reference.)\n */\n host: string;\n appId?: string;\n appSecret?: string;\n scopes?: Scope[];\n /** Default partition; overridable per call (ADR-0008). */\n partition?: PartitionId;\n /** Custom auth strategy; defaults to the transparent code_direct strategy. */\n auth?: TokenProvider;\n /** Token persistence; defaults to in-memory. */\n tokenStore?: TokenStore;\n /** Injectable HTTP transport; defaults to a fetch-based transport. */\n transport?: Transport;\n /**\n * Tenant custom field declarations from {@link defineFields} (ADR-0023). Each resource's\n * declared `U_`/`A_` fields are merged onto its static catalog, so they decode/encode by\n * their declared Data Type and appear typed on reads / writes. Omit for standard `P_` only.\n */\n fields?: DefinedFields<C>;\n};\n\n/**\n * Entry point of the library. Wires the default transport / auth / throttle /\n * requester and exposes namespaced resource accessors such as `candidate`\n * (ADR-0005).\n */\nexport class PortersClient<C extends DeclaredCatalogs = EmptyCatalog> {\n readonly candidate: CandidateResource<CustomFor<C, \"candidate\">>;\n readonly job: JobResource<CustomFor<C, \"job\">>;\n readonly client: ClientResource<CustomFor<C, \"client\">>;\n readonly process: ProcessResource<CustomFor<C, \"process\">>;\n readonly resume: ResumeResource<CustomFor<C, \"resume\">>;\n readonly attachment: AttachmentResource;\n /** Master Read: accessible partitions (ADR-0021/0022). */\n readonly partition: PartitionResource;\n /** Master Read: users, plus `current()` self-identification (ADR-0021/0022). */\n readonly user: UserResource;\n /** Master Read: a resource's field catalog (ADR-0021/0022). */\n readonly field: FieldResource;\n /** Master Read: a tenant's choice (option) master (ADR-0021/0022). */\n readonly option: OptionResource;\n readonly #host: string;\n\n constructor(options: PortersClientOptions<C>) {\n const transport = options.transport ?? createFetchTransport();\n const auth =\n options.auth ??\n createDefaultTokenProvider({\n host: options.host,\n appId: options.appId ?? \"\",\n appSecret: options.appSecret ?? \"\",\n transport,\n tokenStore: options.tokenStore,\n });\n const requester = createRequester({\n transport,\n auth,\n throttle: createThrottle(),\n backoff: expoBackoff(),\n });\n this.#host = options.host;\n const deps = {\n requester,\n host: options.host,\n partition: options.partition ?? 0,\n };\n // The per-resource custom catalog declared via defineFields (or {} when none). Branded\n // = already validated (ADR-0023 D4), so the factory merges it without re-checking.\n const customFor = <K extends keyof DeclaredCatalogs>(\n key: K,\n ): CustomFor<C, K> => (options.fields?.[key] ?? {}) as CustomFor<C, K>;\n this.candidate = createCandidateResource(deps, customFor(\"candidate\"));\n this.job = createJobResource(deps, customFor(\"job\"));\n this.client = createClientResource(deps, customFor(\"client\"));\n this.process = createProcessResource(deps, customFor(\"process\"));\n this.resume = createResumeResource(deps, customFor(\"resume\"));\n this.attachment = createAttachmentResource(deps);\n // Partition Read takes no `partition` param (it discovers them); the rest use the default.\n this.partition = createPartitionResource({ requester, host: options.host });\n this.user = createUserResource(deps);\n this.field = createFieldResource(deps);\n this.option = createOptionResource(deps);\n }\n\n /** The configured API host. */\n get host(): string {\n return this.#host;\n }\n}\n","// Custom field declaration DSL (ADR-0023, grounding ADR-0004 案H / ADR-0005 SD-2).\n// `defineFields` is the single validation boundary: a typed builder declares each\n// tenant custom field's Data Type per data resource, validation runs synchronously,\n// and the result is branded so PortersClient trusts it without re-validating. Standard\n// `P_` fields come from the static catalogs (ADR-0019); this only covers custom U_/A_.\n\nimport { PortersConfigError } from \"../errors\";\nimport type { EmptyCatalog } from \"../resources/read-core\";\nimport type { DataType } from \"../xml/decode\";\n\n/** One custom field's declared Data Type — the builder's return value (ADR-0023 D2). */\nexport type FieldDef<D extends DataType> = { readonly dataType: D };\n\n// Data Types a custom U_/A_ field may declare (ADR-0023 D3): the value-shaped types. The\n// System family (System[Id]/[DateTime]/[Reference]) is system-managed = standard territory,\n// so it is not offered; Image / Link are not modelled in DataType yet (future work).\nexport type CustomDataType =\n | \"Number\"\n | \"SinglelineText\"\n | \"MultilineText\"\n | \"Mail\"\n | \"Telephone\"\n | \"URL\"\n | \"Date\"\n | \"DateTime\"\n | \"Age\"\n | \"Option\"\n | \"User\";\n\n/** Builder passed to each resource declaration: one method per declarable Data Type. */\nexport type FieldBuilder = {\n number(): FieldDef<\"Number\">;\n singlelineText(): FieldDef<\"SinglelineText\">;\n multilineText(): FieldDef<\"MultilineText\">;\n mail(): FieldDef<\"Mail\">;\n telephone(): FieldDef<\"Telephone\">;\n url(): FieldDef<\"URL\">;\n date(): FieldDef<\"Date\">;\n dateTime(): FieldDef<\"DateTime\">;\n age(): FieldDef<\"Age\">;\n option(): FieldDef<\"Option\">;\n user(): FieldDef<\"User\">;\n};\n\n/** Data resources that accept custom fields (ADR-0023 D6). Master / Attachment are excluded. */\nexport type CustomFieldResource =\n | \"candidate\"\n | \"job\"\n | \"client\"\n | \"process\"\n | \"resume\";\n\n/** One resource's custom field declarations: alias -> {@link FieldDef}. */\nexport type ResourceDecl = Record<string, FieldDef<DataType>>;\n\n/** Declaration input: per (data) resource, a builder fn returning its custom fields. */\nexport type FieldDecls = {\n [R in CustomFieldResource]?: (f: FieldBuilder) => ResourceDecl;\n};\n\n/** A per-resource custom catalog (bare alias -> Data Type), as produced by {@link defineFields}. */\nexport type CustomCatalog = Record<string, DataType>;\n\n/** Map of (data) resource -> its custom catalog; the client merges these into the static catalogs. */\nexport type DeclaredCatalogs = {\n [R in CustomFieldResource]?: CustomCatalog;\n};\n\n// Extract the catalog (alias -> Data Type literal) from a resource's FieldDef map.\ntype CatalogOf<R extends ResourceDecl> = {\n [K in keyof R]: R[K][\"dataType\"];\n};\n\n/** The validated, branded result of {@link defineFields}, keyed by the declared resources. */\nexport type DeclaredCatalogsOf<D extends FieldDecls> = {\n [R in keyof D]: D[R] extends (f: FieldBuilder) => infer Out\n ? Out extends ResourceDecl\n ? CatalogOf<Out>\n : never\n : never;\n};\n\n// Phantom brand: marks a catalog set as already validated by defineFields (ADR-0023 D4).\n// It never exists at runtime — the value is a plain frozen object.\ndeclare const definedFieldsBrand: unique symbol;\n\n/** A validated set of custom field catalogs (branded — the client does not re-validate). */\nexport type DefinedFields<C extends DeclaredCatalogs = DeclaredCatalogs> = C & {\n readonly [definedFieldsBrand]: true;\n};\n\n/** The custom catalog declared for resource `K` (or `{}` if none) — types each accessor (ADR-0023 D1). */\nexport type CustomFor<\n C extends DeclaredCatalogs,\n K extends CustomFieldResource,\n> = K extends keyof C\n ? C[K] extends CustomCatalog\n ? C[K]\n : EmptyCatalog\n : EmptyCatalog;\n\n// 全 arrow(ADR-0013)=巻き上げ無しのため、ヘルパー → builder → defineFields の順で定義する。\nconst def = <D extends CustomDataType>(dataType: D): FieldDef<D> => ({\n dataType,\n});\n\nconst builder: FieldBuilder = {\n number: () => def(\"Number\"),\n singlelineText: () => def(\"SinglelineText\"),\n multilineText: () => def(\"MultilineText\"),\n mail: () => def(\"Mail\"),\n telephone: () => def(\"Telephone\"),\n url: () => def(\"URL\"),\n date: () => def(\"Date\"),\n dateTime: () => def(\"DateTime\"),\n age: () => def(\"Age\"),\n option: () => def(\"Option\"),\n user: () => def(\"User\"),\n};\n\n// Custom field aliases are `U_[Name]` (user-created) or `A_[Name]` (app-created) — ADR-0004.\nconst ALIAS_PATTERN = /^[UA]_/;\n\nconst KNOWN_RESOURCES: readonly CustomFieldResource[] = [\n \"candidate\",\n \"job\",\n \"client\",\n \"process\",\n \"resume\",\n];\n\n/**\n * Declare tenant-specific custom fields per data resource (ADR-0023). This is the validation\n * boundary: it throws {@link PortersConfigError} synchronously for an unknown resource key or an\n * alias that is not `U_`/`A_`-prefixed. The branded result is passed to `PortersClient({ fields })`,\n * which merges each catalog into the resource so the custom fields decode/encode by their declared\n * Data Type and appear typed on reads / writes.\n *\n * @example\n * const myFields = defineFields({\n * candidate: (f) => ({ U_score: f.number(), U_source: f.option() }),\n * });\n */\nexport const defineFields = <D extends FieldDecls>(\n decls: D,\n): DefinedFields<DeclaredCatalogsOf<D>> => {\n const catalogs: Record<string, CustomCatalog> = {};\n for (const [resource, declare] of Object.entries(decls)) {\n if (declare === undefined) continue;\n if (!KNOWN_RESOURCES.includes(resource as CustomFieldResource)) {\n throw new PortersConfigError(\n `defineFields: unknown resource \"${resource}\" (expected one of ${KNOWN_RESOURCES.join(\", \")})`,\n { category: \"config\" },\n );\n }\n const catalog: CustomCatalog = {};\n for (const [alias, fieldDef] of Object.entries(declare(builder))) {\n if (!ALIAS_PATTERN.test(alias)) {\n throw new PortersConfigError(\n `defineFields: custom field alias \"${alias}\" on \"${resource}\" must start with \"U_\" or \"A_\" (standard P_ fields are built in)`,\n { category: \"config\" },\n );\n }\n catalog[alias] = fieldDef.dataType;\n }\n catalogs[resource] = catalog;\n }\n return Object.freeze(catalogs) as DefinedFields<DeclaredCatalogsOf<D>>;\n};\n","// Opt-in binary <-> Base64 helpers for Attachment / Image content (ADR-0018). The\n// resource core takes a Base64 string; these let callers convert raw bytes without a\n// dependency. `btoa` / `atob` are globals on Node 20+ and browsers.\n\n/** Encode raw bytes to a Base64 string. */\nexport const bytesToBase64 = (bytes: Uint8Array): string => {\n // Build a Latin-1 \"binary string\" then Base64 it. O(n) string building — fine for\n // typical attachments; very large files can be encoded by the caller upstream.\n let binary = \"\";\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary);\n};\n\n/** Decode a Base64 string back to raw bytes. */\nexport const base64ToBytes = (b64: string): Uint8Array =>\n Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));\n"],"mappings":"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","names":["sleep","tag","FIELDS","REQUIRED_ON_CREATE","FIELDS","REQUIRED_ON_CREATE","FIELDS","REQUIRED_ON_CREATE","FIELDS","REQUIRED_ON_CREATE","FIELDS","FIELDS","buildUrl","FIELDS","buildUrl","FIELDS","buildUrl"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors/porters-error.ts","../src/errors/classify.ts","../src/xml/parser.ts","../src/xml/raw.ts","../src/auth/memory-store.ts","../src/auth/token-exchange.ts","../src/auth/token-provider.ts","../src/auth/auth-api.ts","../src/http/fetch-transport.ts","../src/http/mock-transport.ts","../src/http/throttle.ts","../src/http/retry.ts","../src/http/requester.ts","../src/util/datetime.ts","../src/xml/encode.ts","../src/xml/decode.ts","../src/resources/read-core.ts","../src/resources/resource.ts","../src/resources/candidate.ts","../src/resources/job.ts","../src/resources/client.ts","../src/resources/process.ts","../src/resources/resume.ts","../src/resources/attachment.ts","../src/resources/partition.ts","../src/resources/user.ts","../src/resources/field.ts","../src/resources/option.ts","../src/client.ts","../src/fields/define-fields.ts","../src/util/base64.ts"],"sourcesContent":["// PortersError hierarchy (ADR-0006): source-split subclasses + a cross-cutting\n// `category`. Never swallow errors; always surface a PortersError.\n\n/** Cross-cutting classification shared by every PORTERS error. */\nexport type ErrorCategory =\n | \"auth\"\n | \"permission\"\n | \"validation\"\n | \"notFound\"\n | \"conflict\"\n // 予約(現状どの分類関数も produce しない)。PORTERS はレート超過時に判別可能なコードを\n // 返さず接続を切るため、強制切断は PortersNetworkError(category \"network\")として表面化する。\n // 将来 429 相当の判別手段が得られたら配線するため型には残す(RV-3)。\n | \"rateLimit\"\n | \"transient\"\n | \"network\"\n | \"server\"\n | \"config\"\n | \"unknown\";\n\n/** Where the failing call was aimed (for self-service debugging). */\nexport type PortersErrorContext = {\n resource?: string;\n operation?: string;\n partition?: number;\n};\n\n/** Construction options for {@link PortersError}. */\nexport type PortersErrorOptions = {\n category: ErrorCategory;\n /** PORTERS raw code; `null` for network/transport failures. */\n code?: number | null;\n retryable?: boolean;\n /** Actionable hint (English by default). */\n hint?: string;\n httpStatus?: number;\n context?: PortersErrorContext;\n cause?: unknown;\n};\n\n/** Base class for every PORTERS-originated error (catch-all). */\nexport class PortersError extends Error {\n readonly category: ErrorCategory;\n readonly code: number | null;\n readonly retryable: boolean;\n readonly hint?: string;\n readonly httpStatus?: number;\n readonly context?: PortersErrorContext;\n\n constructor(message: string, options: PortersErrorOptions) {\n super(\n message,\n options.cause === undefined ? undefined : { cause: options.cause },\n );\n this.name = new.target.name;\n this.category = options.category;\n this.code = options.code ?? null;\n this.retryable = options.retryable ?? false;\n this.hint = options.hint;\n this.httpStatus = options.httpStatus;\n this.context = options.context;\n }\n}\n\n/** OAuth / Token errors. */\nexport class PortersAuthError extends PortersError {}\n\n/** Resource API errors. */\nexport class PortersResourceError extends PortersError {}\n\n/** Connection / timeout / forced rate-limit disconnect. */\nexport class PortersNetworkError extends PortersError {}\n\n/** Misconfiguration / misuse — not PORTERS-originated; thrown synchronously. */\nexport class PortersConfigError extends PortersError {}\n","// Code -> category -> retryable classification and PortersError factories\n// (ADR-0006 / result-codes.md). Unknown codes fall through to `category:\n// \"unknown\"` — never swallowed (fail-safe).\n\nimport {\n PortersAuthError,\n PortersNetworkError,\n PortersResourceError,\n type ErrorCategory,\n type PortersErrorContext,\n} from \"./porters-error\";\n\nconst RESOURCE_VALIDATION = new Set([8, 124, 126, 127, 133, 146, 500]);\n\n/** Resource API `<Code>` -> category (ADR-0006). */\nexport const resourceCategory = (code: number): ErrorCategory => {\n if (code === 9 || code === 302) return \"transient\";\n if (code === 401 || code === 402) return \"auth\";\n if (\n code === 6 ||\n code === 400 ||\n code === 403 ||\n code === 406 ||\n code === 601\n )\n return \"permission\";\n if (code === 7 || code === 404) return \"notFound\";\n if (code === 301 || code === 303 || code === 304) return \"conflict\";\n if (code === 1000) return \"server\";\n if (RESOURCE_VALIDATION.has(code) || (code >= 100 && code <= 116))\n return \"validation\";\n return \"unknown\";\n};\n\n/** Authentication API `<Error>` -> category (ADR-0006). */\nexport const authCategory = (code: number): ErrorCategory => {\n if (code === 400) return \"auth\";\n if ([401, 103, 104, 105, 106, 107, 109, 114, 117].includes(code))\n return \"auth\";\n if ([100, 101, 102, 110, 112].includes(code)) return \"validation\";\n if ([111, 115, 116, 402].includes(code)) return \"permission\";\n if (code === 108) return \"server\";\n return \"unknown\";\n};\n\nconst resourceHint = (code: number): string | undefined => {\n if (code === 403)\n return \"No data permission. Run the initial browser `code` grant for this Company DB, or check scopes.\";\n if (code === 404)\n return \"Partition not found or outside the contract period. Verify the partition id.\";\n return undefined;\n};\n\n/** Build a PortersResourceError from a Resource API `<Code>`. */\nexport const resourceError = (\n code: number,\n message: string,\n context?: PortersErrorContext,\n): PortersResourceError => {\n const category = resourceCategory(code);\n return new PortersResourceError(message, {\n category,\n code,\n retryable: category === \"transient\",\n hint: resourceHint(code),\n context,\n });\n};\n\n/** Build a PortersAuthError from an Authentication API `<Error>`. */\nexport const authError = (code: number, message: string): PortersAuthError => {\n const category = authCategory(code);\n return new PortersAuthError(message, {\n category,\n code,\n retryable: false,\n hint:\n category === \"auth\"\n ? \"Authentication failed; re-authenticate (browser `code` grant) or check app credentials.\"\n : undefined,\n });\n};\n\n/** Build a PortersNetworkError (no PORTERS code; retryable for idempotent ops). */\nexport const networkError = (\n message: string,\n cause?: unknown,\n): PortersNetworkError =>\n new PortersNetworkError(message, {\n category: \"network\",\n retryable: true,\n cause,\n });\n","// XML parsing + error routing (ADR-0011). The parser returns raw strings\n// (`parseTagValue: false`); all type coercion happens in `decode.ts`.\n\nimport { XMLParser } from \"fast-xml-parser\";\n\nimport { authError, resourceError } from \"../errors/classify\";\nimport { PortersAuthError, PortersResourceError } from \"../errors/index\";\nimport { asArray, asRecord, asString } from \"./raw\";\n\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n ignoreDeclaration: true,\n parseTagValue: false,\n parseAttributeValue: false,\n trimValues: true,\n // asArray() already normalizes a single/missing/repeated <Item> into an array,\n // so isArray is belt-and-suspenders: these mutants are equivalent (no test can\n // observe the difference once asArray() runs).\n // Stryker disable next-line ArrowFunction,ConditionalExpression,StringLiteral: equivalent — asArray() normalizes regardless\n isArray: (name) => name === \"Item\",\n});\n\n// fast-xml-parser yields raw strings; coerce an attribute/code node to an int,\n// treating a missing node as 0. The explicit `undefined` check keeps the\n// fallback observable — `Number(\"\") === 0`, so a `?? \"0\"` default would be an\n// equivalent mutant.\nconst toInt = (v: unknown): number => {\n const s = asString(v);\n return s === undefined ? 0 : Number(s);\n};\n\n/** One `<Item>`: a map of field alias -> raw node (string or nested object). */\nexport type RawItem = Record<string, unknown>;\n\nexport type ResourcePage = {\n total: number;\n count: number;\n start: number;\n items: RawItem[];\n};\n\n/**\n * Parse a Resource Read response. Reads `<Code>` first and, if non-zero, throws\n * the mapped PortersError (ADR-0006) — HTTP 200 + `<Code>≠0` is an error, not\n * data.\n */\nexport const parseResourcePage = (xml: string): ResourcePage => {\n const root = asRecord(parser.parse(xml) as unknown);\n const rootKey = root ? Object.keys(root)[0] : undefined;\n // `root` is always a record here and `root[rootKey]` is undefined exactly when\n // rootKey is, so dropping/forcing either guard collapses to the same throw.\n // Stryker disable next-line ConditionalExpression,LogicalOperator: equivalent — both branches converge on the unparseable throw\n const body = root && rootKey ? asRecord(root[rootKey]) : undefined;\n if (!body) {\n throw new PortersResourceError(\"unparseable resource response\", {\n category: \"unknown\",\n });\n }\n\n const code = toInt(body.Code);\n if (code !== 0) {\n throw resourceError(code, `resource returned code ${code}`, {\n resource: rootKey,\n });\n }\n\n return {\n total: toInt(body[\"@_Total\"]),\n count: toInt(body[\"@_Count\"]),\n start: toInt(body[\"@_Start\"]),\n items: asArray(body.Item).map((it) => asRecord(it) ?? {}),\n };\n};\n\n/** One written record's outcome: the assigned/updated `Id` and its Result `Code`. */\nexport type WriteResultItem = {\n id: number;\n code: number;\n};\n\n/**\n * Parse a Resource Write response. Unlike Read there is no root `<Code>` nor\n * Total/Count/Start: each `<Item>` carries its own `<Id>` (assigned on create /\n * echoed on update) and `<Code>` (per-item Result Code). Applying the per-item\n * code policy (throw on `!= 0`) is the accessor's job, since a bulk write mixes\n * successes and failures — see write-format.md.\n */\nexport const parseWriteResult = (xml: string): WriteResultItem[] => {\n const root = asRecord(parser.parse(xml) as unknown);\n const rootKey = root ? Object.keys(root)[0] : undefined;\n // Same equivalence as parseResourcePage: both guards converge on the throw.\n // Stryker disable next-line ConditionalExpression,LogicalOperator: equivalent — both branches converge on the unparseable throw\n const body = root && rootKey ? asRecord(root[rootKey]) : undefined;\n if (!body) {\n throw new PortersResourceError(\"unparseable write response\", {\n category: \"unknown\",\n });\n }\n\n return asArray(body.Item).map((it) => {\n const item = asRecord(it) ?? {};\n return { id: toInt(item.Id), code: toInt(item.Code) };\n });\n};\n\n/** Parsed `<Authentication>` response (OAuth `code_direct` / Token). */\nexport type AuthResponse = {\n code?: string;\n accessToken?: string;\n accessTokenExpiresIn?: number;\n refreshToken?: string;\n refreshTokenExpiresIn?: number;\n};\n\n/**\n * Parse an `<Authentication>` response. Reads `<Error>` first and, if non-zero,\n * throws the mapped PortersAuthError (ADR-0006).\n */\nexport const parseAuthentication = (xml: string): AuthResponse => {\n const root = asRecord(parser.parse(xml) as unknown);\n const body = root ? asRecord(root.Authentication) : undefined;\n if (!body) {\n throw new PortersAuthError(\"unparseable authentication response\", {\n category: \"unknown\",\n });\n }\n\n const error = toInt(body.Error);\n if (error !== 0) {\n throw authError(\n error,\n asString(body.Message) ?? `authentication error ${error}`,\n );\n }\n\n const num = (v: unknown): number | undefined => {\n const s = asString(v);\n return s === undefined ? undefined : Number(s);\n };\n return {\n code: asString(body.Code),\n accessToken: asString(body.AccessToken),\n accessTokenExpiresIn: num(body.AccessTokenExpiresIn),\n refreshToken: asString(body.RefreshToken),\n refreshTokenExpiresIn: num(body.RefreshTokenExpiresIn),\n };\n};\n","// Narrowing helpers for fast-xml-parser output. The parser is typed as `any`;\n// we launder it through `unknown` and narrow here so we never spread `any`.\n\nexport const asRecord = (v: unknown): Record<string, unknown> | undefined =>\n typeof v === \"object\" && v !== null && !Array.isArray(v)\n ? (v as Record<string, unknown>)\n : undefined;\n\nexport const asString = (v: unknown): string | undefined =>\n typeof v === \"string\" ? v : undefined;\n\n/** Normalize a node that may be missing, single, or repeated into an array. */\nexport const asArray = (v: unknown): unknown[] => {\n if (Array.isArray(v)) return v;\n return v === undefined || v === null ? [] : [v];\n};\n","import type { StoredTokens, TokenStore } from \"./types\";\n\n/** Default in-process token store (single instance; lost on restart). */\nexport const createMemoryTokenStore = (): TokenStore => {\n let tokens: StoredTokens | undefined;\n return {\n get: () => Promise.resolve(tokens),\n set: (t) => {\n tokens = t;\n return Promise.resolve();\n },\n clear: () => {\n tokens = undefined;\n return Promise.resolve();\n },\n };\n};\n","// Shared OAuth token exchange against `POST /v1/token` (ADR-0034 F-1 / ADR-0007).\n// Used by both the default transparent provider (code_direct grant) and the public\n// auth API's browser `code` exchange — they POST the same form and parse the same\n// <Authentication> envelope, so the logic lives here once. The App Secret only ever\n// rides the POST body (ADR-0034 SD-9), never a URL/log.\n\nimport { PortersAuthError } from \"../errors/index\";\nimport type { Transport } from \"../http/index\";\nimport { parseAuthentication } from \"../xml/parser\";\nimport type { StoredTokens } from \"./types\";\n\n/** Credentials + seams shared by every token exchange. */\nexport type TokenExchangeDeps = {\n host: string;\n appId: string;\n appSecret: string;\n transport: Transport;\n /** Clock for converting relative expiry (ms) to an absolute epoch (ADR-0012). */\n now: () => number;\n};\n\n/** OAuth grant kinds the Token endpoint accepts (token.md). */\nexport type TokenGrantType = \"oauth_code\" | \"refresh_token\";\n\n/**\n * Exchange an OAuth `code` (new grant) or a Refresh Token (renewal) for tokens via\n * `POST {host}/v1/token`. The relative `*ExpiresIn` (ms) is converted to an absolute\n * epoch at receipt (clock-skew tolerant — ADR-0012). Throws {@link PortersAuthError}\n * when the envelope reports an error (`<Error>≠0`, via the parser) or omits a token.\n */\nexport const exchangeToken = async (\n deps: TokenExchangeDeps,\n grantType: TokenGrantType,\n code: string,\n): Promise<StoredTokens> => {\n const body = new URLSearchParams({\n app_id: deps.appId,\n secret: deps.appSecret,\n grant_type: grantType,\n code,\n }).toString();\n const res = await deps.transport.send({\n method: \"POST\",\n url: `https://${deps.host}/v1/token`,\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n const a = parseAuthentication(res.body);\n if (a.accessToken === undefined || a.refreshToken === undefined) {\n throw new PortersAuthError(\"token response missing tokens\", {\n category: \"auth\",\n });\n }\n return {\n accessToken: a.accessToken,\n refreshToken: a.refreshToken,\n accessTokenExpiresAt: deps.now() + (a.accessTokenExpiresIn ?? 0),\n refreshTokenExpiresAt: deps.now() + (a.refreshTokenExpiresIn ?? 0),\n };\n};\n","// Default transparent TokenProvider (ADR-0007 / ADR-0012): code_direct -> token,\n// cache, hybrid refresh (proactive margin + on-demand), in-process single-flight.\n// Factory style per ADR-0013. Exposes internal cache/clear so the public auth API\n// (ADR-0034 F-1) can save a browser-`code` exchange and locally forget tokens.\n\nimport { PortersAuthError } from \"../errors/index\";\nimport type { Transport } from \"../http/index\";\nimport { parseAuthentication } from \"../xml/parser\";\nimport { createMemoryTokenStore } from \"./memory-store\";\nimport { exchangeToken } from \"./token-exchange\";\nimport type { StoredTokens, TokenProvider, TokenStore } from \"./types\";\n\nexport type DefaultTokenProviderOptions = {\n host: string;\n appId: string;\n appSecret: string;\n transport: Transport;\n /** Token persistence; defaults to in-memory. */\n tokenStore?: TokenStore;\n /** Refresh this many ms before expiry (proactive). Default 60s. */\n refreshMarginMs?: number;\n /** Injectable clock (tests). Default `Date.now`. */\n now?: () => number;\n};\n\n/**\n * The default provider plus internal controls used by the public auth API\n * (ADR-0034 SD-8): {@link DefaultTokenProvider.cache} saves externally-acquired\n * tokens (browser `code` exchange) to the in-memory cache + token store;\n * {@link DefaultTokenProvider.clear} forgets them (local revoke). Deliberately *not*\n * part of the public\n * {@link TokenProvider} contract — a custom strategy supplies neither.\n */\nexport type DefaultTokenProvider = TokenProvider & {\n cache(tokens: StoredTokens): Promise<void>;\n clear(): Promise<void>;\n};\n\nconst DEFAULT_MARGIN_MS = 60_000;\n\nexport const createDefaultTokenProvider = (\n opts: DefaultTokenProviderOptions,\n): DefaultTokenProvider => {\n const store = opts.tokenStore ?? createMemoryTokenStore();\n const margin = opts.refreshMarginMs ?? DEFAULT_MARGIN_MS;\n const now = opts.now ?? (() => Date.now());\n\n let cached: StoredTokens | undefined;\n let inflight: Promise<StoredTokens> | undefined;\n\n const accessValid = (t: StoredTokens | undefined): t is StoredTokens =>\n t !== undefined && now() < t.accessTokenExpiresAt - margin;\n\n const canRefresh = (t: StoredTokens | undefined): t is StoredTokens =>\n t !== undefined && now() < t.refreshTokenExpiresAt - margin;\n\n // Cache + persist freshly minted tokens so the next call (and other instances) reuse them.\n const save = async (tokens: StoredTokens): Promise<StoredTokens> => {\n cached = tokens;\n await store.set(tokens);\n return tokens;\n };\n\n const exchange = async (\n grantType: \"oauth_code\" | \"refresh_token\",\n code: string,\n ): Promise<StoredTokens> =>\n save(\n await exchangeToken(\n {\n host: opts.host,\n appId: opts.appId,\n appSecret: opts.appSecret,\n transport: opts.transport,\n now,\n },\n grantType,\n code,\n ),\n );\n\n // code_direct -> token (initial acquisition; requires prior browser grant).\n const acquire = async (): Promise<StoredTokens> => {\n const url =\n `https://${opts.host}/v1/oauth` +\n `?app_id=${encodeURIComponent(opts.appId)}&response_type=code_direct`;\n const res = await opts.transport.send({ method: \"GET\", url, headers: {} });\n const { code } = parseAuthentication(res.body);\n if (code === undefined) {\n throw new PortersAuthError(\"code_direct returned no code\", {\n category: \"auth\",\n });\n }\n return exchange(\"oauth_code\", code);\n };\n\n const renew = async (): Promise<StoredTokens> => {\n if (cached === undefined) cached = await store.get();\n if (canRefresh(cached)) {\n return exchange(\"refresh_token\", cached.refreshToken);\n }\n return acquire();\n };\n\n const ensure = (forceRefresh: boolean): Promise<StoredTokens> => {\n if (!forceRefresh && accessValid(cached)) return Promise.resolve(cached);\n return (inflight ??= renew().finally(() => {\n inflight = undefined;\n }));\n };\n\n return {\n getAccessToken: async (o) =>\n (await ensure(o?.forceRefresh ?? false)).accessToken,\n cache: async (tokens) => {\n await save(tokens);\n },\n clear: async () => {\n cached = undefined;\n await store.clear();\n },\n };\n};\n","// Public OAuth surface `porters.auth.*` (ADR-0034 F-1 / ADR-0007 SD-3/SD-6). A thin\n// facade over the active token provider: it builds the browser `code` / `remove` URLs,\n// exchanges a redirect `?code=` for tokens (saving them into the default strategy),\n// warms up / inspects the token, and locally forgets tokens. Credential- and\n// default-strategy-dependent methods fail fast with a PortersConfigError under a custom\n// auth strategy (ADR-0034 SD-7). Factory style per ADR-0013; the App Secret never leaves\n// the Token POST body (SD-9).\n\nimport { PortersConfigError } from \"../errors/index\";\nimport type { Transport } from \"../http/index\";\nimport type { Scope } from \"../types/index\";\nimport { exchangeToken } from \"./token-exchange\";\nimport type { StoredTokens, TokenProvider } from \"./types\";\n\n/** Shared options for the browser `code` / `remove` OAuth URLs (oauth.md). */\nexport type AuthorizationUrlOptions = {\n /** Registered Redirect URL the browser returns to (required for code/remove). */\n redirectUrl: string;\n /** Scopes to grant/remove; defaults to the client's configured `scopes`. */\n scopes?: Scope[];\n /** Opaque value echoed back on redirect (e.g. CSRF defense). */\n state?: string;\n};\n\n/** Options for the `remove` (de-authorization) browser URL. */\nexport type RevokeUrlOptions = AuthorizationUrlOptions;\n\n/**\n * The `porters.auth.*` surface (ADR-0007 SD-3/SD-6). The initial per-Company-DB grant\n * needs a human to open {@link AuthApi.authorizationUrl} in a browser and consent; the\n * library only builds the URL and exchanges the returned `code`. Day-to-day token\n * acquisition/refresh stays transparent (the default strategy), so most callers never\n * touch this surface.\n */\nexport type AuthApi = {\n /** Build the browser `code`-grant URL to open for the initial permission grant. */\n authorizationUrl(opts: AuthorizationUrlOptions): string;\n /**\n * Exchange a redirect `?code=` for tokens and save them into the default strategy.\n * Resolves `void` on success (tokens are stored internally — inspect via\n * {@link AuthApi.getToken}); throws on failure: {@link PortersConfigError} (missing\n * credentials / custom strategy), `PortersAuthError` (token-endpoint error or expired\n * code), or `PortersNetworkError`.\n */\n exchangeAuthorizationCode(code: string): Promise<void>;\n /**\n * Build the browser `remove`-grant URL to open for server-side de-authorization.\n * PORTERS has no server-to-server removal, so completing it stays a browser step;\n * pair with {@link AuthApi.clearTokens} to drop the local copy.\n */\n revokeUrl(opts: RevokeUrlOptions): string;\n /** Forget cached + stored tokens locally. Does not de-authorize server-side. */\n clearTokens(): Promise<void>;\n /** Acquire a token now (startup fail-fast / warm-up); throws if auth is unavailable. */\n ensureAuthenticated(): Promise<void>;\n /** Return the current valid Access Token (debug). The Refresh Token is never exposed. */\n getToken(): Promise<string>;\n};\n\n/** Internal save/forget controls, present only when the default provider is in use. */\nexport type AuthProviderControls = {\n cache(tokens: StoredTokens): Promise<void>;\n clear(): Promise<void>;\n};\n\nexport type AuthApiOptions = {\n host: string;\n appId?: string;\n appSecret?: string;\n scopes?: Scope[];\n transport: Transport;\n /** The active token provider (default or custom) backing ensure/getToken. */\n provider: TokenProvider;\n /** Present only for the default provider; absent under a custom strategy. */\n controls?: AuthProviderControls;\n /** Injectable clock (tests). Default `Date.now`. */\n now?: () => number;\n};\n\nexport const createAuthApi = (opts: AuthApiOptions): AuthApi => {\n const now = opts.now ?? (() => Date.now());\n\n const requireAppId = (): string => {\n if (!opts.appId) {\n throw new PortersConfigError(\"appId is required to build an OAuth URL\", {\n category: \"config\",\n hint: \"Set appId on PortersClient. A custom auth strategy that supplies its own tokens cannot run the browser grant.\",\n });\n }\n return opts.appId;\n };\n\n const requireDefaultStrategy = (method: string): AuthProviderControls => {\n if (opts.controls === undefined) {\n throw new PortersConfigError(\n `${method} is only available with the default auth strategy`,\n {\n category: \"config\",\n hint: \"Remove the custom `auth` strategy to let the library manage tokens, or perform this step in your own strategy.\",\n },\n );\n }\n return opts.controls;\n };\n\n const requireCredentials = (): { appId: string; appSecret: string } => {\n if (!opts.appId || !opts.appSecret) {\n throw new PortersConfigError(\n \"appId and appSecret are required to exchange an authorization code\",\n {\n category: \"config\",\n hint: \"Set appId/appSecret on PortersClient (the Token endpoint needs both).\",\n },\n );\n }\n return { appId: opts.appId, appSecret: opts.appSecret };\n };\n\n const resolveScopes = (scopes: Scope[] | undefined): Scope[] => {\n const resolved = scopes ?? opts.scopes ?? [];\n if (resolved.length === 0) {\n throw new PortersConfigError(\n \"at least one scope is required for the code/remove grant\",\n {\n category: \"config\",\n hint: \"Pass `scopes` to this call or configure `scopes` on PortersClient.\",\n },\n );\n }\n return resolved;\n };\n\n const buildOAuthUrl = (\n responseType: \"code\" | \"remove\",\n o: AuthorizationUrlOptions,\n ): string => {\n const params = new URLSearchParams({\n app_id: requireAppId(),\n redirect_url: o.redirectUrl,\n response_type: responseType,\n scope: resolveScopes(o.scopes).join(\",\"),\n });\n if (o.state !== undefined) params.set(\"state\", o.state);\n return `https://${opts.host}/v1/oauth?${params.toString()}`;\n };\n\n return {\n authorizationUrl: (o) => buildOAuthUrl(\"code\", o),\n revokeUrl: (o) => buildOAuthUrl(\"remove\", o),\n exchangeAuthorizationCode: async (code) => {\n const controls = requireDefaultStrategy(\"exchangeAuthorizationCode\");\n const { appId, appSecret } = requireCredentials();\n const tokens = await exchangeToken(\n { host: opts.host, appId, appSecret, transport: opts.transport, now },\n \"oauth_code\",\n code,\n );\n await controls.cache(tokens);\n },\n clearTokens: async () => {\n const controls = requireDefaultStrategy(\"clearTokens\");\n await controls.clear();\n },\n ensureAuthenticated: async () => {\n await opts.provider.getAccessToken();\n },\n getToken: () => opts.provider.getAccessToken(),\n };\n};\n","// Default fetch-based transport (ADR-0009). Thin: one request -> one response;\n// throttle/retry/auth live above it. Network/timeout -> PortersNetworkError.\n\nimport { PortersNetworkError } from \"../errors/index\";\nimport type { Transport } from \"./types\";\n\nexport type FetchTransportOptions = {\n timeoutMs?: number;\n /** Injectable fetch (tests / custom dispatcher). Default global fetch. */\n fetchImpl?: typeof fetch;\n};\n\nexport const createFetchTransport = (\n opts: FetchTransportOptions = {},\n): Transport => {\n const doFetch = opts.fetchImpl ?? fetch;\n const timeoutMs = opts.timeoutMs ?? 30_000;\n return {\n send: async (req) => {\n try {\n const res = await doFetch(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n signal: AbortSignal.timeout(timeoutMs),\n });\n return { status: res.status, body: await res.text() };\n } catch (cause) {\n throw new PortersNetworkError(\"transport request failed\", {\n category: \"network\",\n retryable: true,\n cause,\n });\n }\n },\n };\n};\n","// Public mock transport for offline evaluation / unit tests (ADR-0024 / R-17 / R-12).\n// It targets the stable public `Transport` seam (not `fetch`), so it survives an internal\n// transport change. By default the OAuth code_direct + token endpoints are auto-answered,\n// so callers only mock resource XML; an unmocked route fails loud (fail-safe).\n\nimport { PortersConfigError } from \"../errors/index\";\nimport type { Transport, TransportRequest, TransportResponse } from \"./types\";\n\n/** A mock reply: an XML body string (HTTP 200), or an explicit status + body. */\nexport type MockReply = string | { status?: number; body: string };\n\n/**\n * Maps a request to a {@link MockReply}, or returns `undefined` for \"not mocked\". When `undefined`\n * is returned (and the request is not an auto-answered auth endpoint), the transport throws a\n * {@link PortersConfigError} naming the request, so an unmocked route surfaces instead of silently\n * returning an empty response.\n */\nexport type MockHandler = (request: TransportRequest) => MockReply | undefined;\n\n/** Options for {@link createMockTransport}. */\nexport type MockTransportOptions = {\n /**\n * Auto-answer the OAuth `code_direct` (`/v1/oauth`) and token (`/v1/token`) endpoints with valid\n * demo tokens, so callers only mock resource XML. Default `true`. Set `false` to handle the auth\n * endpoints in your own handler.\n */\n auth?: boolean;\n};\n\n// Default auth responses (mirrors the live envelope; expiry values are ms — see token-provider).\nconst AUTH_CODE_XML = `<Authentication><Code>mock-code</Code><Error>0</Error></Authentication>`;\nconst AUTH_TOKEN_XML =\n `<Authentication>` +\n `<AccessToken>mock-access-token</AccessToken><AccessTokenExpiresIn>1800000</AccessTokenExpiresIn>` +\n `<RefreshToken>mock-refresh-token</RefreshToken><RefreshTokenExpiresIn>7200000</RefreshTokenExpiresIn>` +\n `<Error>0</Error></Authentication>`;\n\nconst toResponse = (reply: MockReply): TransportResponse =>\n typeof reply === \"string\"\n ? { status: 200, body: reply }\n : { status: reply.status ?? 200, body: reply.body };\n\n// method + path だけで「どの route を足すか」は十分。既定 field を載せた Read URL の\n// クエリは長大でノイズなので落とす(不正な URL はそのまま出す=フェイルセーフ)。\nconst routeLabel = (method: string, url: string): string => {\n try {\n return `${method} ${new URL(url).pathname}`;\n } catch {\n return `${method} ${url}`;\n }\n};\n\n/**\n * Build a {@link Transport} that answers from a handler instead of the network — run the library\n * fully offline, with no PORTERS contract (R-17). Pass it as `new PortersClient({ transport })`.\n *\n * @example\n * const transport = createMockTransport((req) =>\n * req.url.includes(\"/v1/candidate\")\n * ? `<Candidate Total=\"0\" Count=\"0\" Start=\"0\"><Code>0</Code></Candidate>`\n * : undefined, // unmocked -> a clear PortersConfigError\n * );\n */\nexport const createMockTransport = (\n handler: MockHandler,\n options: MockTransportOptions = {},\n): Transport => {\n const autoAuth = options.auth ?? true;\n // Non-async on purpose: always return a Promise (resolve/reject) so an unmocked route rejects\n // rather than throwing synchronously — faithful to the Transport contract.\n return {\n send: (req) => {\n if (autoAuth && req.url.includes(\"/v1/token\")) {\n return Promise.resolve({ status: 200, body: AUTH_TOKEN_XML });\n }\n if (autoAuth && req.url.includes(\"/v1/oauth\")) {\n return Promise.resolve({ status: 200, body: AUTH_CODE_XML });\n }\n const reply = handler(req);\n if (reply === undefined) {\n return Promise.reject(\n new PortersConfigError(\n `createMockTransport: no mock response for ${routeLabel(req.method, req.url)} — add a case to your handler` +\n ` (or pass { auth: false } to mock the auth endpoints too)`,\n { category: \"config\" },\n ),\n );\n }\n return Promise.resolve(toResponse(reply));\n },\n };\n};\n","// Token-bucket throttle (ADR-0010): per-minute Read/Write limits at ~90% safety.\n// Bursts are allowed up to capacity; the average stays under the limit.\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nexport type Throttle = {\n take(write: boolean): Promise<void>;\n};\n\nexport type ThrottleOptions = {\n readPerMin?: number;\n writePerMin?: number;\n /** Fraction of the limit to actually use (headroom). Default 0.9. */\n safety?: number;\n now?: () => number;\n};\n\nconst makeBucket = (\n capacity: number,\n now: () => number,\n): (() => Promise<void>) => {\n const ratePerMs = capacity / 60_000;\n let tokens = capacity;\n let last = now();\n return async () => {\n for (;;) {\n const t = now();\n tokens = Math.min(capacity, tokens + (t - last) * ratePerMs);\n last = t;\n if (tokens >= 1) {\n tokens -= 1;\n return;\n }\n await sleep(Math.ceil((1 - tokens) / ratePerMs));\n }\n };\n};\n\nexport const createThrottle = (opts: ThrottleOptions = {}): Throttle => {\n const safety = opts.safety ?? 0.9;\n const now = opts.now ?? (() => Date.now());\n const read = makeBucket(Math.floor((opts.readPerMin ?? 2000) * safety), now);\n const write = makeBucket(Math.floor((opts.writePerMin ?? 500) * safety), now);\n return { take: (isWrite) => (isWrite ? write() : read()) };\n};\n","// Exponential backoff with full jitter (ADR-0010).\n\nexport type Backoff = (attempt: number) => number;\n\nexport const expoBackoff =\n (baseMs = 200, maxMs = 8_000): Backoff =>\n (attempt) =>\n Math.floor(Math.random() * Math.min(maxMs, baseMs * 2 ** attempt));\n","// Request pipeline (ADR-0009/0010/0012): throttle -> auth header -> transport,\n// with reactive token refresh (401/402) and bounded backoff retry. The\n// idempotency guard keeps non-idempotent writes (create) from double-applying.\n\nimport type { TokenProvider } from \"../auth/types\";\nimport {\n PortersConfigError,\n PortersError,\n PortersNetworkError,\n} from \"../errors/index\";\nimport type { Backoff } from \"./retry\";\nimport type { Throttle } from \"./throttle\";\nimport type { Transport, TransportRequest } from \"./types\";\n\nconst API_VERSION = \"2\";\n\n// docs/reference: keep a *whole* request under ~15000 chars (a larger payload 400s).\n// \"Whole\" is load-bearing: a write's body dominates, but a read's length lives in the\n// URL (field / condition) — and ADR-0020 makes a fieldless Read send the catalog default\n// field set, so that URL grew. A future 16KB cap is planned but undetermined — follow the\n// canonical value.\nconst MAX_REQUEST_LENGTH = 15000;\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst withAuth = (\n req: TransportRequest,\n token: string,\n write: boolean,\n): TransportRequest => ({\n ...req,\n headers: {\n ...req.headers,\n \"X-porters-hrbc-oauth-token\": token,\n \"X-P-ConnectAPI-Version\": API_VERSION,\n ...(write ? { \"Content-Type\": \"application/xml; charset=UTF-8\" } : {}),\n },\n});\n\nexport type RequesterOptions = {\n transport: Transport;\n auth: TokenProvider;\n throttle: Throttle;\n backoff: Backoff;\n maxRetries?: number;\n};\n\nexport type RequestSpec = {\n /** Write (POST) uses the write throttle bucket. */\n write?: boolean;\n /** false for non-idempotent ops (create); not auto-retried on network uncertainty. */\n idempotent?: boolean;\n /** Skip the ~15000-char size guard (file uploads have their own limit; ADR-0018). */\n unboundedBody?: boolean;\n};\n\nexport type Requester = {\n request<T>(\n req: TransportRequest,\n parse: (body: string) => T,\n spec?: RequestSpec,\n ): Promise<T>;\n};\n\nexport const createRequester = (o: RequesterOptions): Requester => {\n const maxRetries = o.maxRetries ?? 3;\n\n const request = async <T>(\n req: TransportRequest,\n parse: (body: string) => T,\n spec: RequestSpec = {},\n ): Promise<T> => {\n // Eager size guard: block an oversized request before throttle / auth / transport.\n // A clear config error beats an opaque server 400, and we don't burn a throttle token\n // or a token refresh on a request that cannot succeed (fail-safe). PORTERS limits the\n // whole request, so measure URL + body: a write's body or a read's field/condition\n // query string can blow the cap (RV-5). File uploads opt out via `unboundedBody` (the\n // body has its own limit — ADR-0018; their write URL is short, so skipping is safe).\n const requestLength = req.url.length + (req.body?.length ?? 0);\n if (!spec.unboundedBody && requestLength > MAX_REQUEST_LENGTH) {\n throw new PortersConfigError(\n `request is ${requestLength} characters, over the ~${MAX_REQUEST_LENGTH}-character limit`,\n {\n category: \"config\",\n hint: \"Shorten the request: narrow a read's field/condition, or split a write into batches of 200 or fewer records (PORTERS caps a request at ~15000 characters).\",\n },\n );\n }\n const write = spec.write ?? false;\n const idempotent = spec.idempotent ?? !write;\n let authRetried = false;\n let forceRefresh = false;\n let attempt = 0;\n\n for (;;) {\n await o.throttle.take(write);\n try {\n const token = await o.auth.getAccessToken(\n forceRefresh ? { forceRefresh: true } : undefined,\n );\n forceRefresh = false;\n const res = await o.transport.send(withAuth(req, token, write));\n return parse(res.body);\n } catch (e) {\n if (!(e instanceof PortersError)) throw e;\n // reactive: token expired -> refresh once and retry (safe even for create).\n if ((e.code === 401 || e.code === 402) && !authRetried) {\n authRetried = true;\n forceRefresh = true;\n continue;\n }\n // idempotency guard: non-idempotent write + network-uncertain -> surface.\n if (e instanceof PortersNetworkError && write && !idempotent) throw e;\n // transient (9/302) / network -> bounded backoff.\n if (e.retryable && attempt < maxRetries) {\n attempt += 1;\n await sleep(o.backoff(attempt - 1));\n continue;\n }\n throw e;\n }\n }\n };\n\n return { request };\n};\n","// PORTERS datetime <-> ISO 8601 (UTC) normalization (PRD R-10 / ADR-0011).\n// DateTime `yyyy/mm/dd HH:MM:SS` (UTC) <-> ISO `...Z`\n// Date `yyyy/mm/dd` <-> date-only (no `Z`)\n// No business-timezone (e.g. JST) conversion — that is the caller's responsibility.\n\nconst DATETIME_RE = /^(\\d{4})\\/(\\d{2})\\/(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})$/;\nconst DATE_RE = /^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/;\nconst ISO_DATE_RE = /^(\\d{4})-(\\d{2})-(\\d{2})/;\n\n/** PORTERS `yyyy/mm/dd HH:MM:SS` (UTC) -> ISO 8601 `...Z`. */\nexport const portersDateTimeToIso = (value: string): string => {\n const m = DATETIME_RE.exec(value);\n if (!m) throw new RangeError(`invalid PORTERS DateTime: \"${value}\"`);\n const iso = `${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}Z`;\n if (Number.isNaN(Date.parse(iso))) {\n throw new RangeError(`invalid PORTERS DateTime: \"${value}\"`);\n }\n return iso;\n};\n\n/** ISO 8601 (with `Z` or offset) -> PORTERS `yyyy/mm/dd HH:MM:SS` (UTC). */\nexport const isoToPortersDateTime = (value: string): string => {\n const t = Date.parse(value);\n if (Number.isNaN(t)) throw new RangeError(`invalid ISO datetime: \"${value}\"`);\n const d = new Date(t);\n const pad = (n: number): string => String(n).padStart(2, \"0\");\n return (\n `${d.getUTCFullYear()}/${pad(d.getUTCMonth() + 1)}/${pad(d.getUTCDate())} ` +\n `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`\n );\n};\n\n/** PORTERS `yyyy/mm/dd` -> ISO date `yyyy-mm-dd` (no timezone). */\nexport const portersDateToIso = (value: string): string => {\n const m = DATE_RE.exec(value);\n if (!m) throw new RangeError(`invalid PORTERS Date: \"${value}\"`);\n return `${m[1]}-${m[2]}-${m[3]}`;\n};\n\n/** ISO date (or datetime) -> PORTERS `yyyy/mm/dd` (calendar date as-is, no shift). */\nexport const isoToPortersDate = (value: string): string => {\n const m = ISO_DATE_RE.exec(value);\n if (!m) throw new RangeError(`invalid ISO date: \"${value}\"`);\n return `${m[1]}/${m[2]}/${m[3]}`;\n};\n","// Data-Type-driven value encoding for Write (ADR-0011). Read and Write\n// representations are asymmetric: User/System[Reference] write the ID only, Option writes\n// `<Field><OptionAlias/></Field>`, and DateTime/Date go ISO -> PORTERS. This is the\n// mirror of decode.ts; it builds the request body so XML stays out of resources/.\n\nimport { isoToPortersDate, isoToPortersDateTime } from \"../util/datetime\";\nimport type { DataType } from \"./decode\";\n\n/**\n * A value to write. Scalars cover the string Data Types / Number / Id and the\n * ID-only User / Reference. An **Option** value is an array of selected aliases\n * (`string[]`) — symmetric with the Option read shape (ADR-0017); a lone string\n * is tolerated as a 1-element selection (fail-safe). `null` / `undefined` omits the\n * field (leaves it unchanged) — send `\"\"` to clear a string field.\n *\n * Per-field static typing (Option fields as `string[]`, etc.) is future work — the\n * precise static Write type (SD-3).\n */\nexport type WriteValue = string | number | string[] | null | undefined;\n\n/** One record to write: field alias (bare, e.g. `P_Name`) -> value. */\nexport type WriteItem = Record<string, WriteValue>;\n\n// Data Types a user may write. `System[Id]` is library-supplied (`P_Id=-1`/target id) and\n// `System[DateTime]` (registration/update) is Write-restricted by PORTERS — both are excluded\n// from the static Write input so they cannot be set (ADR-0016 promise, realized in ADR-0019).\nexport type WritableDataType = Exclude<\n DataType,\n \"System[Id]\" | \"System[DateTime]\"\n>;\n\n// Per-Data-Type write value (mirror of `encodeField`): User / System[Reference] / Number take a\n// number, Option an alias array, the rest a scalar string. Drives the static Write type (ADR-0019).\nexport type WriteValueOf<D extends DataType> = D extends\n | \"User\"\n | \"System[Reference]\"\n | \"Number\"\n ? number\n : D extends \"Option\"\n ? string[]\n : string;\n\n// Element-content escaping. Only `& < >` are significant in PCDATA; we never emit\n// attributes, so quotes are left as-is.\nconst escapeXml = (s: string): string =>\n s.replace(/[&<>]/g, (c) =>\n c === \"&\" ? \"&\" : c === \"<\" ? \"<\" : \">\",\n );\n\nconst scalar = (v: string | number | string[]): string => escapeXml(String(v));\n\n/** Encode one field's value into the inner XML of its element. */\nexport const encodeField = (\n type: DataType,\n value: string | number | string[],\n): string => {\n switch (type) {\n // Option: the selected aliases as empty child elements. Canonical input is an\n // array (ADR-0017, symmetric with read); a lone string is wrapped as a 1-element\n // selection (fail-safe).\n case \"Option\":\n return (Array.isArray(value) ? value : [value])\n .map((alias) => `<${alias}/>`)\n .join(\"\");\n // System[DateTime] (registration/update) is Write-restricted by PORTERS; we still\n // serialize it identically — rejecting the write is the input type's job (SD-3).\n case \"DateTime\":\n case \"System[DateTime]\":\n return scalar(isoToPortersDateTime(String(value)));\n // Age shares Date's wire format (`yyyy/mm/dd`): we write the birthdate.\n case \"Date\":\n case \"Age\":\n return scalar(isoToPortersDate(String(value)));\n // System[Id] / Number / User & System[Reference] (ID-only) / string Data Types all\n // serialize as a scalar (the string types stay distinct labels per ADR-0016).\n case \"System[Id]\":\n case \"Number\":\n case \"User\":\n case \"System[Reference]\":\n case \"SinglelineText\":\n case \"MultilineText\":\n case \"Mail\":\n case \"Telephone\":\n case \"URL\":\n return scalar(value);\n }\n};\n\n// One `<Item>…</Item>` body. Unknown aliases (custom U_/A_, no catalog entry) fall\n// back to Text — symmetric with decode's raw-string passthrough (fail-safe).\nconst encodeItem = (\n prefix: string,\n fields: ReadonlyMap<string, DataType>,\n item: WriteItem,\n): string => {\n const parts: string[] = [];\n for (const [alias, value] of Object.entries(item)) {\n // null / undefined -> omit (leave unchanged); \"\" is kept (clears a Text field).\n if (value === null || value === undefined) continue;\n const type = fields.get(alias);\n const inner = type === undefined ? scalar(value) : encodeField(type, value);\n parts.push(`<${prefix}.${alias}>${inner}</${prefix}.${alias}>`);\n }\n return parts.join(\"\");\n};\n\n/** Build a Write request body: `<{Resource}><Item>…</Item>…</{Resource}>`. */\nexport const buildWriteXml = (config: {\n resource: string;\n prefix: string;\n fields: ReadonlyMap<string, DataType>;\n items: WriteItem[];\n}): string => {\n const items = config.items\n .map(\n (item) =>\n `<Item>${encodeItem(config.prefix, config.fields, item)}</Item>`,\n )\n .join(\"\");\n return `<${config.resource}>${items}</${config.resource}>`;\n};\n","// Data-Type-driven value decoding (ADR-0011). Input is the raw node (string or\n// nested object) from the parser; output is the typed value. Empty -> null.\n\nimport { portersDateToIso, portersDateTimeToIso } from \"../util/datetime\";\nimport { asRecord, asString } from \"./raw\";\n\n// Granularity = PORTERS Data Type (ADR-0016). Labels are the literal Data Type\n// strings, incl. the System family (`System[Id]` / `System[DateTime]` / `System[Reference]`).\n// Currency collapses to Number and the three Option subtypes to Option (PORTERS' own\n// Data Type does the same); the string Data Types stay distinct (room for future\n// validation / normalisation). The `System[…]` qualifier marks system-managed values\n// (auto-assigned, often Write-restricted); that lifecycle is enforced via input types,\n// not here — decoding is by value shape.\nexport type DataType =\n | \"System[Id]\"\n | \"Number\"\n | \"DateTime\"\n | \"System[DateTime]\"\n | \"Date\"\n | \"Age\"\n | \"SinglelineText\"\n | \"MultilineText\"\n | \"Mail\"\n | \"Telephone\"\n | \"URL\"\n | \"User\"\n | \"Option\"\n | \"System[Reference]\";\n\n/** A referenced User (Read is nested; Write is `User.P_Id` only). */\nexport type UserRef = {\n P_Id: number | null;\n P_Type: string | null;\n P_Name: string | null;\n P_Mail: string | null;\n};\n\n// `string[]` is the Option read value (a set of selected aliases — ADR-0017).\nexport type FieldValue = string | number | string[] | UserRef | null;\n\n// Per-Data-Type decoded value (the non-null shape). A read value is `DecodedValue<D> | null`\n// (empty -> null). Mirrors `decodeField`'s branches and drives the static resource Read type\n// (ADR-0019): id/number/reference -> number, User -> UserRef, Option -> string[], rest -> string.\nexport type DecodedValue<D extends DataType> = D extends\n | \"System[Id]\"\n | \"Number\"\n | \"System[Reference]\"\n ? number\n : D extends \"User\"\n ? UserRef\n : D extends \"Option\"\n ? string[]\n : string;\n\n// alias タグは接頭辞付き想定(例 `User.P_Id`)だが、接頭辞無しにも両対応(ADR-0011)。\n// 全 arrow(ADR-0013)=巻き上げ無しのため、ヘルパーを decodeField より前に定義する。\nconst pickPrefixed = (\n obj: Record<string, unknown>,\n prefix: string,\n key: string,\n): string | undefined =>\n asString(obj[`${prefix}.${key}`]) ?? asString(obj[key]);\n\nconst decodeUser = (raw: unknown): UserRef | null => {\n const outer = asRecord(raw);\n const user = outer ? asRecord(outer.User) : undefined;\n if (!user) return null;\n const id = pickPrefixed(user, \"User\", \"P_Id\");\n return {\n P_Id: id === undefined ? null : Number(id),\n P_Type: pickPrefixed(user, \"User\", \"P_Type\") ?? null,\n P_Name: pickPrefixed(user, \"User\", \"P_Name\") ?? null,\n P_Mail: pickPrefixed(user, \"User\", \"P_Mail\") ?? null,\n };\n};\n\n// Read: the selected leaf aliases (e.g. `<Option.P_Tokyo/>`) sit under `<OptionRoot>`.\n// PORTERS represents single/multi alike as a set, so return every selected alias verbatim\n// — incl. the `Option.` prefix (ADR-0017). None / empty -> null.\n// VERIFY(live): the `Option.` prefix and the `OptionRoot` wrapper come from the Read API\n// doc, not a live contract; we tolerate a missing wrapper. See docs/live-verification.md (LV-1, LV-2).\nconst decodeOption = (raw: unknown): string[] | null => {\n const outer = asRecord(raw);\n if (!outer) return null;\n // Aliases live under `<OptionRoot>` when present; the doc's sample omits it, so fall\n // back to the field's own children.\n const root = \"OptionRoot\" in outer ? asRecord(outer.OptionRoot) : outer;\n if (!root) return null;\n const keys = Object.keys(root);\n return keys.length > 0 ? keys : null;\n};\n\n// System[Reference] Read mirrors User: <Field><Resource>...</Resource></Field>, but the\n// inner tag varies (Client/Recruiter/...). Write is ID-only, so we decode the referenced\n// record's id — enough to round-trip. Richer reference reading is future work (SD-3).\n// NB: the label is literally `System[Reference]` (a nested record). It is NOT the\n// display-only Field-Type-16 \"Reference\" (a scalar mirror, Data Type `—`), left uncatalogued.\nconst decodeReference = (raw: unknown): number | null => {\n const outer = asRecord(raw);\n if (!outer) return null;\n // The nested resource is the first record-valued child (skip attributes / siblings,\n // which decodeUser avoids via a fixed key — here the tag varies). Read that record's\n // own `{Tag}.P_Id` (prefix-less also accepted), not just any key ending in P_Id.\n for (const [tag, value] of Object.entries(outer)) {\n const inner = asRecord(value);\n if (!inner) continue;\n const id = asString(inner[`${tag}.P_Id`]) ?? asString(inner.P_Id);\n return id === undefined ? null : Number(id);\n }\n return null;\n};\n\n/** Decode one field's raw node by its Data Type. */\nexport const decodeField = (type: DataType, raw: unknown): FieldValue => {\n // `raw === \"\"` is load-bearing (a Text \"\" must become null, not stay \"\");\n // `=== undefined` / `=== null` are defense-in-depth — every switch branch below\n // also maps them to null, so dropping either is an equivalent mutant.\n // Stryker disable next-line ConditionalExpression: see above (undefined/null are redundant with the switch)\n if (raw === \"\" || raw === undefined || raw === null) return null;\n switch (type) {\n case \"System[Id]\":\n case \"Number\": {\n // raw is neither \"\" nor non-string here (guarded above), so `s` is a\n // non-empty string or undefined — `s === \"\"` would be dead.\n const s = asString(raw);\n return s === undefined ? null : Number(s);\n }\n // String Data Types share one decode (a plain string); they stay distinct\n // labels for fidelity / future per-type validation (ADR-0016).\n case \"SinglelineText\":\n case \"MultilineText\":\n case \"Mail\":\n case \"Telephone\":\n case \"URL\":\n return asString(raw) ?? null;\n // FT-12 DateTime and the system timestamps (registration/update) share the wire\n // format; System[DateTime] is Write-restricted, but that is a write-time concern.\n case \"DateTime\":\n case \"System[DateTime]\": {\n const s = asString(raw);\n return s === undefined ? null : portersDateTimeToIso(s);\n }\n // Age shares Date's wire format (`yyyy/mm/dd`); PORTERS transmits the birthdate\n // and derives the age in its UI, so the faithful value is the date itself.\n case \"Date\":\n case \"Age\": {\n const s = asString(raw);\n return s === undefined ? null : portersDateToIso(s);\n }\n case \"User\":\n return decodeUser(raw);\n case \"Option\":\n return decodeOption(raw);\n case \"System[Reference]\":\n return decodeReference(raw);\n }\n};\n","// Shared Read internals for every resource — data (resource.ts) and master\n// (partition/user/field/option). Owns catalog typing, the catalog-driven item decoder, the\n// GET+parse+decode runner, and offset pagination. Data resources add Write on top; master\n// resources add bespoke query/URL building (ADR-0021/0022). XML stays in xml/ — this only\n// wires parse + decode together.\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decodeField,\n type DataType,\n type DecodedValue,\n type FieldValue,\n} from \"../xml/decode\";\nimport { parseResourcePage, type RawItem } from \"../xml/parser\";\n\n// A field catalog: bare alias -> Data Type. Declared `as const` per resource so the static\n// Read/Write types derive from it — the catalog is the single source of truth (ADR-0019).\nexport type FieldCatalog = Record<string, DataType>;\n\n/**\n * \"No custom fields\": the intersection-identity default for the generic catalog params (ADR-0023).\n * A bare `{}` is flagged by `no-empty-object-type`; `Record<never, never>` is the same empty object,\n * lint-clean, adds no keys in `static & C`, and satisfies both `FieldCatalog` and `DeclaredCatalogs`.\n * Lives here (with `FieldCatalog`) so resources need not import from the higher-level `fields/` (RV-8).\n */\nexport type EmptyCatalog = Record<never, never>;\n\n/**\n * A decoded record: every known field, each `DecodedValue | null`, and **optional** because a\n * field not named in `field` is simply absent (SD-3 \"simple\" type — ADR-0005/0019). Custom\n * `U_`/`A_` aliases are not in the catalog, so they are not typed here (access via a cast until\n * the declaration DSL lands — ADR-0005 SD-2); at runtime they still pass through as raw values.\n */\nexport type ReadRecord<F extends FieldCatalog> = {\n [K in keyof F]?: DecodedValue<F[K]> | null;\n};\n\nexport type ResourcePage<F extends FieldCatalog> = {\n items: ReadRecord<F>[];\n total: number;\n count: number;\n start: number;\n};\n\n// `includes(\".\")` -> `includes(\"\")` is an equivalent mutant: for a dotless key,\n// slice(indexOf(\".\") + 1) is slice(0), which equals the key — same as the else.\n// Stryker disable StringLiteral\nconst bareAlias = (key: string): string =>\n key.includes(\".\") ? key.slice(key.indexOf(\".\") + 1) : key;\n// Stryker restore StringLiteral\n\n/**\n * Build a catalog-driven item decoder: known `P_` fields decode by their Data Type, unknown\n * `U_`/`A_` aliases pass through (raw string, or null when nested). `bareAlias` strips the\n * `{prefix}.` so `Person.P_Name` and `P_Name` both hit the catalog.\n */\nexport const decoderFor = <F extends FieldCatalog>(\n fields: F,\n): ((item: RawItem) => ReadRecord<F>) => {\n const fieldMap = new Map<string, DataType>(Object.entries(fields));\n return (item) => {\n const out: Record<string, FieldValue> = {};\n for (const [key, raw] of Object.entries(item)) {\n const alias = bareAlias(key);\n const type = fieldMap.get(alias);\n out[alias] = type\n ? decodeField(type, raw)\n : typeof raw === \"string\"\n ? raw\n : null;\n }\n return out as ReadRecord<F>;\n };\n};\n\n/** GET a Read URL, parse the standard envelope (Total/Count/Start + Items), decode each item. */\nexport const runRead = <F extends FieldCatalog>(\n requester: Requester,\n url: string,\n decode: (item: RawItem) => ReadRecord<F>,\n): Promise<ResourcePage<F>> =>\n requester.request({ method: \"GET\", url, headers: {} }, (body) => {\n const page = parseResourcePage(body);\n return {\n items: page.items.map(decode),\n total: page.total,\n count: page.count,\n start: page.start,\n };\n });\n\n// Read max page size (docs/reference: count 1–200). searchAll pages by this.\nconst PAGE_SIZE = 200;\n\n/**\n * Offset pagination shared by every `searchAll`. Advances by the items actually returned and\n * stops at `total` — or on an empty page (defensive against a stuck offset / infinite loop).\n * A generator can't be an arrow; a function expression still satisfies func-style:expression.\n */\nexport const paginate = async function* <T>(\n fetchPage: (\n count: number,\n start: number,\n ) => Promise<{ items: T[]; total: number }>,\n): AsyncGenerator<T> {\n let start = 0;\n for (;;) {\n const page = await fetchPage(PAGE_SIZE, start);\n for (const item of page.items) yield item;\n start += page.items.length;\n if (page.items.length === 0 || start >= page.total) return;\n }\n};\n","// Generic resource accessor (ADR-0004/0005/0011): the Read (search / searchAll /\n// get) + Write (create / update) shape shared by every PORTERS resource. A resource\n// module supplies its names + Data-Type catalog; this owns the wiring and keeps XML\n// out of resources/ (parse/encode live in xml/). Standard `P_` fields use the catalog;\n// custom `U_`/`A_` pass through (decode: raw string / encode: Text).\n\nimport { PortersResourceError, resourceError } from \"../errors\";\nimport type { Requester } from \"../http/requester\";\nimport type { DataType } from \"../xml/decode\";\nimport {\n buildWriteXml,\n type WritableDataType,\n type WriteItem,\n type WriteValueOf,\n} from \"../xml/encode\";\nimport { parseWriteResult } from \"../xml/parser\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\n// Shared Read types/internals live in read-core (reused by master resources). Re-export the\n// types so the data-resource modules keep importing them from \"./resource\".\nexport type {\n EmptyCatalog,\n FieldCatalog,\n ReadRecord,\n ResourcePage,\n} from \"./read-core\";\n\nexport type SearchQuery = {\n /**\n * Output fields as prefixed aliases (e.g. `Person.P_Name`). **Omit** to fetch every catalogued\n * field by default (ADR-0020): PORTERS returns only the primary key for a fieldless request, so\n * the library sends a catalog-derived default field set instead. Pass `[]` to opt into that\n * API-native \"primary key only\" response (e.g. counting). A non-empty list is sent verbatim.\n */\n field?: string[];\n condition?: Record<string, string>;\n count?: number;\n start?: number;\n};\n\n// Writable aliases: every field whose Data Type a user may write (excludes System[Id] /\n// System[DateTime] — ADR-0016/0019).\ntype WritableKeys<F extends FieldCatalog> = {\n [K in keyof F]: F[K] extends WritableDataType ? K : never;\n}[keyof F];\n\n/**\n * Create input (ADR-0019 W2): the `requiredOnCreate` aliases are **required** (non-null); every\n * other writable field is optional (`null` omits). `P_Id` is supplied by the library — not here.\n */\nexport type CreateInput<F extends FieldCatalog, Req extends keyof F> = {\n [K in Req]: WriteValueOf<F[K]>;\n} & {\n [K in Exclude<WritableKeys<F>, Req>]?: WriteValueOf<F[K]> | null;\n};\n\n/** Update input (ADR-0019 W2): every writable field optional (`null` omits, `\"\"` clears). */\nexport type UpdateInput<F extends FieldCatalog> = {\n [K in WritableKeys<F>]?: WriteValueOf<F[K]> | null;\n};\n\n/** Static description of a resource: names + `as const` catalog + required-on-create aliases. */\nexport type ResourceConfig<\n F extends FieldCatalog,\n Req extends readonly (keyof F)[],\n> = {\n /** Root element + Write resource name, e.g. `\"Candidate\"`. */\n name: string;\n /** URL path segment, e.g. `\"candidate\"`. */\n path: string;\n /** Field alias prefix, e.g. `\"Person\"`. */\n prefix: string;\n /** Data-Type catalog (`as const`): bare alias -> Data Type. */\n fields: F;\n /** Aliases required on `create` (PORTERS new-record requirements — ADR-0019 W2). */\n requiredOnCreate: Req;\n};\n\nexport type Resource<F extends FieldCatalog, Req extends keyof F> = {\n search(query?: SearchQuery): Promise<ResourcePage<F>>;\n /** Auto-paginating search: yields every matching record (200 per page). */\n searchAll(\n query?: Omit<SearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<ReadRecord<F>>;\n get(id: number): Promise<ReadRecord<F> | undefined>;\n /** Create one record; resolves to the newly assigned id. */\n create(input: CreateInput<F, Req>): Promise<number>;\n /** Update one record by id; resolves to that id. */\n update(id: number, input: UpdateInput<F>): Promise<number>;\n};\n\n// The 4 readable sub-fields of a User-type field (docs/reference: only these are returned).\nconst USER_SUBFIELDS = [\"P_Id\", \"P_Type\", \"P_Name\", \"P_Mail\"] as const;\n\n// Default Read `field` list derived from the catalog (ADR-0020, 案A+2a). PORTERS returns only\n// `{Resource}.P_Id` for a fieldless request, so a typed-record read would otherwise drop every\n// known field despite the type promising them. We send every catalog alias as `{prefix}.{alias}`,\n// expanding User to its 4 readable sub-fields and leaving System[Reference] ID-only (`()` omitted)\n// so the wire shape matches decode.ts. The API-native \"primary key only\" stays reachable via\n// `field: []` (透明化 — see SearchQuery.field).\nconst defaultFieldList = (prefix: string, fields: FieldCatalog): string[] =>\n Object.entries(fields).map(([alias, type]) =>\n type === \"User\"\n ? `${prefix}.${alias}(${USER_SUBFIELDS.map((s) => `User.${s}`).join(\",\")})`\n : `${prefix}.${alias}`,\n );\n\n/**\n * A single-Item Write response -> the assigned/updated id. A non-zero per-item Code is a\n * resource error (mapped, not swallowed); a missing result Item is unparseable. Shared by\n * the generic factory and the bespoke Attachment accessor. `path` names the error code\n * message, `name` the error context resource.\n */\nexport const firstWriteResultId = (\n body: string,\n path: string,\n name: string,\n): number => {\n const first = parseWriteResult(body)[0];\n if (first === undefined) {\n throw new PortersResourceError(\"write returned no result item\", {\n category: \"unknown\",\n });\n }\n if (first.code !== 0) {\n throw resourceError(\n first.code,\n `${path} write returned code ${first.code}`,\n {\n resource: name,\n },\n );\n }\n return first.id;\n};\n\n/** Build a Read URL: `https://{host}/v1/{path}?partition=…&field=…&condition=…&count=…&start=…`. */\nexport const buildReadUrl = (\n host: string,\n partition: number,\n path: string,\n q: SearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n if (q.field && q.field.length > 0) p.set(\"field\", q.field.join(\",\"));\n if (q.condition) {\n const conds = Object.entries(q.condition).map(([k, v]) => `${k}=${v}`);\n if (conds.length > 0) p.set(\"condition\", conds.join(\",\"));\n }\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/${path}?${p.toString()}`;\n};\n\n/** Build a Write URL: `https://{host}/v1/{path}?partition=…`. */\nexport const buildWriteUrl = (\n host: string,\n partition: number,\n path: string,\n): string => `https://${host}/v1/${path}?partition=${partition}`;\n\nexport const createResource = <\n const F extends FieldCatalog,\n const Req extends readonly (keyof F)[],\n>(\n config: ResourceConfig<F, Req>,\n deps: { requester: Requester; host: string; partition: number },\n): Resource<F, Req[number]> => {\n // The catalog is `as const` for the types; encode needs a runtime lookup, decode gets its own.\n const fieldMap = new Map<string, DataType>(Object.entries(config.fields));\n const decode = decoderFor(config.fields);\n // Computed once: the default field set sent when a caller omits `field` (ADR-0020).\n const defaultFields = defaultFieldList(config.prefix, config.fields);\n\n const readUrl = (q: SearchQuery): string =>\n buildReadUrl(deps.host, deps.partition, config.path, q);\n\n const writeUrl = (): string =>\n buildWriteUrl(deps.host, deps.partition, config.path);\n\n const firstWriteId = (body: string): number =>\n firstWriteResultId(body, config.path, config.name);\n\n // `field` omitted -> send the catalog default; `[]` stays empty (API-native primary key\n // only); a provided list is sent verbatim (ADR-0020).\n const search = (query: SearchQuery = {}): Promise<ResourcePage<F>> =>\n runRead(\n deps.requester,\n readUrl({ ...query, field: query.field ?? defaultFields }),\n decode,\n );\n\n const searchAll = (\n query: Omit<SearchQuery, \"count\" | \"start\"> = {},\n ): AsyncIterable<ReadRecord<F>> =>\n paginate((count, start) => search({ ...query, count, start }));\n\n const get = async (id: number): Promise<ReadRecord<F> | undefined> => {\n const page = await search({\n condition: { [`${config.prefix}.P_Id:eq`]: String(id) },\n count: 1,\n });\n return page.items[0];\n };\n\n // create forces P_Id=-1 (non-idempotent: a retry would duplicate); update forces\n // the target id (idempotent: re-applying the same write is safe). Forcing P_Id\n // after the spread means a caller-supplied P_Id never overrides it.\n const write = (item: WriteItem, idempotent: boolean): Promise<number> =>\n deps.requester.request(\n {\n method: \"POST\",\n url: writeUrl(),\n headers: {},\n body: buildWriteXml({\n resource: config.name,\n prefix: config.prefix,\n fields: fieldMap,\n items: [item],\n }),\n },\n firstWriteId,\n { write: true, idempotent },\n );\n\n const create = (input: CreateInput<F, Req[number]>): Promise<number> =>\n write({ ...input, P_Id: -1 }, false);\n\n const update = (id: number, input: UpdateInput<F>): Promise<number> =>\n write({ ...input, P_Id: id }, true);\n\n return { search, searchAll, get, create, update };\n};\n","// Candidate accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Only the Data-Type catalog and names\n// are Candidate-specific; the static Candidate / input types derive from the catalog\n// (single source of truth — ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_Name: \"SinglelineText\",\n P_Reading: \"SinglelineText\",\n P_Mail: \"Mail\",\n P_MobileMail: \"Mail\",\n P_Telephone: \"Telephone\",\n P_Mobile: \"Telephone\",\n P_Country: \"SinglelineText\",\n P_Prefecture: \"SinglelineText\",\n P_City: \"SinglelineText\",\n P_Zipcode: \"SinglelineText\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/candidate.md「新規必須」列): P_Owner。\n// (System[Id] の P_Id も新規必須だが lib が -1 を供給するため型からは除外。LV-5 は reference で確定。)\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Candidate: known `P_` fields, each requested field `value | null`. */\nexport type Candidate = ReadRecord<typeof FIELDS>;\nexport type CandidatePage = ResourcePage<typeof FIELDS>;\nexport type CandidateSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` is required; `P_Id` / system timestamps are not settable. */\nexport type CandidateCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type CandidateUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Candidate accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type CandidateResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createCandidateResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): CandidateResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Candidate\",\n path: \"candidate\",\n prefix: \"Person\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Job accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Only the Data-Type catalog and\n// names are Job-specific. P_Client / P_Recruiter are System[Reference] (Write = ID).\n//\n// Display-only Reference fields (P_Mail, P_*Reference — they mirror a Recruiter value and\n// are not writable) are intentionally left out of the catalog: they read through as raw\n// strings. Multi-select Option read returns every selected alias as `string[]` (ADR-0017).\n// The static Job / input types derive from the catalog (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_Client: \"System[Reference]\",\n P_Recruiter: \"System[Reference]\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Position: \"SinglelineText\",\n P_Publish: \"Option\",\n P_JobCategorySummary: \"MultilineText\",\n P_JobCategory: \"Option\",\n P_IndustrySummary: \"MultilineText\",\n P_Industry: \"Option\",\n P_SalarySummary: \"MultilineText\",\n P_MinSalary: \"Number\",\n P_MaxSalary: \"Number\",\n P_AreaSummary: \"MultilineText\",\n P_Area: \"Option\",\n P_PayrollsText: \"SinglelineText\",\n P_Memo: \"MultilineText\",\n P_EmploymentPeriod: \"MultilineText\",\n // \"P_WokingHours\" is the alias as published by PORTERS (source typo); keep verbatim.\n P_WokingHours: \"MultilineText\",\n P_Holidays: \"MultilineText\",\n P_Benefits: \"MultilineText\",\n P_PubliclyTraded: \"Option\",\n P_SalesAmountText: \"SinglelineText\",\n P_EstablishmentDateText: \"SinglelineText\",\n P_CapitalText: \"SinglelineText\",\n P_EmploymentType: \"Option\",\n P_ExpectedAgeReason: \"Option\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/job.md「新規必須」列): P_Owner / P_Client /\n// P_Recruiter(P_Id は System[Id]=lib 供給のため除外)。LV-5 は reference で確定。\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n \"P_Client\",\n \"P_Recruiter\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Job: known `P_` fields, each requested field `value | null`. */\nexport type Job = ReadRecord<typeof FIELDS>;\nexport type JobPage = ResourcePage<typeof FIELDS>;\nexport type JobSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type JobCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type JobUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Job accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type JobResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createJobResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): JobResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Job\",\n path: \"job\",\n prefix: \"Job\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Client accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Only the Data-Type catalog and\n// names are Client-specific; the static Client / input types derive from the catalog\n// (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Name: \"SinglelineText\",\n P_Memo: \"MultilineText\",\n P_Country: \"SinglelineText\",\n P_Prefecture: \"SinglelineText\",\n P_City: \"SinglelineText\",\n P_Street: \"MultilineText\",\n P_Zipcode: \"SinglelineText\",\n P_Telephone: \"Telephone\",\n P_Fax: \"Telephone\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/client.md「新規必須」列): P_Owner。\n// (P_Id は System[Id]=lib 供給のため除外。LV-5 は reference で確定。)\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Client (company): known `P_` fields, each requested field `value | null`. */\nexport type Client = ReadRecord<typeof FIELDS>;\nexport type ClientPage = ResourcePage<typeof FIELDS>;\nexport type ClientSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type ClientCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type ClientUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Client accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type ClientResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createClientResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): ClientResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Client\",\n path: \"client\",\n prefix: \"Client\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Process accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. Process is the relational\n// resource linking a Candidate to a Job; P_Client / P_Recruiter / P_Job / P_Candidate /\n// P_Resume are System[Reference] (Write = the related record's id; P_Candidate is the\n// Person id).\n//\n// Display-only Reference fields (P_JobOwner, P_Job*Reference, P_ResumeOwner,\n// P_Resume*Reference — they mirror a Job/Recruiter/Person value and are not writable) are\n// intentionally left out of the catalog: scalar mirrors read through as raw strings,\n// nested ones (e.g. P_JobOwner -> a User) read as null. Multi-select Option read returns every\n// selected alias as `string[]` (ADR-0017). The static Process / input types derive from the catalog (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_Client: \"System[Reference]\",\n P_Recruiter: \"System[Reference]\",\n P_Job: \"System[Reference]\",\n P_Candidate: \"System[Reference]\",\n P_Resume: \"System[Reference]\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Close: \"Option\",\n P_CloseReason: \"Option\",\n P_ExpectedSalesAmount: \"Number\",\n P_ExpectedClosingDate: \"Date\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/process.md「新規必須」列): P_Owner と関連 5 項目\n// (P_Client / P_Recruiter / P_Job / P_Candidate / P_Resume)。P_Id は System[Id]=lib 供給で除外。\n// LV-5 は reference で確定。\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n \"P_Client\",\n \"P_Recruiter\",\n \"P_Job\",\n \"P_Candidate\",\n \"P_Resume\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Process (a Candidate's progress through a Job): known `P_` fields, each\n * requested field `value | null`. */\nexport type Process = ReadRecord<typeof FIELDS>;\nexport type ProcessPage = ResourcePage<typeof FIELDS>;\nexport type ProcessSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type ProcessCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type ProcessUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Process accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type ProcessResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createProcessResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): ProcessResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Process\",\n path: \"process\",\n prefix: \"Process\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Resume accessor (ADR-0004/0005/0011/0019): Read (search / searchAll / get) + Write\n// (create / update) over the generic resource factory. A Resume belongs to a Candidate;\n// P_Candidate is System[Reference] (Write = the Person id).\n//\n// P_DateOfBirth is the Age Data Type — catalogued as \"Age\". Its wire value is the\n// birthdate (`yyyy/mm/dd`, same as Date); PORTERS derives the displayed age in its UI.\n// Display-only Reference fields (P_Mail, P_*Reference — they mirror a Person value and are\n// not writable) are intentionally left out of the catalog: scalar mirrors read through as\n// raw strings. Multi-select Option read returns every selected alias as `string[]` (ADR-0017).\n// Image-typed custom fields (U_) are future work. The static Resume / input types derive from the catalog (ADR-0019).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n createResource,\n type CreateInput,\n type EmptyCatalog,\n type FieldCatalog,\n type ReadRecord,\n type Resource,\n type ResourcePage,\n type SearchQuery,\n type UpdateInput,\n} from \"./resource\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Owner: \"User\",\n P_Candidate: \"System[Reference]\",\n P_RegistrationDate: \"System[DateTime]\",\n P_RegisteredBy: \"User\",\n P_UpdateDate: \"System[DateTime]\",\n P_UpdatedBy: \"User\",\n P_Phase: \"Option\",\n P_PhaseDate: \"DateTime\",\n P_PhaseMemo: \"MultilineText\",\n P_Name: \"SinglelineText\",\n P_RegisterChannel: \"Option\",\n P_Memo: \"MultilineText\",\n P_CurrentStatus: \"Option\",\n P_Education: \"MultilineText\",\n P_CarrierSummary: \"MultilineText\",\n P_CurrentSalary: \"Number\",\n P_ExperiencedJobCategory: \"Option\",\n P_ExperiencedIndustry: \"Option\",\n P_ChangeJobsCount: \"Number\",\n P_Gender: \"Option\",\n P_DateOfBirth: \"Age\",\n P_ExpectEmploymentType: \"Option\",\n P_ExpectArea: \"Option\",\n P_ExpectJobCategory: \"Option\",\n P_ExpectIndustry: \"Option\",\n P_ExpectCondition: \"MultilineText\",\n P_ExpectSalary: \"Number\",\n P_DesiredHourlyRate: \"Number\",\n P_HourlyRate: \"Number\",\n} as const satisfies FieldCatalog;\n\n// Required on create per docs/reference (resources/resume.md「新規必須」列): P_Owner / P_Candidate\n// (P_Id は System[Id]=lib 供給のため除外)。LV-5 は reference で確定。\nconst REQUIRED_ON_CREATE = [\n \"P_Owner\",\n \"P_Candidate\",\n] as const satisfies readonly (keyof typeof FIELDS)[];\n\n/** A decoded Resume (a Candidate's CV / profile): known `P_` fields, each requested field\n * `value | null`. */\nexport type Resume = ReadRecord<typeof FIELDS>;\nexport type ResumePage = ResourcePage<typeof FIELDS>;\nexport type ResumeSearchQuery = SearchQuery;\n\n/** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */\nexport type ResumeCreateInput = CreateInput<\n typeof FIELDS,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n/** Fields for `update`: all optional (`null` omits, `\"\"` clears a text field). */\nexport type ResumeUpdateInput = UpdateInput<typeof FIELDS>;\n/** The Resume accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */\nexport type ResumeResource<C extends FieldCatalog = EmptyCatalog> = Resource<\n typeof FIELDS & C,\n (typeof REQUIRED_ON_CREATE)[number]\n>;\n\nexport const createResumeResource = <C extends FieldCatalog = EmptyCatalog>(\n deps: { requester: Requester; host: string; partition: number },\n custom?: C,\n): ResumeResource<C> => {\n // Custom U_/A_ aliases never collide with P_, so the merge is exactly `typeof FIELDS & C`;\n // the cast just names that intersection (defineFields already validated aliases — ADR-0023 D7).\n const fields = { ...FIELDS, ...custom } as typeof FIELDS & C;\n return createResource(\n {\n name: \"Resume\",\n path: \"resume\",\n prefix: \"Resume\",\n fields,\n requiredOnCreate: REQUIRED_ON_CREATE,\n },\n deps,\n );\n};\n","// Attachment accessor (ADR-0018, bespoke): Read (search / get) + Write (create / update)\n// for file attachments. Attachment is unlike the other resources — no alias prefix, fixed\n// short field names (Id / Resource / ResourceId / ContentType / FileName / Content), and\n// `Content` is the Base64 file body (up to 10MB). It does not fit the generic factory but\n// reuses the requester, parsers, and `firstWriteResultId`. Turn raw bytes into the Base64\n// `content` with `util/base64`.\n\nimport { PortersConfigError } from \"../errors\";\nimport type { Requester } from \"../http/requester\";\nimport { encodeField } from \"../xml/encode\";\nimport { parseResourcePage } from \"../xml/parser\";\nimport { asString } from \"../xml/raw\";\nimport { buildReadUrl, buildWriteUrl, firstWriteResultId } from \"./resource\";\n\n// A 10MB file is ~13.98M Base64 chars; cap the encoded Content length before send\n// (fail-safe — the ~15000-char request guard is bypassed for uploads). docs/reference.\nconst MAX_CONTENT_CHARS = 14_000_000;\n\nconst ALL_FIELDS = [\n \"Id\",\n \"Resource\",\n \"ResourceId\",\n \"ContentType\",\n \"FileName\",\n \"Content\",\n];\n\n// Default for search() when `field` is omitted (ADR-0020): metadata only — exclude the (large,\n// up to ~14MB Base64) `Content` so listing attachments doesn't download every file body. Fetch\n// `Content` explicitly via `field` or per-record via get(). Mirrors PORTERS' Image default\n// (FileName only). `field: []` still opts into the API-native primary-key-only response.\nconst DEFAULT_FIELDS = [\n \"Id\",\n \"Resource\",\n \"ResourceId\",\n \"ContentType\",\n \"FileName\",\n];\n\n/** A decoded Attachment. A field is `null` unless it was returned (see `field`). */\nexport type Attachment = {\n id: number | null;\n /** Related resource type code (see the PORTERS Resource List). */\n resource: number | null;\n /** Related record id. */\n resourceId: number | null;\n contentType: string | null;\n fileName: string | null;\n /** Base64 file body. */\n content: string | null;\n};\n\nexport type AttachmentPage = {\n items: Attachment[];\n total: number;\n count: number;\n start: number;\n};\n\nexport type AttachmentSearchQuery = {\n /**\n * Output fields. **Omit** to fetch metadata by default (Id / Resource / ResourceId /\n * ContentType / FileName) — the large Base64 `Content` is excluded so listing doesn't download\n * every file body (ADR-0020); request `[\"Content\", …]` or use `get()` for the body. Pass `[]`\n * for the API-native primary-key-only response. A non-empty list is sent verbatim.\n */\n field?: string[];\n condition?: Record<string, string>;\n count?: number;\n start?: number;\n};\n\n/** Fields for creating an Attachment. `content` is the Base64 file body. */\nexport type AttachmentCreate = {\n resource: number;\n resourceId: number;\n contentType: string;\n fileName: string;\n content: string;\n};\n\n/** Fields for updating an Attachment. `Resource` / `ResourceId` are not updatable. */\nexport type AttachmentUpdate = {\n contentType?: string;\n fileName?: string;\n content?: string;\n};\n\nexport type AttachmentResource = {\n search(query?: AttachmentSearchQuery): Promise<AttachmentPage>;\n get(id: number): Promise<Attachment | undefined>;\n /** Create an Attachment; resolves to the newly assigned id. */\n create(input: AttachmentCreate): Promise<number>;\n /** Update an Attachment by id; resolves to that id. */\n update(id: number, input: AttachmentUpdate): Promise<number>;\n};\n\nconst numOrNull = (v: unknown): number | null => {\n const s = asString(v);\n return s === undefined ? null : Number(s);\n};\n\nconst decodeAttachment = (item: Record<string, unknown>): Attachment => ({\n id: numOrNull(item.Id),\n resource: numOrNull(item.Resource),\n resourceId: numOrNull(item.ResourceId),\n contentType: asString(item.ContentType) ?? null,\n fileName: asString(item.FileName) ?? null,\n content: asString(item.Content) ?? null,\n});\n\n// Bare `<Tag>value</Tag>` (Attachment has no alias prefix). encodeField escapes the value.\nconst tag = (name: string, value: string | number): string =>\n `<${name}>${encodeField(\"SinglelineText\", String(value))}</${name}>`;\n\n// Reject an over-10MB file before send (the request size guard is bypassed for uploads).\nconst guardContent = (content: string | undefined): void => {\n if (content !== undefined && content.length > MAX_CONTENT_CHARS) {\n throw new PortersConfigError(\n `attachment content is ${content.length} characters, over the ~10MB file limit`,\n { category: \"config\", hint: \"Attachment files must be 10MB or less.\" },\n );\n }\n};\n\nexport const createAttachmentResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): AttachmentResource => {\n // `field` omitted -> metadata default (no Content); `[]` -> API-native primary key only;\n // a provided list is sent verbatim (ADR-0020).\n const search = (query: AttachmentSearchQuery = {}): Promise<AttachmentPage> =>\n deps.requester.request(\n {\n method: \"GET\",\n url: buildReadUrl(deps.host, deps.partition, \"attachment\", {\n ...query,\n field: query.field ?? DEFAULT_FIELDS,\n }),\n headers: {},\n },\n (body) => {\n const page = parseResourcePage(body);\n return {\n items: page.items.map(decodeAttachment),\n total: page.total,\n count: page.count,\n start: page.start,\n };\n },\n );\n\n // VERIFY(live): Attachment has no alias prefix; the `Id:eq` condition and requesting all\n // fields (incl. Content) are taken from the field list, not a live contract.\n // See docs/live-verification.md (LV-3, LV-4).\n const get = async (id: number): Promise<Attachment | undefined> => {\n const page = await search({\n field: ALL_FIELDS,\n condition: { \"Id:eq\": String(id) },\n count: 1,\n });\n return page.items[0];\n };\n\n const write = (inner: string, idempotent: boolean): Promise<number> =>\n deps.requester.request(\n {\n method: \"POST\",\n url: buildWriteUrl(deps.host, deps.partition, \"attachment\"),\n headers: {},\n body: `<Attachment><Item>${inner}</Item></Attachment>`,\n },\n (body) => firstWriteResultId(body, \"attachment\", \"Attachment\"),\n { write: true, idempotent, unboundedBody: true },\n );\n\n // create forces Id=-1 (non-idempotent). All fields are required.\n const create = (input: AttachmentCreate): Promise<number> => {\n guardContent(input.content);\n const inner =\n tag(\"Id\", -1) +\n tag(\"Resource\", input.resource) +\n tag(\"ResourceId\", input.resourceId) +\n tag(\"ContentType\", input.contentType) +\n tag(\"FileName\", input.fileName) +\n tag(\"Content\", input.content);\n return write(inner, false);\n };\n\n // update targets the id (idempotent). Resource / ResourceId can't change; only the\n // provided fields are sent.\n const update = (id: number, input: AttachmentUpdate): Promise<number> => {\n guardContent(input.content);\n let inner = tag(\"Id\", id);\n if (input.contentType !== undefined) {\n inner += tag(\"ContentType\", input.contentType);\n }\n if (input.fileName !== undefined) inner += tag(\"FileName\", input.fileName);\n if (input.content !== undefined) inner += tag(\"Content\", input.content);\n return write(inner, true);\n };\n\n return { search, get, create, update };\n};\n","// Partition master accessor (read-only — ADR-0021/0022). Partition Read discovers the\n// partitions an App can access. It takes neither `partition` nor `field`/`condition`, only\n// `request_type`: 1 = the accessible-partition list (works under code_direct; the default),\n// 0 = the login partition (only under the browser `code` grant — 403s under code_direct, so\n// it is not exposed; ADR-0022 D3b). No `get(id)`: the API has no id/condition filter.\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Name: \"SinglelineText\",\n P_CompanyId: \"SinglelineText\",\n} as const satisfies FieldCatalog;\n\n/** A decoded Partition (a PORTERS contract company / Company DB). */\nexport type Partition = ReadRecord<typeof FIELDS>;\nexport type PartitionPage = ResourcePage<typeof FIELDS>;\n\n/** Partition Read query. `requestType` 1 = partitions this App can access (default). */\nexport type PartitionSearchQuery = {\n /** 1 = accessible partitions (default). 0 = login partition (browser `code` grant only). */\n requestType?: 0 | 1;\n count?: number;\n start?: number;\n};\n\nexport type PartitionResource = {\n search(query?: PartitionSearchQuery): Promise<PartitionPage>;\n /** Auto-paginating search: yields every accessible partition. */\n searchAll(\n query?: Omit<PartitionSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<Partition>;\n};\n\n// VERIFY(live): Partition Read taking no `partition` param is doc-only (every other read\n// requires it). See docs/live-verification.md (LV-8).\nconst buildUrl = (host: string, q: PartitionSearchQuery): string => {\n const p = new URLSearchParams();\n p.set(\"request_type\", String(q.requestType ?? 1));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/partition?${p.toString()}`;\n};\n\nexport const createPartitionResource = (deps: {\n requester: Requester;\n host: string;\n}): PartitionResource => {\n const decode = decoderFor(FIELDS);\n const search = (query: PartitionSearchQuery = {}): Promise<PartitionPage> =>\n runRead(deps.requester, buildUrl(deps.host, query), decode);\n const searchAll = (\n query: Omit<PartitionSearchQuery, \"count\" | \"start\"> = {},\n ): AsyncIterable<Partition> =>\n paginate((count, start) => search({ ...query, count, start }));\n return { search, searchAll };\n};\n","// User master accessor (read-only — ADR-0021/0022). User Read requires `partition` and\n// `request_type` (1 = all users; 0 = the current user — under code_direct this is the App's\n// own user, i.e. self-identification). `field` defaults to the 4 readable core fields, which\n// is exactly this catalog, so we omit it unless the caller narrows. No `condition`/`get(id)`:\n// the API has no id filter. Extended HR fields (department/telephone/dates/…) are deferred —\n// their read availability/decode shape is unconfirmed (see docs/live-verification.md).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Type: \"Number\",\n P_Name: \"SinglelineText\",\n P_Mail: \"Mail\",\n} as const satisfies FieldCatalog;\n\n/** A decoded User (PORTERS operator). `P_Type`: 0 = standard user, 1 = system admin. */\nexport type User = ReadRecord<typeof FIELDS>;\nexport type UserPage = ResourcePage<typeof FIELDS>;\n\n/** User Read query. `requestType` 1 = all users (default); `userType` -1 = any (default). */\nexport type UserSearchQuery = {\n /** 1 = all users (default). 0 = the current user (code_direct → the App's own user). */\n requestType?: 0 | 1;\n /** -1 = any (default), 0 = system admins, 1 = standard users. */\n userType?: -1 | 0 | 1;\n /** Output fields (prefixed aliases). Omit to get the 4 core fields (this catalog). */\n field?: string[];\n count?: number;\n start?: number;\n};\n\nexport type UserResource = {\n search(query?: UserSearchQuery): Promise<UserPage>;\n /** Auto-paginating search: yields every matching user. */\n searchAll(\n query?: Omit<UserSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<User>;\n /**\n * The current API user (`request_type=0`). Under the library's default `code_direct` auth\n * this resolves to the App's own user (username = app name) — useful for self-identification.\n * Under the browser `code` grant it is the logged-in user. Resolves `undefined` if none.\n */\n current(): Promise<User | undefined>;\n};\n\nconst buildUrl = (\n host: string,\n partition: number,\n q: UserSearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n p.set(\"request_type\", String(q.requestType ?? 1));\n p.set(\"user_type\", String(q.userType ?? -1));\n if (q.field && q.field.length > 0) p.set(\"field\", q.field.join(\",\"));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/user?${p.toString()}`;\n};\n\nexport const createUserResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): UserResource => {\n const decode = decoderFor(FIELDS);\n const search = (query: UserSearchQuery = {}): Promise<UserPage> =>\n runRead(deps.requester, buildUrl(deps.host, deps.partition, query), decode);\n const searchAll = (\n query: Omit<UserSearchQuery, \"count\" | \"start\"> = {},\n ): AsyncIterable<User> =>\n paginate((count, start) => search({ ...query, count, start }));\n // VERIFY(live): code_direct + request_type=0 returning the App's own user is doc-only.\n // See docs/live-verification.md (LV-7).\n const current = async (): Promise<User | undefined> =>\n (await search({ requestType: 0, count: 1 })).items[0];\n return { search, searchAll, current };\n};\n","// Field master accessor (read-only — ADR-0021/0022). Field Read introspects a resource's\n// field catalog (standard `P_` + tenant `U_`/`A_`). It requires `partition` and `resource`\n// (a resource-type Value code), plus optional `active`. No `field`/`condition`/`get(id)`.\n// `P_ReferTo` is a nested alias (the option group for Option-type fields, the parent field for\n// Reference-type) — decoded like an Option value to the referenced alias(es) (ADR-0022).\n\nimport type { Requester } from \"../http/requester\";\nimport {\n decoderFor,\n paginate,\n runRead,\n type FieldCatalog,\n type ReadRecord,\n type ResourcePage,\n} from \"./read-core\";\n\n// Resource-type selector -> Value code (docs/reference resources-list). Master/Phase/Attachment\n// have no Value, so only the R/W data resources are selectable here.\nconst RESOURCE_VALUE = {\n candidate: 1,\n job: 3,\n client: 5,\n recruiter: 9,\n sales: 11,\n contract: 13,\n resume: 17,\n activity: 19,\n opportunity: 25,\n contact: 27,\n} as const;\n\n/** A resource whose field catalog can be read (Field Read `resource` selector). */\nexport type ResourceType = keyof typeof RESOURCE_VALUE;\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Name: \"SinglelineText\",\n P_Alias: \"SinglelineText\",\n P_Type: \"Number\",\n P_Required: \"Number\",\n P_Max: \"Number\",\n P_Min: \"Number\",\n P_DecimalFraction: \"Number\",\n // Nested alias(es): the referenced option group / parent field. Reuse Option decode -> the\n // referenced alias(es) as string[] (usually one); empty -> null (ADR-0017/0022).\n // VERIFY(live): Reference-type P_ReferTo nesting is doc-only. See docs/live-verification.md (LV-6).\n P_ReferTo: \"Option\",\n P_ResourceType: \"Number\",\n} as const satisfies FieldCatalog;\n\n/** A decoded Field definition. `P_Required`: 0 = normal, 1 = required. */\nexport type Field = ReadRecord<typeof FIELDS>;\nexport type FieldPage = ResourcePage<typeof FIELDS>;\n\n/** Field Read query. `resource` selects which resource's fields to read (required). */\nexport type FieldSearchQuery = {\n resource: ResourceType;\n /** -1 = all (default), 0 = unused only, 1 = in-use only. */\n active?: -1 | 0 | 1;\n count?: number;\n start?: number;\n};\n\nexport type FieldResource = {\n search(query: FieldSearchQuery): Promise<FieldPage>;\n /** Auto-paginating search: yields every field of the resource. */\n searchAll(\n query: Omit<FieldSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<Field>;\n};\n\nconst buildUrl = (\n host: string,\n partition: number,\n q: FieldSearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n p.set(\"resource\", String(RESOURCE_VALUE[q.resource]));\n p.set(\"active\", String(q.active ?? -1));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n if (q.start !== undefined) p.set(\"start\", String(q.start));\n return `https://${host}/v1/field?${p.toString()}`;\n};\n\nexport const createFieldResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): FieldResource => {\n const decode = decoderFor(FIELDS);\n const search = (query: FieldSearchQuery): Promise<FieldPage> =>\n runRead(deps.requester, buildUrl(deps.host, deps.partition, query), decode);\n const searchAll = (\n query: Omit<FieldSearchQuery, \"count\" | \"start\">,\n ): AsyncIterable<Field> =>\n paginate((count, start) => search({ ...query, count, start }));\n return { search, searchAll };\n};\n","// Option master accessor (read-only — ADR-0021/0022). Option Read returns a tenant's choice\n// master as a recursive tree: each <Item> nests child <Item>s under <Items>. We flatten the\n// tree depth-first into one array — every node present, parent linkage kept via `P_ParentId`\n// and ordering via `P_Order` (ADR-0021 軸3, case 3a). It requires `partition` and takes\n// `alias`/`level`/`enabled`/`count` — no `start` (no offset paging → no searchAll), no\n// `field`/`condition`/`get(id)`.\n\nimport type { Requester } from \"../http/requester\";\nimport { parseResourcePage, type RawItem } from \"../xml/parser\";\nimport { asArray, asRecord } from \"../xml/raw\";\nimport { decoderFor, type FieldCatalog, type ReadRecord } from \"./read-core\";\n\nconst FIELDS = {\n P_Id: \"System[Id]\",\n P_Name: \"SinglelineText\",\n P_Alias: \"SinglelineText\",\n P_ParentId: \"Number\",\n P_Type: \"Number\",\n P_Order: \"Number\",\n} as const satisfies FieldCatalog;\n\n/** A decoded Option (one choice). `P_ParentId` links to the parent; `P_Type` 0 = normal, 1–11 = a phase kind. */\nexport type Option = ReadRecord<typeof FIELDS>;\n\n/** Option Read query. `alias` selects a subtree root; `level` its depth (-1 all). */\nexport type OptionSearchQuery = {\n /** Root alias of the subtree to read (e.g. `Option.P_Gender`). Omit for all. */\n alias?: string;\n /** Depth: -1 all (default), 0 = siblings of `alias`, 1+ = descendants. */\n level?: number;\n /** -1 = all (default), 0 = unused only, 1 = in-use only. */\n enabled?: -1 | 0 | 1;\n count?: number;\n};\n\nexport type OptionResource = {\n /** Read options, flattened depth-first (all nodes; tree is reconstructable via `P_ParentId`). */\n search(query?: OptionSearchQuery): Promise<Option[]>;\n};\n\nconst buildUrl = (\n host: string,\n partition: number,\n q: OptionSearchQuery,\n): string => {\n const p = new URLSearchParams();\n p.set(\"partition\", String(partition));\n if (q.alias !== undefined) p.set(\"alias\", q.alias);\n if (q.level !== undefined) p.set(\"level\", String(q.level));\n if (q.enabled !== undefined) p.set(\"enabled\", String(q.enabled));\n if (q.count !== undefined) p.set(\"count\", String(q.count));\n return `https://${host}/v1/option?${p.toString()}`;\n};\n\n// Decode one node's own fields, dropping the nested `Items` collection (handled by the walk).\nconst withoutItems = (raw: RawItem): RawItem =>\n Object.fromEntries(Object.entries(raw).filter(([k]) => k !== \"Items\"));\n\nexport const createOptionResource = (deps: {\n requester: Requester;\n host: string;\n partition: number;\n}): OptionResource => {\n const decode = decoderFor(FIELDS);\n // Depth-first flatten: push each node, then recurse into its <Items><Item>… children.\n const flatten = (items: RawItem[], out: Option[]): void => {\n for (const raw of items) {\n out.push(decode(withoutItems(raw)));\n const children = asArray(asRecord(raw.Items)?.Item).map(\n (it) => asRecord(it) ?? {},\n );\n flatten(children, out);\n }\n };\n const search = (query: OptionSearchQuery = {}): Promise<Option[]> =>\n deps.requester.request(\n {\n method: \"GET\",\n url: buildUrl(deps.host, deps.partition, query),\n headers: {},\n },\n (body) => {\n const out: Option[] = [];\n flatten(parseResourcePage(body).items, out);\n return out;\n },\n );\n return { search };\n};\n","import { createAuthApi, createDefaultTokenProvider } from \"./auth\";\nimport type {\n AuthApi,\n AuthProviderControls,\n TokenProvider,\n TokenStore,\n} from \"./auth\";\nimport {\n createFetchTransport,\n createRequester,\n createThrottle,\n expoBackoff,\n} from \"./http\";\nimport type { Transport } from \"./http\";\nimport {\n createAttachmentResource,\n createCandidateResource,\n createClientResource,\n createFieldResource,\n createJobResource,\n createOptionResource,\n createPartitionResource,\n createProcessResource,\n createResumeResource,\n createUserResource,\n} from \"./resources\";\nimport type {\n AttachmentResource,\n CandidateResource,\n ClientResource,\n FieldResource,\n JobResource,\n OptionResource,\n PartitionResource,\n ProcessResource,\n ResumeResource,\n UserResource,\n} from \"./resources\";\nimport type { CustomFor, DeclaredCatalogs, DefinedFields } from \"./fields\";\nimport type { EmptyCatalog } from \"./resources/read-core\";\nimport type { PartitionId, Scope } from \"./types\";\n\n/** Options for constructing a {@link PortersClient}. `C` is inferred from `fields` (ADR-0023). */\nexport type PortersClientOptions<C extends DeclaredCatalogs = EmptyCatalog> = {\n /**\n * API host. Required and supplied via `PORTERS_HOST` — never hard-code it.\n * (A representative value lives in docs/reference.)\n */\n host: string;\n appId?: string;\n appSecret?: string;\n scopes?: Scope[];\n /** Partition (Company DB) used for every call. Per-call override is not yet supported (planned — see ADR-0033). */\n partition?: PartitionId;\n /** Custom auth strategy; defaults to the transparent code_direct strategy. */\n auth?: TokenProvider;\n /** Token persistence; defaults to in-memory. */\n tokenStore?: TokenStore;\n /** Injectable HTTP transport; defaults to a fetch-based transport. */\n transport?: Transport;\n /**\n * Tenant custom field declarations from {@link defineFields} (ADR-0023). Each resource's\n * declared `U_`/`A_` fields are merged onto its static catalog, so they decode/encode by\n * their declared Data Type and appear typed on reads / writes. Omit for standard `P_` only.\n */\n fields?: DefinedFields<C>;\n};\n\n/**\n * Entry point of the library. Wires the default transport / auth / throttle /\n * requester and exposes namespaced resource accessors such as `candidate`\n * (ADR-0005).\n */\nexport class PortersClient<C extends DeclaredCatalogs = EmptyCatalog> {\n readonly candidate: CandidateResource<CustomFor<C, \"candidate\">>;\n readonly job: JobResource<CustomFor<C, \"job\">>;\n readonly client: ClientResource<CustomFor<C, \"client\">>;\n readonly process: ProcessResource<CustomFor<C, \"process\">>;\n readonly resume: ResumeResource<CustomFor<C, \"resume\">>;\n readonly attachment: AttachmentResource;\n /** OAuth surface: initial browser grant, token warm-up/inspection, local revoke (ADR-0007/0034). */\n readonly auth: AuthApi;\n /** Master Read: accessible partitions (ADR-0021/0022). */\n readonly partition: PartitionResource;\n /** Master Read: users, plus `current()` self-identification (ADR-0021/0022). */\n readonly user: UserResource;\n /** Master Read: a resource's field catalog (ADR-0021/0022). */\n readonly field: FieldResource;\n /** Master Read: a tenant's choice (option) master (ADR-0021/0022). */\n readonly option: OptionResource;\n readonly #host: string;\n\n constructor(options: PortersClientOptions<C>) {\n const transport = options.transport ?? createFetchTransport();\n // Custom strategy (案3) takes over token supply; otherwise the default transparent\n // provider also exposes cache/clear controls for the auth surface (ADR-0034 SD-7/SD-8).\n let auth: TokenProvider;\n let controls: AuthProviderControls | undefined = undefined;\n if (options.auth) {\n auth = options.auth;\n } else {\n const provider = createDefaultTokenProvider({\n host: options.host,\n appId: options.appId ?? \"\",\n appSecret: options.appSecret ?? \"\",\n transport,\n tokenStore: options.tokenStore,\n });\n auth = provider;\n controls = provider;\n }\n this.auth = createAuthApi({\n host: options.host,\n appId: options.appId,\n appSecret: options.appSecret,\n scopes: options.scopes,\n transport,\n provider: auth,\n controls,\n });\n const requester = createRequester({\n transport,\n auth,\n throttle: createThrottle(),\n backoff: expoBackoff(),\n });\n this.#host = options.host;\n const deps = {\n requester,\n host: options.host,\n partition: options.partition ?? 0,\n };\n // The per-resource custom catalog declared via defineFields (or {} when none). Branded\n // = already validated (ADR-0023 D4), so the factory merges it without re-checking.\n const customFor = <K extends keyof DeclaredCatalogs>(\n key: K,\n ): CustomFor<C, K> => (options.fields?.[key] ?? {}) as CustomFor<C, K>;\n this.candidate = createCandidateResource(deps, customFor(\"candidate\"));\n this.job = createJobResource(deps, customFor(\"job\"));\n this.client = createClientResource(deps, customFor(\"client\"));\n this.process = createProcessResource(deps, customFor(\"process\"));\n this.resume = createResumeResource(deps, customFor(\"resume\"));\n this.attachment = createAttachmentResource(deps);\n // Partition Read takes no `partition` param (it discovers them); the rest use the default.\n this.partition = createPartitionResource({ requester, host: options.host });\n this.user = createUserResource(deps);\n this.field = createFieldResource(deps);\n this.option = createOptionResource(deps);\n }\n\n /** The configured API host. */\n get host(): string {\n return this.#host;\n }\n}\n","// Custom field declaration DSL (ADR-0023, grounding ADR-0004 案H / ADR-0005 SD-2).\n// `defineFields` is the single validation boundary: a typed builder declares each\n// tenant custom field's Data Type per data resource, validation runs synchronously,\n// and the result is branded so PortersClient trusts it without re-validating. Standard\n// `P_` fields come from the static catalogs (ADR-0019); this only covers custom U_/A_.\n\nimport { PortersConfigError } from \"../errors\";\nimport type { EmptyCatalog } from \"../resources/read-core\";\nimport type { DataType } from \"../xml/decode\";\n\n/** One custom field's declared Data Type — the builder's return value (ADR-0023 D2). */\nexport type FieldDef<D extends DataType> = { readonly dataType: D };\n\n// Data Types a custom U_/A_ field may declare (ADR-0023 D3): the value-shaped types. The\n// System family (System[Id]/[DateTime]/[Reference]) is system-managed = standard territory,\n// so it is not offered; Image / Link are not modelled in DataType yet (future work).\nexport type CustomDataType =\n | \"Number\"\n | \"SinglelineText\"\n | \"MultilineText\"\n | \"Mail\"\n | \"Telephone\"\n | \"URL\"\n | \"Date\"\n | \"DateTime\"\n | \"Age\"\n | \"Option\"\n | \"User\";\n\n/** Builder passed to each resource declaration: one method per declarable Data Type. */\nexport type FieldBuilder = {\n number(): FieldDef<\"Number\">;\n singlelineText(): FieldDef<\"SinglelineText\">;\n multilineText(): FieldDef<\"MultilineText\">;\n mail(): FieldDef<\"Mail\">;\n telephone(): FieldDef<\"Telephone\">;\n url(): FieldDef<\"URL\">;\n date(): FieldDef<\"Date\">;\n dateTime(): FieldDef<\"DateTime\">;\n age(): FieldDef<\"Age\">;\n option(): FieldDef<\"Option\">;\n user(): FieldDef<\"User\">;\n};\n\n/** Data resources that accept custom fields (ADR-0023 D6). Master / Attachment are excluded. */\nexport type CustomFieldResource =\n | \"candidate\"\n | \"job\"\n | \"client\"\n | \"process\"\n | \"resume\";\n\n/** One resource's custom field declarations: alias -> {@link FieldDef}. */\nexport type ResourceDecl = Record<string, FieldDef<DataType>>;\n\n/** Declaration input: per (data) resource, a builder fn returning its custom fields. */\nexport type FieldDecls = {\n [R in CustomFieldResource]?: (f: FieldBuilder) => ResourceDecl;\n};\n\n/** A per-resource custom catalog (bare alias -> Data Type), as produced by {@link defineFields}. */\nexport type CustomCatalog = Record<string, DataType>;\n\n/** Map of (data) resource -> its custom catalog; the client merges these into the static catalogs. */\nexport type DeclaredCatalogs = {\n [R in CustomFieldResource]?: CustomCatalog;\n};\n\n// Extract the catalog (alias -> Data Type literal) from a resource's FieldDef map.\ntype CatalogOf<R extends ResourceDecl> = {\n [K in keyof R]: R[K][\"dataType\"];\n};\n\n/** The validated, branded result of {@link defineFields}, keyed by the declared resources. */\nexport type DeclaredCatalogsOf<D extends FieldDecls> = {\n [R in keyof D]: D[R] extends (f: FieldBuilder) => infer Out\n ? Out extends ResourceDecl\n ? CatalogOf<Out>\n : never\n : never;\n};\n\n// Phantom brand: marks a catalog set as already validated by defineFields (ADR-0023 D4).\n// It never exists at runtime — the value is a plain frozen object.\ndeclare const definedFieldsBrand: unique symbol;\n\n/** A validated set of custom field catalogs (branded — the client does not re-validate). */\nexport type DefinedFields<C extends DeclaredCatalogs = DeclaredCatalogs> = C & {\n readonly [definedFieldsBrand]: true;\n};\n\n/** The custom catalog declared for resource `K` (or `{}` if none) — types each accessor (ADR-0023 D1). */\nexport type CustomFor<\n C extends DeclaredCatalogs,\n K extends CustomFieldResource,\n> = K extends keyof C\n ? C[K] extends CustomCatalog\n ? C[K]\n : EmptyCatalog\n : EmptyCatalog;\n\n// 全 arrow(ADR-0013)=巻き上げ無しのため、ヘルパー → builder → defineFields の順で定義する。\nconst def = <D extends CustomDataType>(dataType: D): FieldDef<D> => ({\n dataType,\n});\n\nconst builder: FieldBuilder = {\n number: () => def(\"Number\"),\n singlelineText: () => def(\"SinglelineText\"),\n multilineText: () => def(\"MultilineText\"),\n mail: () => def(\"Mail\"),\n telephone: () => def(\"Telephone\"),\n url: () => def(\"URL\"),\n date: () => def(\"Date\"),\n dateTime: () => def(\"DateTime\"),\n age: () => def(\"Age\"),\n option: () => def(\"Option\"),\n user: () => def(\"User\"),\n};\n\n// Custom field aliases are `U_[Name]` (user-created) or `A_[Name]` (app-created) — ADR-0004.\nconst ALIAS_PATTERN = /^[UA]_/;\n\nconst KNOWN_RESOURCES: readonly CustomFieldResource[] = [\n \"candidate\",\n \"job\",\n \"client\",\n \"process\",\n \"resume\",\n];\n\n/**\n * Declare tenant-specific custom fields per data resource (ADR-0023). This is the validation\n * boundary: it throws {@link PortersConfigError} synchronously for an unknown resource key or an\n * alias that is not `U_`/`A_`-prefixed. The branded result is passed to `PortersClient({ fields })`,\n * which merges each catalog into the resource so the custom fields decode/encode by their declared\n * Data Type and appear typed on reads / writes.\n *\n * @example\n * const myFields = defineFields({\n * candidate: (f) => ({ U_score: f.number(), U_source: f.option() }),\n * });\n */\nexport const defineFields = <D extends FieldDecls>(\n decls: D,\n): DefinedFields<DeclaredCatalogsOf<D>> => {\n const catalogs: Record<string, CustomCatalog> = {};\n for (const [resource, declare] of Object.entries(decls)) {\n if (declare === undefined) continue;\n if (!KNOWN_RESOURCES.includes(resource as CustomFieldResource)) {\n throw new PortersConfigError(\n `defineFields: unknown resource \"${resource}\" (expected one of ${KNOWN_RESOURCES.join(\", \")})`,\n { category: \"config\" },\n );\n }\n const catalog: CustomCatalog = {};\n for (const [alias, fieldDef] of Object.entries(declare(builder))) {\n if (!ALIAS_PATTERN.test(alias)) {\n throw new PortersConfigError(\n `defineFields: custom field alias \"${alias}\" on \"${resource}\" must start with \"U_\" or \"A_\" (standard P_ fields are built in)`,\n { category: \"config\" },\n );\n }\n catalog[alias] = fieldDef.dataType;\n }\n catalogs[resource] = catalog;\n }\n return Object.freeze(catalogs) as DefinedFields<DeclaredCatalogsOf<D>>;\n};\n","// Opt-in binary <-> Base64 helpers for Attachment / Image content (ADR-0018). The\n// resource core takes a Base64 string; these let callers convert raw bytes without a\n// dependency. `btoa` / `atob` are globals on Node 20+ and browsers.\n\n/** Encode raw bytes to a Base64 string. */\nexport const bytesToBase64 = (bytes: Uint8Array): string => {\n // Build a Latin-1 \"binary string\" then Base64 it. O(n) string building — fine for\n // typical attachments; very large files can be encoded by the caller upstream.\n let binary = \"\";\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary);\n};\n\n/** Decode a Base64 string back to raw bytes. */\nexport const base64ToBytes = (b64: string): Uint8Array =>\n Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));\n"],"mappings":"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","names":["sleep","tag","FIELDS","REQUIRED_ON_CREATE","FIELDS","REQUIRED_ON_CREATE","FIELDS","REQUIRED_ON_CREATE","FIELDS","REQUIRED_ON_CREATE","FIELDS","FIELDS","buildUrl","FIELDS","buildUrl","FIELDS","buildUrl"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joymerrevent/porters-connect",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Unofficial type-safe TypeScript wrapper for the PORTERS Connect API (formerly HRBC).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"porters",
|
|
@@ -68,9 +68,12 @@
|
|
|
68
68
|
"changeset": "changeset",
|
|
69
69
|
"changeset:version": "changeset version",
|
|
70
70
|
"changeset:publish": "pnpm build && changeset publish",
|
|
71
|
+
"check:publish": "publint && attw --pack --ignore-rules cjs-resolves-to-esm",
|
|
72
|
+
"check:release": "node scripts/check-release-invariants.mjs",
|
|
71
73
|
"prepare": "simple-git-hooks"
|
|
72
74
|
},
|
|
73
75
|
"devDependencies": {
|
|
76
|
+
"@arethetypeswrong/cli": "^0.18.3",
|
|
74
77
|
"@changesets/cli": "^2.31.0",
|
|
75
78
|
"@commitlint/cli": "^21.0.2",
|
|
76
79
|
"@commitlint/config-conventional": "^21.0.2",
|
|
@@ -81,9 +84,11 @@
|
|
|
81
84
|
"@vitest/coverage-v8": "^4.1.9",
|
|
82
85
|
"eslint": "^10.5.0",
|
|
83
86
|
"eslint-config-prettier": "^10.1.8",
|
|
87
|
+
"globals": "^17.6.0",
|
|
84
88
|
"lint-staged": "^17.0.7",
|
|
85
89
|
"markdownlint-cli2": "^0.22.1",
|
|
86
90
|
"prettier": "^3.8.4",
|
|
91
|
+
"publint": "^0.3.21",
|
|
87
92
|
"simple-git-hooks": "^2.13.1",
|
|
88
93
|
"tsup": "^8.5.1",
|
|
89
94
|
"tsx": "^4.22.4",
|
|
@@ -98,19 +103,6 @@
|
|
|
98
103
|
"pre-commit": "pnpm exec lint-staged",
|
|
99
104
|
"commit-msg": "pnpm exec commitlint --edit \"$1\""
|
|
100
105
|
},
|
|
101
|
-
"lint-staged": {
|
|
102
|
-
"*.{ts,tsx,cts,mts,js,jsx,cjs,mjs}": [
|
|
103
|
-
"eslint --fix",
|
|
104
|
-
"prettier --write"
|
|
105
|
-
],
|
|
106
|
-
"*.json": [
|
|
107
|
-
"prettier --write"
|
|
108
|
-
],
|
|
109
|
-
"*.md": [
|
|
110
|
-
"markdownlint-cli2 --fix",
|
|
111
|
-
"prettier --write"
|
|
112
|
-
]
|
|
113
|
-
},
|
|
114
106
|
"pnpm": {
|
|
115
107
|
"overrides": {
|
|
116
108
|
"js-yaml": ">=4.2.0",
|