@joymerrevent/porters-connect 0.1.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.
@@ -0,0 +1,684 @@
1
+ /** Options for {@link TokenProvider.getAccessToken}. */
2
+ type GetAccessTokenOptions = {
3
+ /** Force a refresh even if the cached token looks valid (reactive 401/402). */
4
+ forceRefresh?: boolean;
5
+ };
6
+ /** Supplies a valid Access Token, refreshing transparently when expired. */
7
+ type TokenProvider = {
8
+ getAccessToken(opts?: GetAccessTokenOptions): Promise<string>;
9
+ };
10
+ /** Tokens persisted by a {@link TokenStore} (expiry is absolute epoch ms). */
11
+ type StoredTokens = {
12
+ accessToken: string;
13
+ refreshToken: string;
14
+ accessTokenExpiresAt: number;
15
+ refreshTokenExpiresAt: number;
16
+ };
17
+ /**
18
+ * Pluggable token persistence (default: in-memory). Async so it can back onto
19
+ * redis / DB / file for multi-instance server use.
20
+ */
21
+ type TokenStore = {
22
+ get(): Promise<StoredTokens | undefined>;
23
+ set(tokens: StoredTokens): Promise<void>;
24
+ clear(): Promise<void>;
25
+ };
26
+
27
+ /** A single HTTP request issued to the PORTERS API. */
28
+ type TransportRequest = {
29
+ method: "GET" | "POST";
30
+ url: string;
31
+ headers: Record<string, string>;
32
+ body?: string;
33
+ };
34
+ /** The raw HTTP response. Body stays as text; XML parsing happens in `xml/`. */
35
+ type TransportResponse = {
36
+ status: number;
37
+ body: string;
38
+ };
39
+ /** Sends a request and resolves the raw response. */
40
+ type Transport = {
41
+ send(request: TransportRequest): Promise<TransportResponse>;
42
+ };
43
+
44
+ /** A mock reply: an XML body string (HTTP 200), or an explicit status + body. */
45
+ type MockReply = string | {
46
+ status?: number;
47
+ body: string;
48
+ };
49
+ /**
50
+ * Maps a request to a {@link MockReply}, or returns `undefined` for "not mocked". When `undefined`
51
+ * is returned (and the request is not an auto-answered auth endpoint), the transport throws a
52
+ * {@link PortersConfigError} naming the request, so an unmocked route surfaces instead of silently
53
+ * returning an empty response.
54
+ */
55
+ type MockHandler = (request: TransportRequest) => MockReply | undefined;
56
+ /** Options for {@link createMockTransport}. */
57
+ type MockTransportOptions = {
58
+ /**
59
+ * Auto-answer the OAuth `code_direct` (`/v1/oauth`) and token (`/v1/token`) endpoints with valid
60
+ * demo tokens, so callers only mock resource XML. Default `true`. Set `false` to handle the auth
61
+ * endpoints in your own handler.
62
+ */
63
+ auth?: boolean;
64
+ };
65
+ /**
66
+ * Build a {@link Transport} that answers from a handler instead of the network — run the library
67
+ * fully offline, with no PORTERS contract (R-17). Pass it as `new PortersClient({ transport })`.
68
+ *
69
+ * @example
70
+ * const transport = createMockTransport((req) =>
71
+ * req.url.includes("/v1/candidate")
72
+ * ? `<Candidate Total="0" Count="0" Start="0"><Code>0</Code></Candidate>`
73
+ * : undefined, // unmocked -> a clear PortersConfigError
74
+ * );
75
+ */
76
+ declare const createMockTransport: (handler: MockHandler, options?: MockTransportOptions) => Transport;
77
+
78
+ type DataType = "System[Id]" | "Number" | "DateTime" | "System[DateTime]" | "Date" | "Age" | "SinglelineText" | "MultilineText" | "Mail" | "Telephone" | "URL" | "User" | "Option" | "System[Reference]";
79
+ /** A referenced User (Read is nested; Write is `User.P_Id` only). */
80
+ type UserRef = {
81
+ P_Id: number | null;
82
+ P_Type: string | null;
83
+ P_Name: string | null;
84
+ P_Mail: string | null;
85
+ };
86
+ type FieldValue = string | number | string[] | UserRef | null;
87
+ type DecodedValue<D extends DataType> = D extends "System[Id]" | "Number" | "System[Reference]" ? number : D extends "User" ? UserRef : D extends "Option" ? string[] : string;
88
+
89
+ type WritableDataType = Exclude<DataType, "System[Id]" | "System[DateTime]">;
90
+ type WriteValueOf<D extends DataType> = D extends "User" | "System[Reference]" | "Number" ? number : D extends "Option" ? string[] : string;
91
+
92
+ type FieldCatalog = Record<string, DataType>;
93
+ /**
94
+ * "No custom fields": the intersection-identity default for the generic catalog params (ADR-0023).
95
+ * A bare `{}` is flagged by `no-empty-object-type`; `Record<never, never>` is the same empty object,
96
+ * lint-clean, adds no keys in `static & C`, and satisfies both `FieldCatalog` and `DeclaredCatalogs`.
97
+ * Lives here (with `FieldCatalog`) so resources need not import from the higher-level `fields/` (RV-8).
98
+ */
99
+ type EmptyCatalog = Record<never, never>;
100
+ /**
101
+ * A decoded record: every known field, each `DecodedValue | null`, and **optional** because a
102
+ * field not named in `field` is simply absent (SD-3 "simple" type — ADR-0005/0019). Custom
103
+ * `U_`/`A_` aliases are not in the catalog, so they are not typed here (access via a cast until
104
+ * the declaration DSL lands — ADR-0005 SD-2); at runtime they still pass through as raw values.
105
+ */
106
+ type ReadRecord<F extends FieldCatalog> = {
107
+ [K in keyof F]?: DecodedValue<F[K]> | null;
108
+ };
109
+ type ResourcePage<F extends FieldCatalog> = {
110
+ items: ReadRecord<F>[];
111
+ total: number;
112
+ count: number;
113
+ start: number;
114
+ };
115
+
116
+ type SearchQuery = {
117
+ /**
118
+ * Output fields as prefixed aliases (e.g. `Person.P_Name`). **Omit** to fetch every catalogued
119
+ * field by default (ADR-0020): PORTERS returns only the primary key for a fieldless request, so
120
+ * the library sends a catalog-derived default field set instead. Pass `[]` to opt into that
121
+ * API-native "primary key only" response (e.g. counting). A non-empty list is sent verbatim.
122
+ */
123
+ field?: string[];
124
+ condition?: Record<string, string>;
125
+ count?: number;
126
+ start?: number;
127
+ };
128
+ type WritableKeys<F extends FieldCatalog> = {
129
+ [K in keyof F]: F[K] extends WritableDataType ? K : never;
130
+ }[keyof F];
131
+ /**
132
+ * Create input (ADR-0019 W2): the `requiredOnCreate` aliases are **required** (non-null); every
133
+ * other writable field is optional (`null` omits). `P_Id` is supplied by the library — not here.
134
+ */
135
+ type CreateInput<F extends FieldCatalog, Req extends keyof F> = {
136
+ [K in Req]: WriteValueOf<F[K]>;
137
+ } & {
138
+ [K in Exclude<WritableKeys<F>, Req>]?: WriteValueOf<F[K]> | null;
139
+ };
140
+ /** Update input (ADR-0019 W2): every writable field optional (`null` omits, `""` clears). */
141
+ type UpdateInput<F extends FieldCatalog> = {
142
+ [K in WritableKeys<F>]?: WriteValueOf<F[K]> | null;
143
+ };
144
+ type Resource<F extends FieldCatalog, Req extends keyof F> = {
145
+ search(query?: SearchQuery): Promise<ResourcePage<F>>;
146
+ /** Auto-paginating search: yields every matching record (200 per page). */
147
+ searchAll(query?: Omit<SearchQuery, "count" | "start">): AsyncIterable<ReadRecord<F>>;
148
+ get(id: number): Promise<ReadRecord<F> | undefined>;
149
+ /** Create one record; resolves to the newly assigned id. */
150
+ create(input: CreateInput<F, Req>): Promise<number>;
151
+ /** Update one record by id; resolves to that id. */
152
+ update(id: number, input: UpdateInput<F>): Promise<number>;
153
+ };
154
+
155
+ declare const FIELDS$8: {
156
+ readonly P_Id: "System[Id]";
157
+ readonly P_Owner: "User";
158
+ readonly P_RegistrationDate: "System[DateTime]";
159
+ readonly P_RegisteredBy: "User";
160
+ readonly P_UpdateDate: "System[DateTime]";
161
+ readonly P_UpdatedBy: "User";
162
+ readonly P_Phase: "Option";
163
+ readonly P_PhaseDate: "DateTime";
164
+ readonly P_Name: "SinglelineText";
165
+ readonly P_Reading: "SinglelineText";
166
+ readonly P_Mail: "Mail";
167
+ readonly P_MobileMail: "Mail";
168
+ readonly P_Telephone: "Telephone";
169
+ readonly P_Mobile: "Telephone";
170
+ readonly P_Country: "SinglelineText";
171
+ readonly P_Prefecture: "SinglelineText";
172
+ readonly P_City: "SinglelineText";
173
+ readonly P_Zipcode: "SinglelineText";
174
+ };
175
+ declare const REQUIRED_ON_CREATE$4: readonly ["P_Owner"];
176
+ /** A decoded Candidate: known `P_` fields, each requested field `value | null`. */
177
+ type Candidate = ReadRecord<typeof FIELDS$8>;
178
+ type CandidatePage = ResourcePage<typeof FIELDS$8>;
179
+ type CandidateSearchQuery = SearchQuery;
180
+ /** Fields for `create`: `P_Owner` is required; `P_Id` / system timestamps are not settable. */
181
+ type CandidateCreateInput = CreateInput<typeof FIELDS$8, (typeof REQUIRED_ON_CREATE$4)[number]>;
182
+ /** Fields for `update`: all optional (`null` omits, `""` clears a text field). */
183
+ type CandidateUpdateInput = UpdateInput<typeof FIELDS$8>;
184
+ /** The Candidate accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */
185
+ type CandidateResource<C extends FieldCatalog = EmptyCatalog> = Resource<typeof FIELDS$8 & C, (typeof REQUIRED_ON_CREATE$4)[number]>;
186
+
187
+ declare const FIELDS$7: {
188
+ readonly P_Id: "System[Id]";
189
+ readonly P_Owner: "User";
190
+ readonly P_Client: "System[Reference]";
191
+ readonly P_Recruiter: "System[Reference]";
192
+ readonly P_RegistrationDate: "System[DateTime]";
193
+ readonly P_RegisteredBy: "User";
194
+ readonly P_UpdateDate: "System[DateTime]";
195
+ readonly P_UpdatedBy: "User";
196
+ readonly P_Phase: "Option";
197
+ readonly P_PhaseDate: "DateTime";
198
+ readonly P_PhaseMemo: "MultilineText";
199
+ readonly P_Position: "SinglelineText";
200
+ readonly P_Publish: "Option";
201
+ readonly P_JobCategorySummary: "MultilineText";
202
+ readonly P_JobCategory: "Option";
203
+ readonly P_IndustrySummary: "MultilineText";
204
+ readonly P_Industry: "Option";
205
+ readonly P_SalarySummary: "MultilineText";
206
+ readonly P_MinSalary: "Number";
207
+ readonly P_MaxSalary: "Number";
208
+ readonly P_AreaSummary: "MultilineText";
209
+ readonly P_Area: "Option";
210
+ readonly P_PayrollsText: "SinglelineText";
211
+ readonly P_Memo: "MultilineText";
212
+ readonly P_EmploymentPeriod: "MultilineText";
213
+ readonly P_WokingHours: "MultilineText";
214
+ readonly P_Holidays: "MultilineText";
215
+ readonly P_Benefits: "MultilineText";
216
+ readonly P_PubliclyTraded: "Option";
217
+ readonly P_SalesAmountText: "SinglelineText";
218
+ readonly P_EstablishmentDateText: "SinglelineText";
219
+ readonly P_CapitalText: "SinglelineText";
220
+ readonly P_EmploymentType: "Option";
221
+ readonly P_ExpectedAgeReason: "Option";
222
+ };
223
+ declare const REQUIRED_ON_CREATE$3: readonly ["P_Owner", "P_Client", "P_Recruiter"];
224
+ /** A decoded Job: known `P_` fields, each requested field `value | null`. */
225
+ type Job = ReadRecord<typeof FIELDS$7>;
226
+ type JobPage = ResourcePage<typeof FIELDS$7>;
227
+ type JobSearchQuery = SearchQuery;
228
+ /** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */
229
+ type JobCreateInput = CreateInput<typeof FIELDS$7, (typeof REQUIRED_ON_CREATE$3)[number]>;
230
+ /** Fields for `update`: all optional (`null` omits, `""` clears a text field). */
231
+ type JobUpdateInput = UpdateInput<typeof FIELDS$7>;
232
+ /** The Job accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */
233
+ type JobResource<C extends FieldCatalog = EmptyCatalog> = Resource<typeof FIELDS$7 & C, (typeof REQUIRED_ON_CREATE$3)[number]>;
234
+
235
+ declare const FIELDS$6: {
236
+ readonly P_Id: "System[Id]";
237
+ readonly P_Owner: "User";
238
+ readonly P_RegistrationDate: "System[DateTime]";
239
+ readonly P_RegisteredBy: "User";
240
+ readonly P_UpdateDate: "System[DateTime]";
241
+ readonly P_UpdatedBy: "User";
242
+ readonly P_Phase: "Option";
243
+ readonly P_PhaseDate: "DateTime";
244
+ readonly P_PhaseMemo: "MultilineText";
245
+ readonly P_Name: "SinglelineText";
246
+ readonly P_Memo: "MultilineText";
247
+ readonly P_Country: "SinglelineText";
248
+ readonly P_Prefecture: "SinglelineText";
249
+ readonly P_City: "SinglelineText";
250
+ readonly P_Street: "MultilineText";
251
+ readonly P_Zipcode: "SinglelineText";
252
+ readonly P_Telephone: "Telephone";
253
+ readonly P_Fax: "Telephone";
254
+ };
255
+ declare const REQUIRED_ON_CREATE$2: readonly ["P_Owner"];
256
+ /** A decoded Client (company): known `P_` fields, each requested field `value | null`. */
257
+ type Client = ReadRecord<typeof FIELDS$6>;
258
+ type ClientPage = ResourcePage<typeof FIELDS$6>;
259
+ type ClientSearchQuery = SearchQuery;
260
+ /** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */
261
+ type ClientCreateInput = CreateInput<typeof FIELDS$6, (typeof REQUIRED_ON_CREATE$2)[number]>;
262
+ /** Fields for `update`: all optional (`null` omits, `""` clears a text field). */
263
+ type ClientUpdateInput = UpdateInput<typeof FIELDS$6>;
264
+ /** The Client accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */
265
+ type ClientResource<C extends FieldCatalog = EmptyCatalog> = Resource<typeof FIELDS$6 & C, (typeof REQUIRED_ON_CREATE$2)[number]>;
266
+
267
+ declare const FIELDS$5: {
268
+ readonly P_Id: "System[Id]";
269
+ readonly P_Owner: "User";
270
+ readonly P_Client: "System[Reference]";
271
+ readonly P_Recruiter: "System[Reference]";
272
+ readonly P_Job: "System[Reference]";
273
+ readonly P_Candidate: "System[Reference]";
274
+ readonly P_Resume: "System[Reference]";
275
+ readonly P_RegistrationDate: "System[DateTime]";
276
+ readonly P_RegisteredBy: "User";
277
+ readonly P_UpdateDate: "System[DateTime]";
278
+ readonly P_UpdatedBy: "User";
279
+ readonly P_Phase: "Option";
280
+ readonly P_PhaseDate: "DateTime";
281
+ readonly P_PhaseMemo: "MultilineText";
282
+ readonly P_Close: "Option";
283
+ readonly P_CloseReason: "Option";
284
+ readonly P_ExpectedSalesAmount: "Number";
285
+ readonly P_ExpectedClosingDate: "Date";
286
+ };
287
+ declare const REQUIRED_ON_CREATE$1: readonly ["P_Owner", "P_Client", "P_Recruiter", "P_Job", "P_Candidate", "P_Resume"];
288
+ /** A decoded Process (a Candidate's progress through a Job): known `P_` fields, each
289
+ * requested field `value | null`. */
290
+ type Process = ReadRecord<typeof FIELDS$5>;
291
+ type ProcessPage = ResourcePage<typeof FIELDS$5>;
292
+ type ProcessSearchQuery = SearchQuery;
293
+ /** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */
294
+ type ProcessCreateInput = CreateInput<typeof FIELDS$5, (typeof REQUIRED_ON_CREATE$1)[number]>;
295
+ /** Fields for `update`: all optional (`null` omits, `""` clears a text field). */
296
+ type ProcessUpdateInput = UpdateInput<typeof FIELDS$5>;
297
+ /** The Process accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */
298
+ type ProcessResource<C extends FieldCatalog = EmptyCatalog> = Resource<typeof FIELDS$5 & C, (typeof REQUIRED_ON_CREATE$1)[number]>;
299
+
300
+ declare const FIELDS$4: {
301
+ readonly P_Id: "System[Id]";
302
+ readonly P_Owner: "User";
303
+ readonly P_Candidate: "System[Reference]";
304
+ readonly P_RegistrationDate: "System[DateTime]";
305
+ readonly P_RegisteredBy: "User";
306
+ readonly P_UpdateDate: "System[DateTime]";
307
+ readonly P_UpdatedBy: "User";
308
+ readonly P_Phase: "Option";
309
+ readonly P_PhaseDate: "DateTime";
310
+ readonly P_PhaseMemo: "MultilineText";
311
+ readonly P_Name: "SinglelineText";
312
+ readonly P_RegisterChannel: "Option";
313
+ readonly P_Memo: "MultilineText";
314
+ readonly P_CurrentStatus: "Option";
315
+ readonly P_Education: "MultilineText";
316
+ readonly P_CarrierSummary: "MultilineText";
317
+ readonly P_CurrentSalary: "Number";
318
+ readonly P_ExperiencedJobCategory: "Option";
319
+ readonly P_ExperiencedIndustry: "Option";
320
+ readonly P_ChangeJobsCount: "Number";
321
+ readonly P_Gender: "Option";
322
+ readonly P_DateOfBirth: "Age";
323
+ readonly P_ExpectEmploymentType: "Option";
324
+ readonly P_ExpectArea: "Option";
325
+ readonly P_ExpectJobCategory: "Option";
326
+ readonly P_ExpectIndustry: "Option";
327
+ readonly P_ExpectCondition: "MultilineText";
328
+ readonly P_ExpectSalary: "Number";
329
+ readonly P_DesiredHourlyRate: "Number";
330
+ readonly P_HourlyRate: "Number";
331
+ };
332
+ declare const REQUIRED_ON_CREATE: readonly ["P_Owner", "P_Candidate"];
333
+ /** A decoded Resume (a Candidate's CV / profile): known `P_` fields, each requested field
334
+ * `value | null`. */
335
+ type Resume = ReadRecord<typeof FIELDS$4>;
336
+ type ResumePage = ResourcePage<typeof FIELDS$4>;
337
+ type ResumeSearchQuery = SearchQuery;
338
+ /** Fields for `create`: `P_Owner` required; `P_Id` / system timestamps are not settable. */
339
+ type ResumeCreateInput = CreateInput<typeof FIELDS$4, (typeof REQUIRED_ON_CREATE)[number]>;
340
+ /** Fields for `update`: all optional (`null` omits, `""` clears a text field). */
341
+ type ResumeUpdateInput = UpdateInput<typeof FIELDS$4>;
342
+ /** The Resume accessor; `C` is the declared custom-field catalog merged on (ADR-0023). */
343
+ type ResumeResource<C extends FieldCatalog = EmptyCatalog> = Resource<typeof FIELDS$4 & C, (typeof REQUIRED_ON_CREATE)[number]>;
344
+
345
+ /** A decoded Attachment. A field is `null` unless it was returned (see `field`). */
346
+ type Attachment = {
347
+ id: number | null;
348
+ /** Related resource type code (see the PORTERS Resource List). */
349
+ resource: number | null;
350
+ /** Related record id. */
351
+ resourceId: number | null;
352
+ contentType: string | null;
353
+ fileName: string | null;
354
+ /** Base64 file body. */
355
+ content: string | null;
356
+ };
357
+ type AttachmentPage = {
358
+ items: Attachment[];
359
+ total: number;
360
+ count: number;
361
+ start: number;
362
+ };
363
+ type AttachmentSearchQuery = {
364
+ /**
365
+ * Output fields. **Omit** to fetch metadata by default (Id / Resource / ResourceId /
366
+ * ContentType / FileName) — the large Base64 `Content` is excluded so listing doesn't download
367
+ * every file body (ADR-0020); request `["Content", …]` or use `get()` for the body. Pass `[]`
368
+ * for the API-native primary-key-only response. A non-empty list is sent verbatim.
369
+ */
370
+ field?: string[];
371
+ condition?: Record<string, string>;
372
+ count?: number;
373
+ start?: number;
374
+ };
375
+ /** Fields for creating an Attachment. `content` is the Base64 file body. */
376
+ type AttachmentCreate = {
377
+ resource: number;
378
+ resourceId: number;
379
+ contentType: string;
380
+ fileName: string;
381
+ content: string;
382
+ };
383
+ /** Fields for updating an Attachment. `Resource` / `ResourceId` are not updatable. */
384
+ type AttachmentUpdate = {
385
+ contentType?: string;
386
+ fileName?: string;
387
+ content?: string;
388
+ };
389
+ type AttachmentResource = {
390
+ search(query?: AttachmentSearchQuery): Promise<AttachmentPage>;
391
+ get(id: number): Promise<Attachment | undefined>;
392
+ /** Create an Attachment; resolves to the newly assigned id. */
393
+ create(input: AttachmentCreate): Promise<number>;
394
+ /** Update an Attachment by id; resolves to that id. */
395
+ update(id: number, input: AttachmentUpdate): Promise<number>;
396
+ };
397
+
398
+ declare const FIELDS$3: {
399
+ readonly P_Id: "System[Id]";
400
+ readonly P_Name: "SinglelineText";
401
+ readonly P_CompanyId: "SinglelineText";
402
+ };
403
+ /** A decoded Partition (a PORTERS contract company / Company DB). */
404
+ type Partition = ReadRecord<typeof FIELDS$3>;
405
+ type PartitionPage = ResourcePage<typeof FIELDS$3>;
406
+ /** Partition Read query. `requestType` 1 = partitions this App can access (default). */
407
+ type PartitionSearchQuery = {
408
+ /** 1 = accessible partitions (default). 0 = login partition (browser `code` grant only). */
409
+ requestType?: 0 | 1;
410
+ count?: number;
411
+ start?: number;
412
+ };
413
+ type PartitionResource = {
414
+ search(query?: PartitionSearchQuery): Promise<PartitionPage>;
415
+ /** Auto-paginating search: yields every accessible partition. */
416
+ searchAll(query?: Omit<PartitionSearchQuery, "count" | "start">): AsyncIterable<Partition>;
417
+ };
418
+
419
+ declare const FIELDS$2: {
420
+ readonly P_Id: "System[Id]";
421
+ readonly P_Type: "Number";
422
+ readonly P_Name: "SinglelineText";
423
+ readonly P_Mail: "Mail";
424
+ };
425
+ /** A decoded User (PORTERS operator). `P_Type`: 0 = standard user, 1 = system admin. */
426
+ type User = ReadRecord<typeof FIELDS$2>;
427
+ type UserPage = ResourcePage<typeof FIELDS$2>;
428
+ /** User Read query. `requestType` 1 = all users (default); `userType` -1 = any (default). */
429
+ type UserSearchQuery = {
430
+ /** 1 = all users (default). 0 = the current user (code_direct → the App's own user). */
431
+ requestType?: 0 | 1;
432
+ /** -1 = any (default), 0 = system admins, 1 = standard users. */
433
+ userType?: -1 | 0 | 1;
434
+ /** Output fields (prefixed aliases). Omit to get the 4 core fields (this catalog). */
435
+ field?: string[];
436
+ count?: number;
437
+ start?: number;
438
+ };
439
+ type UserResource = {
440
+ search(query?: UserSearchQuery): Promise<UserPage>;
441
+ /** Auto-paginating search: yields every matching user. */
442
+ searchAll(query?: Omit<UserSearchQuery, "count" | "start">): AsyncIterable<User>;
443
+ /**
444
+ * The current API user (`request_type=0`). Under the library's default `code_direct` auth
445
+ * this resolves to the App's own user (username = app name) — useful for self-identification.
446
+ * Under the browser `code` grant it is the logged-in user. Resolves `undefined` if none.
447
+ */
448
+ current(): Promise<User | undefined>;
449
+ };
450
+
451
+ declare const RESOURCE_VALUE: {
452
+ readonly candidate: 1;
453
+ readonly job: 3;
454
+ readonly client: 5;
455
+ readonly recruiter: 9;
456
+ readonly sales: 11;
457
+ readonly contract: 13;
458
+ readonly resume: 17;
459
+ readonly activity: 19;
460
+ readonly opportunity: 25;
461
+ readonly contact: 27;
462
+ };
463
+ /** A resource whose field catalog can be read (Field Read `resource` selector). */
464
+ type ResourceType = keyof typeof RESOURCE_VALUE;
465
+ declare const FIELDS$1: {
466
+ readonly P_Id: "System[Id]";
467
+ readonly P_Name: "SinglelineText";
468
+ readonly P_Alias: "SinglelineText";
469
+ readonly P_Type: "Number";
470
+ readonly P_Required: "Number";
471
+ readonly P_Max: "Number";
472
+ readonly P_Min: "Number";
473
+ readonly P_DecimalFraction: "Number";
474
+ readonly P_ReferTo: "Option";
475
+ readonly P_ResourceType: "Number";
476
+ };
477
+ /** A decoded Field definition. `P_Required`: 0 = normal, 1 = required. */
478
+ type Field = ReadRecord<typeof FIELDS$1>;
479
+ type FieldPage = ResourcePage<typeof FIELDS$1>;
480
+ /** Field Read query. `resource` selects which resource's fields to read (required). */
481
+ type FieldSearchQuery = {
482
+ resource: ResourceType;
483
+ /** -1 = all (default), 0 = unused only, 1 = in-use only. */
484
+ active?: -1 | 0 | 1;
485
+ count?: number;
486
+ start?: number;
487
+ };
488
+ type FieldResource = {
489
+ search(query: FieldSearchQuery): Promise<FieldPage>;
490
+ /** Auto-paginating search: yields every field of the resource. */
491
+ searchAll(query: Omit<FieldSearchQuery, "count" | "start">): AsyncIterable<Field>;
492
+ };
493
+
494
+ declare const FIELDS: {
495
+ readonly P_Id: "System[Id]";
496
+ readonly P_Name: "SinglelineText";
497
+ readonly P_Alias: "SinglelineText";
498
+ readonly P_ParentId: "Number";
499
+ readonly P_Type: "Number";
500
+ readonly P_Order: "Number";
501
+ };
502
+ /** A decoded Option (one choice). `P_ParentId` links to the parent; `P_Type` 0 = normal, 1–11 = a phase kind. */
503
+ type Option = ReadRecord<typeof FIELDS>;
504
+ /** Option Read query. `alias` selects a subtree root; `level` its depth (-1 all). */
505
+ type OptionSearchQuery = {
506
+ /** Root alias of the subtree to read (e.g. `Option.P_Gender`). Omit for all. */
507
+ alias?: string;
508
+ /** Depth: -1 all (default), 0 = siblings of `alias`, 1+ = descendants. */
509
+ level?: number;
510
+ /** -1 = all (default), 0 = unused only, 1 = in-use only. */
511
+ enabled?: -1 | 0 | 1;
512
+ count?: number;
513
+ };
514
+ type OptionResource = {
515
+ /** Read options, flattened depth-first (all nodes; tree is reconstructable via `P_ParentId`). */
516
+ search(query?: OptionSearchQuery): Promise<Option[]>;
517
+ };
518
+
519
+ /** One custom field's declared Data Type — the builder's return value (ADR-0023 D2). */
520
+ type FieldDef<D extends DataType> = {
521
+ readonly dataType: D;
522
+ };
523
+ type CustomDataType = "Number" | "SinglelineText" | "MultilineText" | "Mail" | "Telephone" | "URL" | "Date" | "DateTime" | "Age" | "Option" | "User";
524
+ /** Builder passed to each resource declaration: one method per declarable Data Type. */
525
+ type FieldBuilder = {
526
+ number(): FieldDef<"Number">;
527
+ singlelineText(): FieldDef<"SinglelineText">;
528
+ multilineText(): FieldDef<"MultilineText">;
529
+ mail(): FieldDef<"Mail">;
530
+ telephone(): FieldDef<"Telephone">;
531
+ url(): FieldDef<"URL">;
532
+ date(): FieldDef<"Date">;
533
+ dateTime(): FieldDef<"DateTime">;
534
+ age(): FieldDef<"Age">;
535
+ option(): FieldDef<"Option">;
536
+ user(): FieldDef<"User">;
537
+ };
538
+ /** Data resources that accept custom fields (ADR-0023 D6). Master / Attachment are excluded. */
539
+ type CustomFieldResource = "candidate" | "job" | "client" | "process" | "resume";
540
+ /** One resource's custom field declarations: alias -> {@link FieldDef}. */
541
+ type ResourceDecl = Record<string, FieldDef<DataType>>;
542
+ /** Declaration input: per (data) resource, a builder fn returning its custom fields. */
543
+ type FieldDecls = {
544
+ [R in CustomFieldResource]?: (f: FieldBuilder) => ResourceDecl;
545
+ };
546
+ /** A per-resource custom catalog (bare alias -> Data Type), as produced by {@link defineFields}. */
547
+ type CustomCatalog = Record<string, DataType>;
548
+ /** Map of (data) resource -> its custom catalog; the client merges these into the static catalogs. */
549
+ type DeclaredCatalogs = {
550
+ [R in CustomFieldResource]?: CustomCatalog;
551
+ };
552
+ type CatalogOf<R extends ResourceDecl> = {
553
+ [K in keyof R]: R[K]["dataType"];
554
+ };
555
+ /** The validated, branded result of {@link defineFields}, keyed by the declared resources. */
556
+ type DeclaredCatalogsOf<D extends FieldDecls> = {
557
+ [R in keyof D]: D[R] extends (f: FieldBuilder) => infer Out ? Out extends ResourceDecl ? CatalogOf<Out> : never : never;
558
+ };
559
+ declare const definedFieldsBrand: unique symbol;
560
+ /** A validated set of custom field catalogs (branded — the client does not re-validate). */
561
+ type DefinedFields<C extends DeclaredCatalogs = DeclaredCatalogs> = C & {
562
+ readonly [definedFieldsBrand]: true;
563
+ };
564
+ /** The custom catalog declared for resource `K` (or `{}` if none) — types each accessor (ADR-0023 D1). */
565
+ type CustomFor<C extends DeclaredCatalogs, K extends CustomFieldResource> = K extends keyof C ? C[K] extends CustomCatalog ? C[K] : EmptyCatalog : EmptyCatalog;
566
+ /**
567
+ * Declare tenant-specific custom fields per data resource (ADR-0023). This is the validation
568
+ * boundary: it throws {@link PortersConfigError} synchronously for an unknown resource key or an
569
+ * alias that is not `U_`/`A_`-prefixed. The branded result is passed to `PortersClient({ fields })`,
570
+ * which merges each catalog into the resource so the custom fields decode/encode by their declared
571
+ * Data Type and appear typed on reads / writes.
572
+ *
573
+ * @example
574
+ * const myFields = defineFields({
575
+ * candidate: (f) => ({ U_score: f.number(), U_source: f.option() }),
576
+ * });
577
+ */
578
+ declare const defineFields: <D extends FieldDecls>(decls: D) => DefinedFields<DeclaredCatalogsOf<D>>;
579
+
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
+ /** Options for constructing a {@link PortersClient}. `C` is inferred from `fields` (ADR-0023). */
586
+ type PortersClientOptions<C extends DeclaredCatalogs = EmptyCatalog> = {
587
+ /**
588
+ * API host. Required and supplied via `PORTERS_HOST` — never hard-code it.
589
+ * (A representative value lives in docs/reference.)
590
+ */
591
+ host: string;
592
+ appId?: string;
593
+ appSecret?: string;
594
+ scopes?: Scope[];
595
+ /** Default partition; overridable per call (ADR-0008). */
596
+ partition?: PartitionId;
597
+ /** Custom auth strategy; defaults to the transparent code_direct strategy. */
598
+ auth?: TokenProvider;
599
+ /** Token persistence; defaults to in-memory. */
600
+ tokenStore?: TokenStore;
601
+ /** Injectable HTTP transport; defaults to a fetch-based transport. */
602
+ transport?: Transport;
603
+ /**
604
+ * Tenant custom field declarations from {@link defineFields} (ADR-0023). Each resource's
605
+ * declared `U_`/`A_` fields are merged onto its static catalog, so they decode/encode by
606
+ * their declared Data Type and appear typed on reads / writes. Omit for standard `P_` only.
607
+ */
608
+ fields?: DefinedFields<C>;
609
+ };
610
+ /**
611
+ * Entry point of the library. Wires the default transport / auth / throttle /
612
+ * requester and exposes namespaced resource accessors such as `candidate`
613
+ * (ADR-0005).
614
+ */
615
+ declare class PortersClient<C extends DeclaredCatalogs = EmptyCatalog> {
616
+ #private;
617
+ readonly candidate: CandidateResource<CustomFor<C, "candidate">>;
618
+ readonly job: JobResource<CustomFor<C, "job">>;
619
+ readonly client: ClientResource<CustomFor<C, "client">>;
620
+ readonly process: ProcessResource<CustomFor<C, "process">>;
621
+ readonly resume: ResumeResource<CustomFor<C, "resume">>;
622
+ readonly attachment: AttachmentResource;
623
+ /** Master Read: accessible partitions (ADR-0021/0022). */
624
+ readonly partition: PartitionResource;
625
+ /** Master Read: users, plus `current()` self-identification (ADR-0021/0022). */
626
+ readonly user: UserResource;
627
+ /** Master Read: a resource's field catalog (ADR-0021/0022). */
628
+ readonly field: FieldResource;
629
+ /** Master Read: a tenant's choice (option) master (ADR-0021/0022). */
630
+ readonly option: OptionResource;
631
+ constructor(options: PortersClientOptions<C>);
632
+ /** The configured API host. */
633
+ get host(): string;
634
+ }
635
+
636
+ /** Cross-cutting classification shared by every PORTERS error. */
637
+ type ErrorCategory = "auth" | "permission" | "validation" | "notFound" | "conflict" | "rateLimit" | "transient" | "network" | "server" | "config" | "unknown";
638
+ /** Where the failing call was aimed (for self-service debugging). */
639
+ type PortersErrorContext = {
640
+ resource?: string;
641
+ operation?: string;
642
+ partition?: number;
643
+ };
644
+ /** Construction options for {@link PortersError}. */
645
+ type PortersErrorOptions = {
646
+ category: ErrorCategory;
647
+ /** PORTERS raw code; `null` for network/transport failures. */
648
+ code?: number | null;
649
+ retryable?: boolean;
650
+ /** Actionable hint (English by default). */
651
+ hint?: string;
652
+ httpStatus?: number;
653
+ context?: PortersErrorContext;
654
+ cause?: unknown;
655
+ };
656
+ /** Base class for every PORTERS-originated error (catch-all). */
657
+ declare class PortersError extends Error {
658
+ readonly category: ErrorCategory;
659
+ readonly code: number | null;
660
+ readonly retryable: boolean;
661
+ readonly hint?: string;
662
+ readonly httpStatus?: number;
663
+ readonly context?: PortersErrorContext;
664
+ constructor(message: string, options: PortersErrorOptions);
665
+ }
666
+ /** OAuth / Token errors. */
667
+ declare class PortersAuthError extends PortersError {
668
+ }
669
+ /** Resource API errors. */
670
+ declare class PortersResourceError extends PortersError {
671
+ }
672
+ /** Connection / timeout / forced rate-limit disconnect. */
673
+ declare class PortersNetworkError extends PortersError {
674
+ }
675
+ /** Misconfiguration / misuse — not PORTERS-originated; thrown synchronously. */
676
+ declare class PortersConfigError extends PortersError {
677
+ }
678
+
679
+ /** Encode raw bytes to a Base64 string. */
680
+ declare const bytesToBase64: (bytes: Uint8Array) => string;
681
+ /** Decode a Base64 string back to raw bytes. */
682
+ declare const base64ToBytes: (b64: string) => Uint8Array;
683
+
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 };