@joymerrevent/porters-connect 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,69 @@
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.9.0] - 2026-08-20
9
+
10
+ **Candidate でメモ・住所詳細が扱えるようになった版**です。標準項目でありながらカタログから漏れていた
11
+ 4 項目を追加し、同じ取りこぼしが二度と起きないよう reference との突合を CI で検査するようにしました。
12
+ 併せて `defineFields` と Read クエリの**利用ガイドを新設**しています。
13
+
14
+ ### Added
15
+
16
+ - **Candidate に標準 4 項目**(`P_Memo`(メモ)/`P_Street`(住所詳細)/`P_Fax`(FAX)/`P_PhaseMemo`(フェーズメモ))。
17
+ カタログが型の真実源([ADR-0019][adr19])なので、これまで **`Candidate` 型にも `CandidateCreateInput` /
18
+ `CandidateUpdateInput` にも現れず**、`candidate.create({ P_Memo: "…" })` は型エラーでした。
19
+ `field` 省略時の既定 field([ADR-0020][adr20])にも含まれないため **Read でも取得されません**でした。
20
+ 同じ 4 種は Client には最初から載っており、リソース間で非一貫でした。
21
+ - `field` を省略した Read は**既定 field が 4 つ増えるぶん URL が長くなります**(Candidate で約 100 文字)。
22
+ - **公開ジェネリクスの制約型を export**(`DeclaredCatalogs` / `CustomFor` / `CustomFieldResource`)。
23
+ `PortersClient<C>` / `TenantScope<C>` は公開型なのに制約側が非公開で、
24
+ クライアントを引数に取るヘルパーの型を**名前で書けません**でした(`typeof porters` での回避のみ)。
25
+ 型の追加のみで、既存コードへの影響はありません。
26
+ - **利用ガイドを 2 本新設**([ADR-0035][adr35] の型)。
27
+ - [カスタム項目ガイド][custom-fields-guide] — `defineFields` の宣言、**宣言しないとどうなるか**
28
+ (型が付かず `field` 省略時に取得されない)、宣言できる 11 の Data Type、
29
+ Field Read でテナントの項目を調べる手順、複数テナントでの使い分け。
30
+ - [Read クエリ ガイド][read-query-guide] — `field` の 3 通りの意味、**Data Type ごとの演算子一覧**、
31
+ 削除済み Read の制約(condition は 3 項目・90 日以内)、送信前に落ちるものの一覧。
32
+
33
+ ### Changed
34
+
35
+ - **Read の `count` が範囲外なら送信前に落ちます**。`count` は PORTERS 上 **1〜200**(既定 10)ですが、
36
+ これまで範囲外の値をそのまま送っており、不透明なサーバー応答に倒れていました。
37
+ 今後は `PortersConfigError`(`category: "config"` + `searchAll()` を案内する `hint`)で**リクエストの前に**弾きます。
38
+ 整数でない値(`1.5` など)も同様です。
39
+ - keywords の 100 文字・itemstate の condition 制限・リクエスト長 ~15000 字と同じ
40
+ 「早く・明確に落とす」系列に揃いました。データ系・マスタ系・Attachment の**すべての Read 経路**に効きます。
41
+ - `count` を省略した場合の挙動は変わりません(API 既定に委ねます)。
42
+
43
+ ### Fixed
44
+
45
+ - **reference と静的カタログの突合を CI で検査**するようになりました。値を持つ標準項目の取りこぼし・
46
+ カタログ側の幻の項目・Field Type → Data Type の取り違えを検出します。
47
+ 上記 Candidate の欠落は **0.1.0 から 12 版・563 テストをすべて素通り**していたため、
48
+ 人の目ではなく仕組みで守ります。
49
+
50
+ ## [0.8.0] - 2026-08-14
51
+
52
+ **「0 件」と「届いていない」を区別できるようにした版**です。HTTP 200 を返す中間装置
53
+ (キャプティブポータル・SSO のログイン画面・WAF の通知ページ)の応答が、これまで**正常な空ページ**として
54
+ 通っていました。公開 API の形(型・メソッド)は不変で、**正しい PORTERS 応答に対する挙動も変わりません**。
55
+
56
+ ### Fixed
57
+
58
+ - **HTTP 200 で返る「PORTERS 以外の応答」を 0 件として扱わなくなりました**([ADR-0051][adr51])。
59
+ Read 応答は**ルート要素名(`<Candidate>` などリソース名)と `<Code>` の両方**で同定します。
60
+ どちらかを欠くボディは `PortersResourceError`(`category: "unknown"` + `httpStatus: 200` + 中間装置を疑う `hint`)で拒否します。
61
+ - 従来は**キャプティブポータル・SSO のログイン画面・WAF の通知ページ**(いずれも HTTP 200)が
62
+ `total: 0` の**正常な空ページ**として返っていました。`get(id)` は `undefined` を返すため、
63
+ **「無ければ作る」コードが重複レコードを作りにいく**状態でした(データが無いのか届いていないのかを区別できない)。
64
+ - メッセージは原因を名指しします — `resource response root is <html>, expected <Candidate>` /
65
+ `resource response has no <Code> (not a PORTERS envelope)`。**観測したルート名**が載るので切り分けできます。
66
+ - **正しい PORTERS 応答に対する挙動は変わりません**([エラーハンドリング ガイド][guide]に判定表を追加)。
67
+ - ⚠️ **`createMockTransport` でモックを手書きしている場合**は、ボディに**リソース名のルート要素と `<Code>`** が
68
+ 必要です(例 `<Candidate Total="1" Count="1" Start="0"><Code>0</Code>…</Candidate>`)。
69
+ 実際の応答と同じ形にしていれば変更は不要です。
70
+
8
71
  ## [0.7.0] - 2026-08-13
