@joymerrevent/porters-connect 0.17.0 → 0.18.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 +140 -1
- package/README.md +1 -1
- package/dist/index.d.ts +139 -49
- package/dist/index.js +161 -144
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,140 @@
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.18.0] - 2026-09-17
|
|
9
|
+
|
|
10
|
+
**「どのリソースか」の受け取り方を 1 つの規則に揃えた版**です。**破壊的変更を 4 つ**含みます
|
|
11
|
+
(アクセスポイントの `host` 廃止/束ねた項目は書き込み入力から外れる/Field マスタの Read が
|
|
12
|
+
`of()` 経由に/添付の Read が PORTERS の語彙に)。
|
|
13
|
+
|
|
14
|
+
PORTERS が `resource=` を **URL パラメータで必須**に要求するエンドポイントは 3 つ(Field / Phase /
|
|
15
|
+
Attachment)あるのに、受け口の形が 3 つとも違っていました。**パラメータのリソースは `of(name)` で
|
|
16
|
+
束ね、項目の値は宣言した Data Type どおり(数値)**という線を引き、3 本とも `of()` に揃えています。
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`resourceValueOf` / `resourceNameOf`** — リソース名と数値を相互変換します([ADR-0079][adr79])。
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import {
|
|
24
|
+
resourceNameOf,
|
|
25
|
+
resourceValueOf,
|
|
26
|
+
} from "@joymerrevent/porters-connect";
|
|
27
|
+
|
|
28
|
+
await t.activity.create({
|
|
29
|
+
P_Owner: 5,
|
|
30
|
+
P_Title: "一次面談",
|
|
31
|
+
P_Resource: resourceValueOf("candidate"), // 1
|
|
32
|
+
P_ResourceId: 10001,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
resourceNameOf(17); // "resume"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
PORTERS のリソース番号は**非連続**です(Candidate `1` / Job `3` / Client `5` / Recruiter `9` /
|
|
39
|
+
Sales `11` / …)。欠番も取り違えも数値リテラルでは気づけないので、名前から引いてください。
|
|
40
|
+
`resourceNameOf` は**知らない数値をそのまま返します**(`ResourceName | number`)— Resource List は
|
|
41
|
+
PORTERS のもので増えるため(Contact `27` は後から増えました)、知らない値はエラーにせず
|
|
42
|
+
データとして通します。
|
|
43
|
+
|
|
44
|
+
- 公開した型: `AttachmentAccessor` / `FieldAccessor`(`ResourceName` は 0.17.0 から公開済みで、
|
|
45
|
+
`of()` に渡す名前の型です)。
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- **(破壊的)アクセスポイントが `hostname` と `port` に分かれました**([ADR-0078][adr78])。
|
|
50
|
+
**`host` は無くなります。**
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// これまで
|
|
54
|
+
new PortersClient({ host: "xxxxx.example.com", appId, appSecret });
|
|
55
|
+
new PortersClient({ host: "127.0.0.1:4010", scheme: "http" });
|
|
56
|
+
|
|
57
|
+
// これから
|
|
58
|
+
new PortersClient({ hostname: "xxxxx.example.com", appId, appSecret });
|
|
59
|
+
new PortersClient({ hostname: "127.0.0.1", port: 4010, scheme: "http" });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**契約で渡される値にポートは無い**からです。PORTERS の記事は `{Request Host}` を「該当の
|
|
63
|
+
**サーバー名**を入れてください」と説明し、ポート表記はどの記事にも出てきません。一方 URL 仕様では
|
|
64
|
+
`host` は**ポートを含む**名前で、含まないのが `hostname` です。名前と中身を揃えました。
|
|
65
|
+
|
|
66
|
+
- **`hostname` にポートを書くと構築時に落ちます**(`PortersConfigError`)。素通しすると
|
|
67
|
+
「指定したつもりで既定ポートに送られる」ので、黙って落とさずに弾きます
|
|
68
|
+
- **`port` は 1〜65535 の整数**。省略すれば scheme の既定ポートです。使うのはローカルの
|
|
69
|
+
フェイクサーバーやプロキシに向けるときだけで、PORTERS には要りません
|
|
70
|
+
- **IPv6 は角括弧付き**で渡します(`hostname: "[::1]"`)
|
|
71
|
+
- `PortersClient` のゲッターも `host` → **`hostname` / `port`** の 2 本になります
|
|
72
|
+
- スロットルのバケット([ADR-0073][adr73])は**宛先ごと**になりました。同じ名前でもポートが
|
|
73
|
+
違えば別のバケットです
|
|
74
|
+
|
|
75
|
+
- **(破壊的)添付ファイルの Read が PORTERS の語彙に揃いました**([ADR-0081][adr81])。
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// これまで
|
|
79
|
+
await t.attachment.search({ condition: { "ResourceId:eq": "10001" } });
|
|
80
|
+
await t.attachment.create({ resource: 17, resourceId: 10001, ...file });
|
|
81
|
+
|
|
82
|
+
// これから
|
|
83
|
+
const files = t.attachment.of("resume"); // resource を 1 回束ねる
|
|
84
|
+
await files.search({ resourceId: 10001 });
|
|
85
|
+
await files.get(900);
|
|
86
|
+
await files.create({ resourceId: 10001, ...file }); // resource は束ねた値
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
PORTERS の `Attachment - Read` が取るのは `requestType` / `resource` / `resourceId` / `id` で、
|
|
90
|
+
**`field` と `condition` は挙げられていません**。ライブラリは逆で、**必須の 2 つを送らず、
|
|
91
|
+
記載の無い 2 つを送っていました**。出典どおりなら添付の読み取りは実環境で常に失敗するので、
|
|
92
|
+
出典に一致する側へ倒しました。
|
|
93
|
+
|
|
94
|
+
- `create` の入力から **`resource` が消えました**。付け先を取り違えても添付は消せないので、
|
|
95
|
+
書ける場所を減らしています
|
|
96
|
+
- 本体(`content`)を運ぶかは引き続き**メソッドが決めます**(`get` だけが運びます。
|
|
97
|
+
PORTERS 側では `requestType` です)
|
|
98
|
+
- **絞れるのは `resourceId`(1 レコードの添付)と `id`(1 件)だけ**で、ファイル名などでの
|
|
99
|
+
検索はできません(PORTERS が提供していません)。名前で探すときは `searchAll` で歩きながら
|
|
100
|
+
絞ってください
|
|
101
|
+
- **出典どおりの形が実機で通るかは未確認**です(契約環境でのみ確かめられます)
|
|
102
|
+
|
|
103
|
+
- **(破壊的)Field マスタの Read が `of()` でリソースを束ねる形になりました**([ADR-0080][adr80])。
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// これまで
|
|
107
|
+
await t.field.search({ resource: "candidate", active: 1 });
|
|
108
|
+
|
|
109
|
+
// これから
|
|
110
|
+
await t.field.of("candidate").search({ active: 1 });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
同じ形の Phase は以前から `t.phase.of("client")` で束ねていたので、**URL パラメータのリソースは
|
|
114
|
+
`of()` で束ねる**という 1 つの規則に揃えました。`readCustomCatalog` / `verifyFields` /
|
|
115
|
+
`generateFieldDecls` の**引数は変わりません**。`porters.partition` / `t.user` / `t.option` も
|
|
116
|
+
変わりません — この 3 つは `resource=` を取らないためです。
|
|
117
|
+
|
|
118
|
+
- **(破壊的)アクセサが束ねた項目は、書き込み入力から外れます**。
|
|
119
|
+
|
|
120
|
+
`t.phase.of("client")` は「このアクセサは企業の Phase を扱う」という宣言です。これまでは
|
|
121
|
+
`Resource` を書き込み入力に渡せてしまい、**束ねた値を上書きできました** — `of("client")` から
|
|
122
|
+
JOB(`3`)の Phase が書ける状態でした。
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const phase = (await t.phase.of("client").get(10014))!;
|
|
126
|
+
await t.phase.of("client").create({ ...phase, Date: "2026-09-17T00:00:00Z" });
|
|
127
|
+
// 読みのレコードは `Resource` を持つため、これまでは束ねた値が黙って上書きされていました
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
型で外したうえ、キャストで渡した場合も**送信前に** `PortersConfigError` で止めます(黙って
|
|
131
|
+
捨てません)。Phase に削除 API は無いので、間違ったリソースに付いた履歴は消せません。
|
|
132
|
+
|
|
133
|
+
- **エンドポイント × 機能のマトリクスのずれが無くなりました**。0.17.0 で起こした表は
|
|
134
|
+
**4 セルが食い違った状態**で出しましたが(Phase の 2 つ・Attachment の 2 つ)、本版で
|
|
135
|
+
**すべて解消**しています。パッケージの中身は変わりません。
|
|
136
|
+
|
|
137
|
+
### Removed
|
|
138
|
+
|
|
139
|
+
- **`AttachmentMetaField`** — 0.17.0 で公開した型ですが、添付の Read から `field` が無くなった
|
|
140
|
+
ため役目を終えました([ADR-0081][adr81])。
|
|
141
|
+
|
|
8
142
|
## [0.17.0] - 2026-09-16
|
|
9
143
|
|
|
10
144
|
**添付ファイルの運び方を決め、出典に無いパラメータを型から外した版**です。**破壊的変更を 2 つ**
|
|
@@ -887,13 +1021,18 @@
|
|
|
887
1021
|
[adr75]: docs/adr/0075-attachment-search-all.md
|
|
888
1022
|
[adr76]: docs/adr/0076-phase-read-query-surface.md
|
|
889
1023
|
[adr77]: docs/adr/0077-fetch-transport-timeout.md
|
|
1024
|
+
[adr78]: docs/adr/0078-hostname-port-split.md
|
|
1025
|
+
[adr79]: docs/adr/0079-resource-by-name.md
|
|
1026
|
+
[adr80]: docs/adr/0080-resource-parameter-binding.md
|
|
1027
|
+
[adr81]: docs/adr/0081-attachment-read-parameters.md
|
|
890
1028
|
[limits]: docs/usage/concepts/limits.md
|
|
891
1029
|
[failures]: docs/usage/howto/handle-failures.md
|
|
892
1030
|
[lv]: docs/live-verification.md
|
|
893
1031
|
[ref]: docs/usage/reference/README.md
|
|
894
1032
|
[kac]: https://keepachangelog.com/en/1.1.0/
|
|
895
1033
|
[semver]: https://semver.org/
|
|
896
|
-
[unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.
|
|
1034
|
+
[unreleased]: https://github.com/Joymerrevent/porters-connect/compare/v0.18.0...HEAD
|
|
1035
|
+
[0.18.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.17.0...v0.18.0
|
|
897
1036
|
[0.17.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.16.0...v0.17.0
|
|
898
1037
|
[0.16.0]: https://github.com/Joymerrevent/porters-connect/compare/v0.15.1...v0.16.0
|
|
899
1038
|
[0.15.1]: https://github.com/Joymerrevent/porters-connect/compare/v0.15.0...v0.15.1
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ npm i @joymerrevent/porters-connect
|
|
|
54
54
|
import { PortersClient } from "@joymerrevent/porters-connect";
|
|
55
55
|
|
|
56
56
|
const porters = new PortersClient({
|
|
57
|
-
|
|
57
|
+
hostname: process.env.PORTERS_HOST ?? "", // 契約時に通知される値。ハードコード禁止
|
|
58
58
|
appId: process.env.PORTERS_APP_ID ?? "",
|
|
59
59
|
appSecret: process.env.PORTERS_APP_SECRET ?? "",
|
|
60
60
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -659,16 +659,18 @@ type UpdateInput<F extends FieldCatalog> = {
|
|
|
659
659
|
*/
|
|
660
660
|
type EmptyImages = Record<never, never>;
|
|
661
661
|
/**
|
|
662
|
-
*
|
|
662
|
+
* An object with `K` taken out — and **kept out**. `Omit` alone only stops a fresh object literal
|
|
663
663
|
* (excess-property checking); a variable that happens to carry the key still assigns. Re-declaring
|
|
664
|
-
* each removed key as `?: never` closes that hole, so
|
|
665
|
-
*
|
|
664
|
+
* each removed key as `?: never` closes that hole, so the call fails whichever way the object was
|
|
665
|
+
* built — including `create({ ...recordFromRead })`, which is how the binding actually gets
|
|
666
|
+
* contradicted in practice (RV-47).
|
|
666
667
|
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
668
|
+
* Used for two different exclusions: query keys the endpoint does not take (`Unsupported` —
|
|
669
|
+
* ADR-0076) and write aliases the accessor itself fills (`Bound` — ADR-0061 / ADR-0080).
|
|
670
|
+
* `searchAll` keeps a plain `Omit` for `count` / `start`: those are not "PORTERS does not take
|
|
671
|
+
* this", they are "the walk decides them", and tightening that is a different decision.
|
|
670
672
|
*/
|
|
671
|
-
type
|
|
673
|
+
type Without<T, K extends keyof T> = Omit<T, K> & {
|
|
672
674
|
[P in K]?: never;
|
|
673
675
|
};
|
|
674
676
|
type Resource<F extends FieldCatalog, Req extends keyof F, R extends ReferenceMap = EmptyReferences,
|
|
@@ -683,13 +685,20 @@ type Resource<F extends FieldCatalog, Req extends keyof F, R extends ReferenceMa
|
|
|
683
685
|
* forced in through a cast is still sent, which is how a live contract can test whether
|
|
684
686
|
* PORTERS accepts it at all.
|
|
685
687
|
*/
|
|
686
|
-
Unsupported extends keyof SearchQuery<F, R> = never
|
|
687
|
-
|
|
688
|
+
Unsupported extends keyof SearchQuery<F, R> = never,
|
|
689
|
+
/**
|
|
690
|
+
* Write aliases **the accessor itself fills**, so a caller cannot supply them (ADR-0061 / RV-47).
|
|
691
|
+
* `t.phase.of("client")` binds `Resource`; passing it again could only mean contradicting the
|
|
692
|
+
* binding, and a phase written to the wrong resource cannot be deleted (there is no delete API).
|
|
693
|
+
* `never` — the default — means the caller supplies every writable field.
|
|
694
|
+
*/
|
|
695
|
+
Bound extends WritableKeys<F> = never> = {
|
|
696
|
+
search<const E extends Expand<R> = EmptyReferences, const I extends ImageOption<F> = EmptyImages>(query?: Without<SearchQuery<F, R>, Unsupported> & {
|
|
688
697
|
expand?: E;
|
|
689
698
|
image?: I;
|
|
690
699
|
}): Promise<ResourcePageOf<ImageReadRecord<ExpandedReadRecord<F, R, E>, I>>>;
|
|
691
700
|
/** Auto-paginating search: yields every matching record (200 per page). */
|
|
692
|
-
searchAll<const E extends Expand<R> = EmptyReferences, const I extends ImageOption<F> = EmptyImages>(query?: Omit<
|
|
701
|
+
searchAll<const E extends Expand<R> = EmptyReferences, const I extends ImageOption<F> = EmptyImages>(query?: Omit<Without<SearchQuery<F, R>, Unsupported>, "count" | "start"> & {
|
|
693
702
|
expand?: E;
|
|
694
703
|
image?: I;
|
|
695
704
|
}): AsyncIterable<ImageReadRecord<ExpandedReadRecord<F, R, E>, I>>;
|
|
@@ -703,9 +712,9 @@ Unsupported extends keyof SearchQuery<F, R> = never> = {
|
|
|
703
712
|
image?: I;
|
|
704
713
|
}): Promise<ImageReadRecord<ExpandedReadRecord<F, R, E>, I> | undefined>;
|
|
705
714
|
/** Create one record; resolves to the newly assigned id. */
|
|
706
|
-
create(input: CreateInput<F, Req
|
|
715
|
+
create(input: Without<CreateInput<F, Req>, Extract<Bound, keyof CreateInput<F, Req>>>): Promise<number>;
|
|
707
716
|
/** Update one record by id; resolves to that id. */
|
|
708
|
-
update(id: number, input: UpdateInput<F
|
|
717
|
+
update(id: number, input: Without<UpdateInput<F>, Extract<Bound, keyof UpdateInput<F>>>): Promise<number>;
|
|
709
718
|
/**
|
|
710
719
|
* Create many records in one call (ADR-0041 / F-4). Auto-batched to ≤200 records and under the
|
|
711
720
|
* request size cap. **Not atomic** — inspect the {@link BulkWriteResult}: per-record failures are
|
|
@@ -713,14 +722,14 @@ Unsupported extends keyof SearchQuery<F, R> = never> = {
|
|
|
713
722
|
* already-written count). Batching is non-idempotent: a full retry after a mid-run failure may
|
|
714
723
|
* duplicate creates. Empty input sends no request.
|
|
715
724
|
*/
|
|
716
|
-
createMany(inputs: CreateInput<F, Req
|
|
725
|
+
createMany(inputs: Without<CreateInput<F, Req>, Extract<Bound, keyof CreateInput<F, Req>>>[]): Promise<BulkWriteResult>;
|
|
717
726
|
/**
|
|
718
727
|
* Update many records by id in one call (ADR-0041 / F-4). Auto-batched like {@link createMany};
|
|
719
728
|
* per-record failures are returned in the {@link BulkWriteResult}, not thrown.
|
|
720
729
|
*/
|
|
721
730
|
updateMany(items: {
|
|
722
731
|
id: number;
|
|
723
|
-
fields: UpdateInput<F
|
|
732
|
+
fields: Without<UpdateInput<F>, Extract<Bound, keyof UpdateInput<F>>>;
|
|
724
733
|
}[]): Promise<BulkWriteResult>;
|
|
725
734
|
};
|
|
726
735
|
|
|
@@ -1755,6 +1764,37 @@ declare const RESOURCE_VALUES: {
|
|
|
1755
1764
|
* the accessor (`t.client` -> `"client"`), so a typo is a compile error rather than an HTTP 400.
|
|
1756
1765
|
*/
|
|
1757
1766
|
type ResourceName = keyof typeof RESOURCE_VALUES;
|
|
1767
|
+
/**
|
|
1768
|
+
* The number PORTERS knows a resource by (ADR-0079). The library takes **names** where PORTERS
|
|
1769
|
+
* takes a `resource=` parameter, but a *field value* stays the number its Data Type declares —
|
|
1770
|
+
* `Activity.P_Resource`, `Attachment.Resource`, and a `condition` on either.
|
|
1771
|
+
*
|
|
1772
|
+
* Write the name and let this do the lookup; the numbers are non-contiguous
|
|
1773
|
+
* (1/3/5/7/9/11/13/17/19/25/27), so a literal is easy to get wrong and impossible to spot.
|
|
1774
|
+
*
|
|
1775
|
+
* @example
|
|
1776
|
+
* await t.activity.create({
|
|
1777
|
+
* P_Owner: 5,
|
|
1778
|
+
* P_Title: "面談",
|
|
1779
|
+
* P_Resource: resourceValueOf("candidate"), // 1
|
|
1780
|
+
* P_ResourceId: 10001,
|
|
1781
|
+
* });
|
|
1782
|
+
*/
|
|
1783
|
+
declare const resourceValueOf: (name: ResourceName) => number;
|
|
1784
|
+
/**
|
|
1785
|
+
* The name for a resource number (ADR-0079) — the other direction of {@link resourceValueOf}.
|
|
1786
|
+
* Use it to read a value PORTERS returned: `Activity.P_Resource`, `Field.P_ResourceType`, or a
|
|
1787
|
+
* raw value from {@link rawValue}.
|
|
1788
|
+
*
|
|
1789
|
+
* **A number PORTERS added since this version comes back as the number**, not `undefined` and not
|
|
1790
|
+
* an error. The Resource List belongs to PORTERS and grows (Contact `27` arrived that way), so a
|
|
1791
|
+
* value this library does not know is data, not a fault.
|
|
1792
|
+
*
|
|
1793
|
+
* @example
|
|
1794
|
+
* const a = await t.activity.get(1);
|
|
1795
|
+
* resourceNameOf(a?.P_Resource ?? 0); // "candidate" | … | number
|
|
1796
|
+
*/
|
|
1797
|
+
declare const resourceNameOf: (value: number) => ResourceName | number;
|
|
1758
1798
|
|
|
1759
1799
|
declare const FIELDS$6: {
|
|
1760
1800
|
readonly Id: "System[Id]";
|
|
@@ -1793,9 +1833,11 @@ type PhaseCreateInput = CreateInput<typeof FIELDS$6, (typeof REQUIRED_ON_CREATE$
|
|
|
1793
1833
|
type PhaseUpdateInput = UpdateInput<typeof FIELDS$6>;
|
|
1794
1834
|
/**
|
|
1795
1835
|
* The Phase accessor for one bound resource — the same shape as every other resource, except that
|
|
1796
|
-
* `search` / `searchAll` do not take `keywords` / `itemstate` (ADR-0076)
|
|
1836
|
+
* `search` / `searchAll` do not take `keywords` / `itemstate` (ADR-0076) and the write inputs do
|
|
1837
|
+
* not take `Resource`: `of()` binds it, and supplying it again could only contradict the binding
|
|
1838
|
+
* (RV-47).
|
|
1797
1839
|
*/
|
|
1798
|
-
type PhaseResource = Resource<typeof FIELDS$6, (typeof REQUIRED_ON_CREATE$2)[number], EmptyReferences, PhaseUnsupportedQuery>;
|
|
1840
|
+
type PhaseResource = Resource<typeof FIELDS$6, (typeof REQUIRED_ON_CREATE$2)[number], EmptyReferences, PhaseUnsupportedQuery, "Resource">;
|
|
1799
1841
|
/**
|
|
1800
1842
|
* Phase is reached through the resource whose history you want (ADR-0061 案2a):
|
|
1801
1843
|
*
|
|
@@ -2243,11 +2285,6 @@ type ResumeUpdateInput = UpdateInput<typeof FIELDS$4>;
|
|
|
2243
2285
|
/** The Resume accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */
|
|
2244
2286
|
type ResumeResource<C extends FieldCatalog = EmptyCatalog> = Resource<typeof FIELDS$4 & C, (typeof REQUIRED_ON_CREATE)[number], typeof REFERENCES>;
|
|
2245
2287
|
|
|
2246
|
-
/**
|
|
2247
|
-
* Every Attachment field **except** the body: what a listing may ask for (ADR-0075).
|
|
2248
|
-
* These are the aliases `search` / `searchAll` accept.
|
|
2249
|
-
*/
|
|
2250
|
-
type AttachmentMetaField = "Id" | "Resource" | "ResourceId" | "ContentType" | "FileName";
|
|
2251
2288
|
/** A decoded Attachment. A field is `null` unless it was returned (see `field`). */
|
|
2252
2289
|
type Attachment = {
|
|
2253
2290
|
id: number | null;
|
|
@@ -2268,22 +2305,22 @@ type AttachmentPage = {
|
|
|
2268
2305
|
};
|
|
2269
2306
|
type AttachmentSearchQuery = {
|
|
2270
2307
|
/**
|
|
2271
|
-
*
|
|
2272
|
-
*
|
|
2273
|
-
*
|
|
2274
|
-
* The file body is **not** on this list: a listing never carries it, whatever the count
|
|
2275
|
-
* (ADR-0075). Read a body with {@link AttachmentResource.get}, one record at a time.
|
|
2308
|
+
* Narrow to one record's attachments — the id **within the bound resource**
|
|
2309
|
+
* (`t.attachment.of("resume")` -> a `Resume.P_Id`). Omit to read the whole resource's
|
|
2310
|
+
* attachments.
|
|
2276
2311
|
*/
|
|
2277
|
-
|
|
2278
|
-
condition?: Record<string, string>;
|
|
2312
|
+
resourceId?: number;
|
|
2279
2313
|
count?: number;
|
|
2280
2314
|
start?: number;
|
|
2281
2315
|
};
|
|
2282
2316
|
/** A walking Read: `count` / `start` are the walk's to decide. */
|
|
2283
2317
|
type AttachmentWalkQuery = Omit<AttachmentSearchQuery, "count" | "start">;
|
|
2284
|
-
/**
|
|
2318
|
+
/**
|
|
2319
|
+
* Fields for creating an Attachment. `content` is the Base64 file body; the resource it attaches
|
|
2320
|
+
* to comes from `of(name)` and cannot be given here (ADR-0080 / ADR-0081).
|
|
2321
|
+
*/
|
|
2285
2322
|
type AttachmentCreate = {
|
|
2286
|
-
resource
|
|
2323
|
+
/** The record's id within the bound resource. */
|
|
2287
2324
|
resourceId: number;
|
|
2288
2325
|
contentType: string;
|
|
2289
2326
|
fileName: string;
|
|
@@ -2295,6 +2332,21 @@ type AttachmentUpdate = {
|
|
|
2295
2332
|
fileName?: string;
|
|
2296
2333
|
content?: string;
|
|
2297
2334
|
};
|
|
2335
|
+
/**
|
|
2336
|
+
* Attachments are reached through the resource they belong to (ADR-0080 / ADR-0081):
|
|
2337
|
+
*
|
|
2338
|
+
* ```ts
|
|
2339
|
+
* const files = t.attachment.of("resume");
|
|
2340
|
+
* await files.search({ resourceId: 10006 }); // メタデータだけ
|
|
2341
|
+
* await files.get(900); // 本体つき
|
|
2342
|
+
* ```
|
|
2343
|
+
*
|
|
2344
|
+
* PORTERS requires `resource=` on every Attachment Read, and the same value goes into the
|
|
2345
|
+
* `<Resource>` field on write — one binding, both places, exactly like `t.phase.of(...)`.
|
|
2346
|
+
*/
|
|
2347
|
+
type AttachmentAccessor = {
|
|
2348
|
+
of(resource: ResourceName): AttachmentResource;
|
|
2349
|
+
};
|
|
2298
2350
|
type AttachmentResource = {
|
|
2299
2351
|
search(query?: AttachmentSearchQuery): Promise<AttachmentPage>;
|
|
2300
2352
|
/**
|
|
@@ -2409,18 +2461,33 @@ declare const FIELDS$1: {
|
|
|
2409
2461
|
/** A decoded Field definition. `P_Required`: 0 = normal, 1 = required. */
|
|
2410
2462
|
type Field = ReadRecord<typeof FIELDS$1>;
|
|
2411
2463
|
type FieldPage = ResourcePage<typeof FIELDS$1>;
|
|
2412
|
-
/** Field Read query.
|
|
2464
|
+
/** Field Read query. The resource itself is bound by `of(name)` (ADR-0080). */
|
|
2413
2465
|
type FieldSearchQuery = {
|
|
2414
|
-
resource: ResourceType;
|
|
2415
2466
|
/** -1 = all (default), 0 = unused only, 1 = in-use only. */
|
|
2416
2467
|
active?: -1 | 0 | 1;
|
|
2417
2468
|
count?: number;
|
|
2418
2469
|
start?: number;
|
|
2419
2470
|
};
|
|
2471
|
+
/** The Field accessor for one bound resource. */
|
|
2420
2472
|
type FieldResource = {
|
|
2421
|
-
search(query
|
|
2473
|
+
search(query?: FieldSearchQuery): Promise<FieldPage>;
|
|
2422
2474
|
/** Auto-paginating search: yields every field of the resource. */
|
|
2423
|
-
searchAll(query
|
|
2475
|
+
searchAll(query?: Omit<FieldSearchQuery, "count" | "start">): AsyncIterable<Field>;
|
|
2476
|
+
};
|
|
2477
|
+
/**
|
|
2478
|
+
* Field Read is reached through the resource whose catalog you want (ADR-0080):
|
|
2479
|
+
*
|
|
2480
|
+
* ```ts
|
|
2481
|
+
* const fields = t.field.of("candidate");
|
|
2482
|
+
* for await (const f of fields.searchAll({ active: 1 })) console.log(f.P_Alias);
|
|
2483
|
+
* ```
|
|
2484
|
+
*
|
|
2485
|
+
* The name is the accessor's own spelling ({@link ResourceName}) — `of(1)` and `of("candidat")`
|
|
2486
|
+
* are compile errors. PORTERS requires the `resource=` parameter on every Field Read, so binding
|
|
2487
|
+
* it once means it cannot be forgotten or contradicted.
|
|
2488
|
+
*/
|
|
2489
|
+
type FieldAccessor = {
|
|
2490
|
+
of(resource: ResourceType): FieldResource;
|
|
2424
2491
|
};
|
|
2425
2492
|
|
|
2426
2493
|
declare const FIELDS: {
|
|
@@ -2526,7 +2593,9 @@ declare const defineFields: <D extends FieldDecls>(decls: D) => DefinedFields<De
|
|
|
2526
2593
|
*/
|
|
2527
2594
|
type FieldCatalogSource = {
|
|
2528
2595
|
readonly field: {
|
|
2529
|
-
|
|
2596
|
+
of(resource: CustomFieldResource): {
|
|
2597
|
+
searchAll(query?: Omit<FieldSearchQuery, "count" | "start">): AsyncIterable<Field>;
|
|
2598
|
+
};
|
|
2530
2599
|
};
|
|
2531
2600
|
};
|
|
2532
2601
|
/** Why a tenant custom field cannot be expressed as a declaration (ADR-0069 論点4). */
|
|
@@ -2726,15 +2795,24 @@ declare const assertFieldsMatch: (report: FieldVerification) => void;
|
|
|
2726
2795
|
/** Options for constructing a {@link PortersClient}. `C` is inferred from `fields` (ADR-0023). */
|
|
2727
2796
|
type PortersClientOptions<C extends DeclaredCatalogs = EmptyCatalog> = {
|
|
2728
2797
|
/**
|
|
2729
|
-
* API
|
|
2730
|
-
* (A representative value lives in docs/usage/reference.)
|
|
2798
|
+
* API server name. Required and supplied via `PORTERS_HOST` — never hard-code it.
|
|
2799
|
+
* (A representative value lives in docs/usage/reference.)
|
|
2731
2800
|
*
|
|
2732
|
-
* The **
|
|
2733
|
-
*
|
|
2734
|
-
*
|
|
2735
|
-
*
|
|
2801
|
+
* The **name and nothing else**: no port, no scheme, no path, no userinfo, no whitespace
|
|
2802
|
+
* (ADR-0078). PORTERS issues a server name and speaks https, so a port never arrives with it;
|
|
2803
|
+
* when you need one (a local fake, a proxy) pass {@link PortersClientOptions.port}. A value
|
|
2804
|
+
* like `https://xxxxx.example.com` or `a.test:4010` is rejected at construction with a
|
|
2805
|
+
* {@link PortersConfigError} rather than silently addressing something else (ADR-0048).
|
|
2806
|
+
* Write a non-ASCII name in punycode; bracket an IPv6 address (`[::1]`).
|
|
2807
|
+
*/
|
|
2808
|
+
hostname: string;
|
|
2809
|
+
/**
|
|
2810
|
+
* Port of the access point (ADR-0078). **Omit it for PORTERS** — the contract gives you a name
|
|
2811
|
+
* and the scheme decides the port. Set it only for a local fake server or a proxy:
|
|
2812
|
+
* `{ hostname: "127.0.0.1", port: 4010, scheme: "http" }`. An integer 1–65535; anything else
|
|
2813
|
+
* is rejected at construction.
|
|
2736
2814
|
*/
|
|
2737
|
-
|
|
2815
|
+
port?: number;
|
|
2738
2816
|
/**
|
|
2739
2817
|
* URL scheme of the access point (ADR-0047). Defaults to `"https"`. Set `"http"` only for a
|
|
2740
2818
|
* local fake server or a trusted tunnel: it sends every request — the OAuth token header
|
|
@@ -2753,7 +2831,7 @@ type PortersClientOptions<C extends DeclaredCatalogs = EmptyCatalog> = {
|
|
|
2753
2831
|
/** Injectable HTTP transport; defaults to a fetch-based transport. */
|
|
2754
2832
|
transport?: Transport;
|
|
2755
2833
|
/**
|
|
2756
|
-
* Rate-limit self-restraint (ADR-0073). Defaults to the **process-wide bucket for this
|
|
2834
|
+
* Rate-limit self-restraint (ADR-0073). Defaults to the **process-wide bucket for this destination**,
|
|
2757
2835
|
* so several clients aimed at the same PORTERS add up to one limit instead of one each.
|
|
2758
2836
|
*
|
|
2759
2837
|
* Pass your own to opt out of that sharing, to run different limits, or to coordinate across
|
|
@@ -2792,9 +2870,19 @@ type TenantScope<C extends DeclaredCatalogs = EmptyCatalog> = {
|
|
|
2792
2870
|
readonly phase: PhaseAccessor;
|
|
2793
2871
|
readonly process: ProcessResource<CustomFor<C, "process">>;
|
|
2794
2872
|
readonly resume: ResumeResource<CustomFor<C, "resume">>;
|
|
2795
|
-
|
|
2873
|
+
/**
|
|
2874
|
+
* Attachments, reached through the resource they belong to: `t.attachment.of("resume")`.
|
|
2875
|
+
* PORTERS requires that `resource` on every Attachment Read, and the same value fills the
|
|
2876
|
+
* `<Resource>` field on write, so it is bound once (ADR-0080 / ADR-0081).
|
|
2877
|
+
*/
|
|
2878
|
+
readonly attachment: AttachmentAccessor;
|
|
2796
2879
|
readonly user: UserResource;
|
|
2797
|
-
|
|
2880
|
+
/**
|
|
2881
|
+
* Field master Read, reached through the resource whose catalog you want:
|
|
2882
|
+
* `t.field.of("candidate")`. PORTERS requires `resource=` on every Field Read, so it is bound
|
|
2883
|
+
* once (ADR-0080).
|
|
2884
|
+
*/
|
|
2885
|
+
readonly field: FieldAccessor;
|
|
2798
2886
|
readonly option: OptionResource;
|
|
2799
2887
|
};
|
|
2800
2888
|
/**
|
|
@@ -2806,7 +2894,7 @@ type TenantScope<C extends DeclaredCatalogs = EmptyCatalog> = {
|
|
|
2806
2894
|
* explicitly, exactly once, so "unbound" is not a state this API can be in.
|
|
2807
2895
|
*
|
|
2808
2896
|
* @example
|
|
2809
|
-
* const porters = new PortersClient({
|
|
2897
|
+
* const porters = new PortersClient({ hostname, appId, appSecret });
|
|
2810
2898
|
* await porters.auth.ensureAuthenticated(); // App-level
|
|
2811
2899
|
* const t = porters.tenant(123); // bind the partition once
|
|
2812
2900
|
* const page = await t.candidate.search();
|
|
@@ -2836,8 +2924,10 @@ declare class PortersClient<C extends DeclaredCatalogs = EmptyCatalog> {
|
|
|
2836
2924
|
*/
|
|
2837
2925
|
readonly tenant: (id: PartitionId) => TenantScope<C>;
|
|
2838
2926
|
constructor(options: PortersClientOptions<C>);
|
|
2839
|
-
/** The configured API
|
|
2840
|
-
get
|
|
2927
|
+
/** The configured API server name (no port — see {@link PortersClient.port}). */
|
|
2928
|
+
get hostname(): string;
|
|
2929
|
+
/** The configured port, or `undefined` when the scheme's own port is used (ADR-0078). */
|
|
2930
|
+
get port(): number | undefined;
|
|
2841
2931
|
}
|
|
2842
2932
|
|
|
2843
2933
|
/** Cross-cutting classification shared by every PORTERS error. */
|
|
@@ -2900,4 +2990,4 @@ declare const bytesToBase64: (bytes: Uint8Array) => string;
|
|
|
2900
2990
|
/** Decode a Base64 string back to raw bytes. */
|
|
2901
2991
|
declare const base64ToBytes: (b64: string) => Uint8Array;
|
|
2902
2992
|
|
|
2903
|
-
export { type Activity, type ActivityCreateInput, type ActivityPage, type ActivityResource, type ActivitySearchQuery, type ActivityUpdateInput, type Attachment, type
|
|
2993
|
+
export { type Activity, type ActivityCreateInput, type ActivityPage, type ActivityResource, type ActivitySearchQuery, type ActivityUpdateInput, type Attachment, type AttachmentAccessor, type AttachmentCreate, type AttachmentPage, type AttachmentResource, type AttachmentSearchQuery, type AttachmentUpdate, type AttachmentWalkQuery, type AuthApi, type AuthorizationUrlOptions, type BulkWriteResult, type BulkWriteResultItem, type Candidate, type CandidateCreateInput, type CandidatePage, type CandidateResource, type CandidateSearchQuery, type CandidateUpdateInput, type Client, type ClientCreateInput, type ClientPage, type ClientResource, type ClientSearchQuery, type ClientUpdateInput, type Condition, type Contact, type ContactCreateInput, type ContactPage, type ContactResource, type ContactSearchQuery, type ContactUpdateInput, type Contract, type ContractCreateInput, type ContractPage, type ContractResource, type ContractSearchQuery, type ContractUpdateInput, type CustomDataType, type CustomFieldResource, type CustomFor, type DeclaredCatalogs, type DefinedFields, type DepartmentRef, type ErrorCategory, type Expand, type ExpandedReadRecord, type FetchTransportOptions, type Field, type FieldAccessor, type FieldBuilder, type FieldCatalogSource, type FieldDecls, type FieldDef, type FieldPage, type FieldResource, type FieldSearchQuery, type FieldTypeMismatch, type FieldValue, type FieldVerification, type GenerateFieldDeclsOptions, type GetAccessTokenOptions, type ImageContentType, type ImageOption, type ImageReadRecord, type ImageSelectedValue, type ImageSubField, type ImageValue, type ImageWriteValue, type ItemState, type Job, type JobCreateInput, type JobPage, type JobResource, type JobSearchQuery, type JobUpdateInput, type LinkValue, type MissingField, type MockHandler, type MockReply, type MockTransportOptions, type Opportunity, type OpportunityCreateInput, type OpportunityPage, type OpportunityResource, type OpportunitySearchQuery, type OpportunityUpdateInput, type Option, type OptionResource, type OptionSearchQuery, type Order, type Partition, type PartitionId, type PartitionPage, type PartitionResource, type PartitionSearchQuery, type Phase, type PhaseAccessor, type PhaseCreateInput, type PhasePage, type PhaseResource, type PhaseSearchQuery, type PhaseUpdateInput, PortersAuthError, PortersClient, type PortersClientOptions, PortersConfigError, PortersError, type PortersErrorContext, type PortersErrorOptions, PortersNetworkError, PortersResourceError, type Process, type ProcessCreateInput, type ProcessPage, type ProcessResource, type ProcessSearchQuery, type ProcessUpdateInput, type ReadCustomCatalogOptions, type ReadFieldAlias, type Recruiter, type RecruiterCreateInput, type RecruiterPage, type RecruiterResource, type RecruiterSearchQuery, type RecruiterUpdateInput, type ReferenceMap, type ReferenceRecord, type ResourceName, type ResourcePageOf, type ResourceType, type Resume, type ResumeCreateInput, type ResumePage, type ResumeResource, type ResumeSearchQuery, type ResumeUpdateInput, type RevokeUrlOptions, type Sales, type SalesCreateInput, type SalesPage, type SalesResource, type SalesSearchQuery, type SalesUpdateInput, type Scheme, type Scope, type SearchQuery, type StoredTokens, type TenantCustomCatalog, type TenantScope, type Throttle, type ThrottleOptions, type TokenProvider, type TokenStore, type Transport, type TransportRequest, type TransportResponse, type UndeclarableField, type UndeclarableReason, type UndeclarableTenantField, type UndeclaredField, type UnverifiableResource, type User, type UserPage, type UserRef, type UserResource, type UserSearchQuery, type VerifyFieldsOptions, assertFieldsMatch, base64ToBytes, bytesToBase64, createFetchTransport, createMockTransport, createThrottle, defineFields, generateFieldDecls, rawValue, readCustomCatalog, resourceNameOf, resourceValueOf, verifyFields };
|