9
72
 
10
73
  エラーの見え方をまとめて是正した版です。**PORTERS の応答ではない HTTP エラー**が分類されるようになり、
@@ -217,11 +280,19 @@
217
280
  [adr48]: docs/adr/0048-access-point-host-validation.md
218
281
  [adr49]: docs/adr/0049-host-port-roundtrip.md
219
282
  [adr50]: docs/adr/0050-auth-http-status-handling.md
283
+ [adr51]: docs/adr/0051-read-envelope-identification.md
220
284
  [adr47]: docs/adr/0047-access-point-scheme.md
221
285
  [oauth-guide]: docs/guide/oauth.md
286
+ [adr19]: docs/adr/0019-static-resource-types.md
287
+ [adr20]: docs/adr/0020-read-field-default.md
288
+ [adr35]: docs/adr/0035-usage-documentation-structure.md
289
+ [custom-fields-guide]: docs/guide/custom-fields.md
290
+ [read-query-guide]: docs/guide/read-query.md
222
291
  [kac]: https://keepachangelog.com/en/1.1.0/
223
292
  [semver]: https://semver.org/
224
- [unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.7.0...HEAD
293
+ [unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.9.0...HEAD
294
+ [0.9.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.8.0...v0.9.0
295
+ [0.8.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.7.0...v0.8.0
225
296
  [0.7.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.6.2...v0.7.0
226
297
  [0.6.2]: https://github.com/Joymerrevent/porters-connect/compare/v0.6.1...v0.6.2
227
298
  [0.6.1]: https://github.com/Joymerrevent/porters-connect/compare/v0.6.0...v0.6.1
package/README.md CHANGED
@@ -192,10 +192,40 @@ await porters.auth.exchangeAuthorizationCode(code);
192
192
  - `order`:並び順。`[{ 項目: "asc" | "desc" }]`(数値・日時・System 型のみ)。
193
193
  - `keywords`:テキスト項目のキーワード AND 検索(`string[]`・カンマ込み **100 文字まで**)。
194
194
  - `itemstate`:`"existing"`(既定)/ `"deleted"` / `"all"`。削除済みデータの取得。
195
- - `count`(1–200・既定 10)、`start`(0 始まり)。
195
+ - `count`(1–200・既定 10)、`start`(0 始まり)。**範囲外の `count` は送信前に `PortersConfigError`** で落ちます。
196
196
 
197
197
  > **削除 API はありません**(PORTERS 仕様)。`delete()` メソッドは提供しません。削除済みは `itemstate: "deleted"` で読みます
198
198
  > (`condition` は `P_Id` / `P_UpdateDate` / `P_UpdatedBy` に限られ、更新日は 90 日以内)。
199
+ >
200
+ > `field` の 3 通りの意味(省略=全項目 / `[]`=主キーのみ / 明示)、Data Type ごとの演算子一覧、
201
+ > 削除済み Read の制約、送信前に落ちる条件は [Read クエリ ガイド][read-query-guide] にまとめています。
202
+
203
+ ### カスタム項目(`U_` / `A_`)
204
+
205
+ テナント固有のカスタム項目は `defineFields` で宣言すると、**読み書きの型に現れ**、Data Type どおりに変換されます。
206
+
207
+ ```ts
208
+ import { PortersClient, defineFields } from "@joymerrevent/porters-connect";
209
+
210
+ const fields = defineFields({
211
+ candidate: (f) => ({ U_score: f.number(), U_source: f.option() }),
212
+ });
213
+ const porters = new PortersClient({
214
+ host,
215
+ appId,
216
+ appSecret,
217
+ partition,
218
+ fields,
219
+ });
220
+
221
+ const one = await porters.candidate.get(10001);
222
+ one?.U_score; // number | null | undefined
223
+ ```
224
+
225
+ 宣言しなくても読み書きはできますが(生の文字列として通ります)、**型が付かず、`field` 省略時に取得もされません**。
226
+
227
+ > 宣言できる型の一覧、テナントの項目を Field Read で調べる方法、複数テナントでの扱いは
228
+ > [カスタム項目 ガイド][custom-fields-guide] にまとめています。
199
229
 
200
230
  ### マスタ Read(読み取り専用)
201
231
 
@@ -407,6 +437,8 @@ try {
407
437
  [auth-flow]: ./docs/reference/authentication-api/README.md
408
438
  [oauth-guide]: ./docs/guide/oauth.md
409
439
  [error-handling]: ./docs/guide/error-handling.md
440
+ [custom-fields-guide]: ./docs/guide/custom-fields.md
441
+ [read-query-guide]: ./docs/guide/read-query.md
410
442
  [multi-tenancy]: ./docs/guide/multi-tenancy.md
411
443
  [bulk-write]: ./docs/guide/bulk-write.md
412
444
  [sandbox]: ./examples/offline-sandbox.ts
package/dist/index.d.ts CHANGED
@@ -332,15 +332,19 @@ declare const FIELDS$8: {
332
332
  readonly P_UpdatedBy: "User";
333
333
  readonly P_Phase: "Option";
334
334
  readonly P_PhaseDate: "DateTime";
335
+ readonly P_PhaseMemo: "MultilineText";
335
336
  readonly P_Name: "SinglelineText";
336
337
  readonly P_Reading: "SinglelineText";
338
+ readonly P_Memo: "MultilineText";
337
339
  readonly P_Mail: "Mail";
338
340
  readonly P_MobileMail: "Mail";
339
341
  readonly P_Telephone: "Telephone";
340
342
  readonly P_Mobile: "Telephone";
343
+ readonly P_Fax: "Telephone";
341
344
  readonly P_Country: "SinglelineText";
342
345
  readonly P_Prefecture: "SinglelineText";
343
346
  readonly P_City: "SinglelineText";
347
+ readonly P_Street: "MultilineText";
344
348
  readonly P_Zipcode: "SinglelineText";
345
349
  };
346
350
  declare const REQUIRED_ON_CREATE$4: readonly ["P_Owner"];
@@ -901,4 +905,4 @@ declare const bytesToBase64: (bytes: Uint8Array) => string;
901
905
  /** Decode a Base64 string back to raw bytes. */
902
906
  declare const base64ToBytes: (b64: string) => Uint8Array;
903
907
 
904
- export { type Attachment, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AuthApi, type AuthorizationUrlOptions, type BulkWriteResult, type BulkWriteResultItem, type Candidate, type CandidateCreateInput, type CandidatePage, type CandidateResource, type CandidateSearchQuery, type CandidateUpdateInput, type Client, type ClientCreateInput, type ClientPage, type ClientResource, type ClientSearchQuery, type ClientUpdateInput, type Condition, type CustomDataType, type DefinedFields, type ErrorCategory, type Field, type FieldBuilder, type FieldDecls, type FieldDef, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldValue, type GetAccessTokenOptions, type ItemState, 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 Order, 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 Scheme, type Scope, type SearchQuery, type StoredTokens, type TenantScope, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, base64ToBytes, bytesToBase64, createMockTransport, defineFields };
908
+ export { type Attachment, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AuthApi, type AuthorizationUrlOptions, type BulkWriteResult, type BulkWriteResultItem, type Candidate, type CandidateCreateInput, type CandidatePage, type CandidateResource, type CandidateSearchQuery, type CandidateUpdateInput, type Client, type ClientCreateInput, type ClientPage, type ClientResource, type ClientSearchQuery, type ClientUpdateInput, type Condition, type CustomDataType, type CustomFieldResource, type CustomFor, type DeclaredCatalogs, type DefinedFields, type ErrorCategory, type Field, type FieldBuilder, type FieldDecls, type FieldDef, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldValue, type GetAccessTokenOptions, type ItemState, 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 Order, 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 Scheme, type Scope, type SearchQuery, type StoredTokens, type TenantScope, 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
@@ -380,7 +380,8 @@ var toInt = (v) => {
380
380
  const s = asString(v);
381
381
  return s === void 0 ? 0 : Number(s);
382
382
  };
383
- var parseResourcePage = (xml) => {
383
+ var MIDDLEBOX_HINT = "A middlebox (proxy, captive portal, SSO login page, WAF notice) may be answering instead of PORTERS. Check PORTERS_HOST and the network path from this process to the API.";
384
+ var parseResourcePage = (xml, resource) => {
384
385
  const root = asRecord(parser.parse(xml));
385
386
  const rootKey = root ? Object.keys(root)[0] : void 0;
386
387
  const body = root && rootKey ? asRecord(root[rootKey]) : void 0;
@@ -389,11 +390,21 @@ var parseResourcePage = (xml) => {
389
390
  category: "unknown"
390
391
  });
391
392
  }
393
+ if (rootKey !== resource) {
394
+ throw new PortersResourceError(
395
+ `resource response root is <${rootKey}>, expected <${resource}>`,
396
+ { category: "unknown", hint: MIDDLEBOX_HINT, context: { resource } }
397
+ );
398
+ }
399
+ if (body.Code === void 0) {
400
+ throw new PortersResourceError(
401
+ "resource response has no <Code> (not a PORTERS envelope)",
402
+ { category: "unknown", hint: MIDDLEBOX_HINT, context: { resource } }
403
+ );
404
+ }
392
405
  const code = toInt(body.Code);
393
406
  if (code !== 0) {
394
- throw resourceError(code, `resource returned code ${code}`, {
395
- resource: rootKey
396
- });
407
+ throw resourceError(code, `resource returned code ${code}`, { resource });
397
408
  }
398
409
  return {
399
410
  total: toInt(body["@_Total"]),
@@ -826,8 +837,8 @@ var decoderFor = (fields) => {
826
837
  return out;
827
838
  };
828
839
  };
829
- var runRead = (requester, url, decode) => requester.request({ method: "GET", url, headers: {} }, (body) => {
830
- const page = parseResourcePage(body);
840
+ var runRead = (requester, resource, url, decode) => requester.request({ method: "GET", url, headers: {} }, (body) => {
841
+ const page = parseResourcePage(body, resource);
831
842
  return {
832
843
  items: page.items.map(decode),
833
844
  total: page.total,
@@ -835,7 +846,24 @@ var runRead = (requester, url, decode) => requester.request({ method: "GET", url
835
846
  start: page.start
836
847
  };
837
848
  });
838
- var PAGE_SIZE = 200;
849
+ var MIN_READ_COUNT = 1;
850
+ var MAX_READ_COUNT = 200;
851
+ var PAGE_SIZE = MAX_READ_COUNT;
852
+ var appendPaging = (p, count, start) => {
853
+ if (count !== void 0) {
854
+ if (!Number.isInteger(count) || count < MIN_READ_COUNT || count > MAX_READ_COUNT) {
855
+ throw new PortersConfigError(
856
+ `count must be an integer between ${MIN_READ_COUNT} and ${MAX_READ_COUNT}, got ${count}`,
857
+ {
858
+ category: "config",
859
+ hint: `PORTERS returns 1\u2013${MAX_READ_COUNT} records per Read. Use searchAll() to walk every page instead of raising count.`
860
+ }
861
+ );
862
+ }
863
+ p.set("count", String(count));
864
+ }
865
+ if (start !== void 0) p.set("start", String(start));
866
+ };
839
867
  var paginate = async function* (fetchPage) {
840
868
  let start = 0;
841
869
  for (; ; ) {
@@ -1032,8 +1060,7 @@ var buildReadUrl = (accessPoint, partition, path, q, ctx) => {
1032
1060
  p.set("partition", String(partition));
1033
1061
  if (q.field && q.field.length > 0) p.set("field", q.field.join(","));
1034
1062
  appendReadQuery(p, q, ctx);
1035
- if (q.count !== void 0) p.set("count", String(q.count));
1036
- if (q.start !== void 0) p.set("start", String(q.start));
1063
+ appendPaging(p, q.count, q.start);
1037
1064
  return apiUrl(accessPoint, path, p);
1038
1065
  };
1039
1066
  var buildWriteUrl = (accessPoint, partition, path) => apiUrl(
@@ -1053,6 +1080,7 @@ var createResource = (config, deps) => {
1053
1080
  const firstWriteId = (body) => firstWriteResultId(body, config.path, config.name);
1054
1081
  const search = async (query = {}) => runRead(
1055
1082
  deps.requester,
1083
+ config.name,
1056
1084
  readUrl({ ...query, field: query.field ?? defaultFields }),
1057
1085
  decode
1058
1086
  );
@@ -1110,15 +1138,19 @@ var FIELDS = {
1110
1138
  P_UpdatedBy: "User",
1111
1139
  P_Phase: "Option",
1112
1140
  P_PhaseDate: "DateTime",
1141
+ P_PhaseMemo: "MultilineText",
1113
1142
  P_Name: "SinglelineText",
1114
1143
  P_Reading: "SinglelineText",
1144
+ P_Memo: "MultilineText",
1115
1145
  P_Mail: "Mail",
1116
1146
  P_MobileMail: "Mail",
1117
1147
  P_Telephone: "Telephone",
1118
1148
  P_Mobile: "Telephone",
1149
+ P_Fax: "Telephone",
1119
1150
  P_Country: "SinglelineText",
1120
1151
  P_Prefecture: "SinglelineText",
1121
1152
  P_City: "SinglelineText",
1153
+ P_Street: "MultilineText",
1122
1154
  P_Zipcode: "SinglelineText"
1123
1155
  };
1124
1156
  var REQUIRED_ON_CREATE = [
@@ -1329,6 +1361,7 @@ var createResumeResource = (deps, custom) => {
1329
1361
 
1330
1362
  // src/resources/attachment.ts
1331
1363
  var MAX_CONTENT_CHARS = 14e6;
1364
+ var ATTACHMENT_RESOURCE = "Attachment";
1332
1365
  var ATTACHMENT_FIELD_NAMES = [
1333
1366
  "Id",
1334
1367
  "Resource",
@@ -1352,8 +1385,7 @@ var buildAttachmentReadUrl = (accessPoint, partition, q) => {
1352
1385
  const conds = Object.entries(q.condition).map(([k, v]) => `${k}=${v}`);
1353
1386
  if (conds.length > 0) p.set("condition", conds.join(","));
1354
1387
  }
1355
- if (q.count !== void 0) p.set("count", String(q.count));
1356
- if (q.start !== void 0) p.set("start", String(q.start));
1388
+ appendPaging(p, q.count, q.start);
1357
1389
  return apiUrl(accessPoint, "attachment", p);
1358
1390
  };
1359
1391
  var numOrNull = (v) => {
@@ -1388,7 +1420,7 @@ var createAttachmentResource = (deps) => {
1388
1420
  headers: {}
1389
1421
  },
1390
1422
  (body) => {
1391
- const page = parseResourcePage(body);
1423
+ const page = parseResourcePage(body, ATTACHMENT_RESOURCE);
1392
1424
  return {
1393
1425
  items: page.items.map(decodeAttachment),
1394
1426
  total: page.total,
@@ -1412,7 +1444,7 @@ var createAttachmentResource = (deps) => {
1412
1444
  headers: {},
1413
1445
  body: `<Attachment><Item>${inner}</Item></Attachment>`
1414
1446
  },
1415
- (body) => firstWriteResultId(body, "attachment", "Attachment"),
1447
+ (body) => firstWriteResultId(body, "attachment", ATTACHMENT_RESOURCE),
1416
1448
  { write: true, idempotent, unboundedBody: true }
1417
1449
  );
1418
1450
  const create = async (input) => {
@@ -1439,16 +1471,26 @@ var FIELDS6 = {
1439
1471
  P_Name: "SinglelineText",
1440
1472
  P_CompanyId: "SinglelineText"
1441
1473
  };
1474
+ var PARTITION_DESCRIPTOR = {
1475
+ name: "Partition",
1476
+ path: "partition",
1477
+ prefix: "Partition",
1478
+ fields: FIELDS6
1479
+ };
1442
1480
  var buildUrl = (accessPoint, q) => {
1443
1481
  const p = new URLSearchParams();
1444
1482
  p.set("request_type", String(q.requestType ?? 1));
1445
- if (q.count !== void 0) p.set("count", String(q.count));
1446
- if (q.start !== void 0) p.set("start", String(q.start));
1483
+ appendPaging(p, q.count, q.start);
1447
1484
  return apiUrl(accessPoint, "partition", p);
1448
1485
  };
1449
1486
  var createPartitionResource = (deps) => {
1450
1487
  const decode = decoderFor(FIELDS6);
1451
- const search = async (query = {}) => runRead(deps.requester, buildUrl(deps.accessPoint, query), decode);
1488
+ const search = async (query = {}) => runRead(
1489
+ deps.requester,
1490
+ PARTITION_DESCRIPTOR.name,
1491
+ buildUrl(deps.accessPoint, query),
1492
+ decode
1493
+ );
1452
1494
  const searchAll = (query = {}) => paginate((count, start) => search({ ...query, count, start }));
1453
1495
  return { search, searchAll };
1454
1496
  };
@@ -1460,20 +1502,26 @@ var FIELDS7 = {
1460
1502
  P_Name: "SinglelineText",
1461
1503
  P_Mail: "Mail"
1462
1504
  };
1505
+ var USER_DESCRIPTOR = {
1506
+ name: "User",
1507
+ path: "user",
1508
+ prefix: "User",
1509
+ fields: FIELDS7
1510
+ };
1463
1511
  var buildUrl2 = (accessPoint, partition, q) => {
1464
1512
  const p = new URLSearchParams();
1465
1513
  p.set("partition", String(partition));
1466
1514
  p.set("request_type", String(q.requestType ?? 1));
1467
1515
  p.set("user_type", String(q.userType ?? -1));
1468
1516
  if (q.field && q.field.length > 0) p.set("field", q.field.join(","));
1469
- if (q.count !== void 0) p.set("count", String(q.count));
1470
- if (q.start !== void 0) p.set("start", String(q.start));
1517
+ appendPaging(p, q.count, q.start);
1471
1518
  return apiUrl(accessPoint, "user", p);
1472
1519
  };
1473
1520
  var createUserResource = (deps) => {
1474
1521
  const decode = decoderFor(FIELDS7);
1475
1522
  const search = async (query = {}) => runRead(
1476
1523
  deps.requester,
1524
+ USER_DESCRIPTOR.name,
1477
1525
  buildUrl2(deps.accessPoint, deps.partition, query),
1478
1526
  decode
1479
1527
  );
@@ -1510,19 +1558,25 @@ var FIELDS8 = {
1510
1558
  P_ReferTo: "Option",
1511
1559
  P_ResourceType: "Number"
1512
1560
  };
1561
+ var FIELD_DESCRIPTOR = {
1562
+ name: "Field",
1563
+ path: "field",
1564
+ prefix: "Field",
1565
+ fields: FIELDS8
1566
+ };
1513
1567
  var buildUrl3 = (accessPoint, partition, q) => {
1514
1568
  const p = new URLSearchParams();
1515
1569
  p.set("partition", String(partition));
1516
1570
  p.set("resource", String(RESOURCE_VALUE[q.resource]));
1517
1571
  p.set("active", String(q.active ?? -1));
1518
- if (q.count !== void 0) p.set("count", String(q.count));
1519
- if (q.start !== void 0) p.set("start", String(q.start));
1572
+ appendPaging(p, q.count, q.start);
1520
1573
  return apiUrl(accessPoint, "field", p);
1521
1574
  };
1522
1575
  var createFieldResource = (deps) => {
1523
1576
  const decode = decoderFor(FIELDS8);
1524
1577
  const search = async (query) => runRead(
1525
1578
  deps.requester,
1579
+ FIELD_DESCRIPTOR.name,
1526
1580
  buildUrl3(deps.accessPoint, deps.partition, query),
1527
1581
  decode
1528
1582
  );
@@ -1539,13 +1593,19 @@ var FIELDS9 = {
1539
1593
  P_Type: "Number",
1540
1594
  P_Order: "Number"
1541
1595
  };
1596
+ var OPTION_DESCRIPTOR = {
1597
+ name: "Option",
1598
+ path: "option",
1599
+ prefix: "Option",
1600
+ fields: FIELDS9
1601
+ };
1542
1602
  var buildUrl4 = (accessPoint, partition, q) => {
1543
1603
  const p = new URLSearchParams();
1544
1604
  p.set("partition", String(partition));
1545
1605
  if (q.alias !== void 0) p.set("alias", q.alias);
1546
1606
  if (q.level !== void 0) p.set("level", String(q.level));
1547
1607
  if (q.enabled !== void 0) p.set("enabled", String(q.enabled));
1548
- if (q.count !== void 0) p.set("count", String(q.count));
1608
+ appendPaging(p, q.count);
1549
1609
  return apiUrl(accessPoint, "option", p);
1550
1610
  };
1551
1611
  var withoutItems = (raw) => Object.fromEntries(Object.entries(raw).filter(([k]) => k !== "Items"));
@@ -1568,7 +1628,7 @@ var createOptionResource = (deps) => {
1568
1628
  },
1569
1629
  (body) => {
1570
1630
  const out = [];
1571
- flatten(parseResourcePage(body).items, out);
1631
+ flatten(parseResourcePage(body, OPTION_DESCRIPTOR.name).items, out);
1572
1632
  return out;
1573
1633
  }
1574
1634
  );