@cavuno/board 1.0.0 → 1.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.
- package/dist/index.d.mts +306 -130
- package/dist/index.d.ts +306 -130
- package/dist/index.js +49 -2
- package/dist/index.mjs +49 -2
- package/package.json +10 -9
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe-shaped success envelopes (`01-conventions.md` §5.1). The
|
|
3
|
+
* server MAY add top-level fields; consumers MUST ignore unknown
|
|
4
|
+
* fields.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Medusa-style storefront pagination fields (ADR-0037 §7), populated only by
|
|
8
|
+
* the board jobs catalog reads (browse / search / company-jobs); absent on
|
|
9
|
+
* every other list/search. `nextCursor` is preserved alongside (offset-encoded).
|
|
10
|
+
*/
|
|
11
|
+
interface StorefrontPagination {
|
|
12
|
+
/** Total matching results ("X jobs"). */
|
|
13
|
+
count?: number;
|
|
14
|
+
/** The page size used for this response. */
|
|
15
|
+
limit?: number;
|
|
16
|
+
/** Number of items skipped before this page. */
|
|
17
|
+
offset?: number;
|
|
18
|
+
/** Items hidden behind the candidate paywall for the current viewer; absent/0 when entitled. */
|
|
19
|
+
gatedCount?: number;
|
|
20
|
+
}
|
|
21
|
+
interface ListEnvelope<T> extends StorefrontPagination {
|
|
22
|
+
object: 'list';
|
|
23
|
+
url: string;
|
|
24
|
+
hasMore: boolean;
|
|
25
|
+
/** `null` when `hasMore` is false — always present, never undefined. */
|
|
26
|
+
nextCursor: string | null;
|
|
27
|
+
data: T[];
|
|
28
|
+
}
|
|
29
|
+
interface SearchEnvelope<T> extends StorefrontPagination {
|
|
30
|
+
object: 'search_result';
|
|
31
|
+
url: string;
|
|
32
|
+
hasMore: boolean;
|
|
33
|
+
nextCursor: string | null;
|
|
34
|
+
data: T[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type RemoteOption = 'on_site' | 'hybrid' | 'remote';
|
|
38
|
+
type EmploymentType = 'full_time' | 'part_time' | 'contract' | 'internship' | 'temporary' | 'volunteer' | 'other';
|
|
39
|
+
type Seniority = 'entry_level' | 'associate' | 'mid_level' | 'senior' | 'lead' | 'principal' | 'director' | 'executive';
|
|
40
|
+
type EducationRequirement = 'high_school' | 'associate_degree' | 'bachelor_degree' | 'professional_certificate' | 'postgraduate_degree' | 'no_requirements';
|
|
41
|
+
interface OfficeLocation {
|
|
42
|
+
countryCode: string | null;
|
|
43
|
+
country: string | null;
|
|
44
|
+
locality: string | null;
|
|
45
|
+
city: string | null;
|
|
46
|
+
region: string | null;
|
|
47
|
+
regionCode: string | null;
|
|
48
|
+
postalCode: string | null;
|
|
49
|
+
displayName: string | null;
|
|
50
|
+
}
|
|
51
|
+
interface JobCompany {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string | null;
|
|
54
|
+
slug: string | null;
|
|
55
|
+
logoUrl: string | null;
|
|
56
|
+
website: string | null;
|
|
57
|
+
}
|
|
58
|
+
interface RemotePermit {
|
|
59
|
+
type: string;
|
|
60
|
+
value: string;
|
|
61
|
+
}
|
|
62
|
+
interface RemoteTimezone {
|
|
63
|
+
type: string;
|
|
64
|
+
value: string;
|
|
65
|
+
plusMinus?: number;
|
|
66
|
+
}
|
|
67
|
+
interface PublicJob {
|
|
68
|
+
id: string;
|
|
69
|
+
object: 'public_job';
|
|
70
|
+
title: string;
|
|
71
|
+
slug: string | null;
|
|
72
|
+
status: string;
|
|
73
|
+
companyId: string | null;
|
|
74
|
+
employmentType: string | null;
|
|
75
|
+
remoteOption: string | null;
|
|
76
|
+
seniority: string | null;
|
|
77
|
+
salaryMin: number | null;
|
|
78
|
+
salaryMax: number | null;
|
|
79
|
+
salaryCurrency: string | null;
|
|
80
|
+
salaryTimeframe: string | null;
|
|
81
|
+
isFeatured: boolean;
|
|
82
|
+
publishedAt: string | null;
|
|
83
|
+
expiresAt: string | null;
|
|
84
|
+
createdAt: string;
|
|
85
|
+
updatedAt: string;
|
|
86
|
+
description: string | null;
|
|
87
|
+
applicationUrl: string | null;
|
|
88
|
+
/** Canonical hierarchical permit selection. */
|
|
89
|
+
remotePermits: RemotePermit[];
|
|
90
|
+
/** Read-only — derived from `remotePermits`. */
|
|
91
|
+
remoteWorldwide: boolean | null;
|
|
92
|
+
/** Canonical hierarchical timezone selection. */
|
|
93
|
+
remoteTimezones: RemoteTimezone[];
|
|
94
|
+
/** Read-only — derived from `remoteTimezones`. */
|
|
95
|
+
remoteAllowedTzOffsets: number[];
|
|
96
|
+
/** Read-only — derived from `remotePermits`. */
|
|
97
|
+
remoteWorkPermitCountryCodes: string[];
|
|
98
|
+
/** Read-only — derived from `remotePermits`. */
|
|
99
|
+
remoteWorkPermitSubdivisionCodes: string[];
|
|
100
|
+
remoteSponsorship: 'yes' | 'no' | 'unknown';
|
|
101
|
+
educationRequirements: EducationRequirement[];
|
|
102
|
+
experienceMonths: number | null;
|
|
103
|
+
experienceInPlaceOfEducation: boolean | null;
|
|
104
|
+
inOfficePeriod: 'per_week' | 'per_month' | 'per_year' | null;
|
|
105
|
+
inOfficeFrequency: number | null;
|
|
106
|
+
company: JobCompany | null;
|
|
107
|
+
officeLocations: OfficeLocation[];
|
|
108
|
+
/** Resolved taxonomy — same `{slug,name}` shape as `PublicJobCard`; names joined server-side. */
|
|
109
|
+
categories: Array<{
|
|
110
|
+
slug: string;
|
|
111
|
+
name: string;
|
|
112
|
+
}>;
|
|
113
|
+
skills: Array<{
|
|
114
|
+
slug: string;
|
|
115
|
+
name: string;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Place ancestor chain (country → region → city) for the breadcrumb. Each
|
|
119
|
+
* `slug` is the English SOURCE slug — the key `taxonomy.places.resolve()`
|
|
120
|
+
* accepts. On a localized board it may differ from the canonical
|
|
121
|
+
* board-language URL slug (the board router 308-redirects the source slug to
|
|
122
|
+
* the canonical one); link via `/jobs/locations/:slug`.
|
|
123
|
+
*/
|
|
124
|
+
placeHierarchy: Array<{
|
|
125
|
+
slug: string;
|
|
126
|
+
name: string;
|
|
127
|
+
}>;
|
|
128
|
+
links: {
|
|
129
|
+
public: string | null;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The slim listing card (ADR-0037 §1) returned by `jobs.list` / `jobs.search`
|
|
134
|
+
* / `companies.listJobs`. Full enrichment (description, officeLocations, the
|
|
135
|
+
* structured remote blocks, …) lives on `jobs.retrieve` (`PublicJob`).
|
|
136
|
+
* Transcribed from `serializeJobCard`.
|
|
137
|
+
*/
|
|
138
|
+
interface PublicJobCard {
|
|
139
|
+
id: string;
|
|
140
|
+
object: 'job_card';
|
|
141
|
+
slug: string;
|
|
142
|
+
title: string;
|
|
143
|
+
publishedAt: string | null;
|
|
144
|
+
employmentType: string | null;
|
|
145
|
+
remoteOption: string | null;
|
|
146
|
+
/** Remote-region label for remote jobs (e.g. "Worldwide"); `null` otherwise. */
|
|
147
|
+
remoteLocationLabel: string | null;
|
|
148
|
+
salaryMin: number | null;
|
|
149
|
+
salaryMax: number | null;
|
|
150
|
+
salaryCurrency: string | null;
|
|
151
|
+
salaryTimeframe: string | null;
|
|
152
|
+
isFeatured: boolean;
|
|
153
|
+
locationLabel: string | null;
|
|
154
|
+
company: {
|
|
155
|
+
slug: string;
|
|
156
|
+
name: string;
|
|
157
|
+
logoUrl: string | null;
|
|
158
|
+
} | null;
|
|
159
|
+
categories: Array<{
|
|
160
|
+
slug: string;
|
|
161
|
+
name: string;
|
|
162
|
+
}>;
|
|
163
|
+
skills: Array<{
|
|
164
|
+
slug: string;
|
|
165
|
+
name: string;
|
|
166
|
+
}>;
|
|
167
|
+
links: {
|
|
168
|
+
public: string | null;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Long-form description (HTML), or `null`. Present ONLY when the list/search
|
|
172
|
+
* was called with `fields: '+description'` (the RSS feed's sparse-fieldset
|
|
173
|
+
* opt-in); `undefined`/absent on the default slim card.
|
|
174
|
+
*/
|
|
175
|
+
description?: string | null;
|
|
176
|
+
}
|
|
177
|
+
/** Derived category/skill suggestion on the jobs browse list (ADR-0037 §8). */
|
|
178
|
+
interface RelatedSearch {
|
|
179
|
+
type: 'category' | 'skill';
|
|
180
|
+
slug: string;
|
|
181
|
+
term: string;
|
|
182
|
+
count: number;
|
|
183
|
+
}
|
|
184
|
+
/** The browse list envelope — `PublicJobCard`s + storefront fields + `relatedSearches`. */
|
|
185
|
+
interface JobCardListEnvelope extends ListEnvelope<PublicJobCard> {
|
|
186
|
+
relatedSearches?: RelatedSearch[];
|
|
187
|
+
}
|
|
188
|
+
/** The search envelope — `PublicJobCard`s + storefront fields. */
|
|
189
|
+
type JobCardSearchEnvelope = SearchEnvelope<PublicJobCard>;
|
|
190
|
+
type JobsListQuery = {
|
|
191
|
+
cursor?: string;
|
|
192
|
+
/** 1–100. */
|
|
193
|
+
limit?: number;
|
|
194
|
+
/** Storefront page offset; takes precedence over `cursor`. `offset + limit` ≤ 10,000. */
|
|
195
|
+
offset?: number;
|
|
196
|
+
/** Single or repeated (up to 10) — repeated params are OR-matched. */
|
|
197
|
+
companyId?: string | string[];
|
|
198
|
+
remoteOption?: RemoteOption | RemoteOption[];
|
|
199
|
+
employmentType?: EmploymentType | EmploymentType[];
|
|
200
|
+
seniority?: Seniority | Seniority[];
|
|
201
|
+
/** Place slug for a geo radius search; unresolvable slugs are ignored. */
|
|
202
|
+
location?: string;
|
|
203
|
+
/** Radius in km around `location` (10–250; default 50). */
|
|
204
|
+
radius?: number;
|
|
205
|
+
/** Category slug seed (the `/jobs/[keyword]` page) — server resolves it to the English source name; unresolvable → 404. */
|
|
206
|
+
category?: string;
|
|
207
|
+
/** Skill slug seed (the `/jobs/skills/[skill]` page) — server-resolved; unresolvable → 404. */
|
|
208
|
+
skill?: string;
|
|
209
|
+
/** Sparse fieldset (Medusa-style `+field`). Only `'+description'` is supported — adds `description` to each card. */
|
|
210
|
+
fields?: string;
|
|
211
|
+
};
|
|
212
|
+
type JobsSimilarQuery = {
|
|
213
|
+
/** How many similar jobs to return (1–20; default 5). */
|
|
214
|
+
limit?: number;
|
|
215
|
+
};
|
|
216
|
+
interface JobsSearchBody {
|
|
217
|
+
/** Free-text query, up to 200 characters. */
|
|
218
|
+
query?: string;
|
|
219
|
+
filters?: {
|
|
220
|
+
/** Up to 10 values each. */
|
|
221
|
+
companyId?: string[];
|
|
222
|
+
remoteOption?: RemoteOption[];
|
|
223
|
+
employmentType?: EmploymentType[];
|
|
224
|
+
seniority?: Seniority[];
|
|
225
|
+
/** ISO 8601 datetime bounds. */
|
|
226
|
+
publishedAt?: {
|
|
227
|
+
gte?: string;
|
|
228
|
+
lte?: string;
|
|
229
|
+
};
|
|
230
|
+
/** Place slug for a geo radius search. */
|
|
231
|
+
location?: string;
|
|
232
|
+
/** Radius in km around `location` (10–250; default 50). */
|
|
233
|
+
radius?: number;
|
|
234
|
+
};
|
|
235
|
+
cursor?: string;
|
|
236
|
+
/** 1–100. */
|
|
237
|
+
limit?: number;
|
|
238
|
+
/** Storefront page offset; takes precedence over `cursor`. */
|
|
239
|
+
offset?: number;
|
|
240
|
+
}
|
|
241
|
+
|
|
1
242
|
type Awaitable<T> = T | Promise<T>;
|
|
2
243
|
/**
|
|
3
244
|
* Async token storage. The SDK reads the access token from storage on
|
|
@@ -151,7 +392,7 @@ declare function isConflict(e: unknown): e is BoardApiError;
|
|
|
151
392
|
* constant because the package is platform-neutral and cannot read
|
|
152
393
|
* package.json at runtime.
|
|
153
394
|
*/
|
|
154
|
-
declare const SDK_VERSION = "1.
|
|
395
|
+
declare const SDK_VERSION = "1.1.0";
|
|
155
396
|
|
|
156
397
|
interface BoardUser {
|
|
157
398
|
id: string;
|
|
@@ -268,27 +509,6 @@ interface BlogSearchBody {
|
|
|
268
509
|
limit?: number;
|
|
269
510
|
}
|
|
270
511
|
|
|
271
|
-
/**
|
|
272
|
-
* Stripe-shaped success envelopes (`01-conventions.md` §5.1). The
|
|
273
|
-
* server MAY add top-level fields; consumers MUST ignore unknown
|
|
274
|
-
* fields.
|
|
275
|
-
*/
|
|
276
|
-
interface ListEnvelope<T> {
|
|
277
|
-
object: 'list';
|
|
278
|
-
url: string;
|
|
279
|
-
hasMore: boolean;
|
|
280
|
-
/** `null` when `hasMore` is false — always present, never undefined. */
|
|
281
|
-
nextCursor: string | null;
|
|
282
|
-
data: T[];
|
|
283
|
-
}
|
|
284
|
-
interface SearchEnvelope<T> {
|
|
285
|
-
object: 'search_result';
|
|
286
|
-
url: string;
|
|
287
|
-
hasMore: boolean;
|
|
288
|
-
nextCursor: string | null;
|
|
289
|
-
data: T[];
|
|
290
|
-
}
|
|
291
|
-
|
|
292
512
|
interface PublicCompany {
|
|
293
513
|
id: string;
|
|
294
514
|
object: 'public_company';
|
|
@@ -321,110 +541,6 @@ interface CompaniesSearchBody {
|
|
|
321
541
|
limit?: number;
|
|
322
542
|
}
|
|
323
543
|
|
|
324
|
-
type RemoteOption = 'on_site' | 'hybrid' | 'remote';
|
|
325
|
-
type EmploymentType = 'full_time' | 'part_time' | 'contract' | 'internship' | 'temporary' | 'volunteer' | 'other';
|
|
326
|
-
type Seniority = 'entry_level' | 'associate' | 'mid_level' | 'senior' | 'lead' | 'principal' | 'director' | 'executive';
|
|
327
|
-
type EducationRequirement = 'high_school' | 'associate_degree' | 'bachelor_degree' | 'professional_certificate' | 'postgraduate_degree' | 'no_requirements';
|
|
328
|
-
interface OfficeLocation {
|
|
329
|
-
countryCode: string | null;
|
|
330
|
-
country: string | null;
|
|
331
|
-
locality: string | null;
|
|
332
|
-
city: string | null;
|
|
333
|
-
region: string | null;
|
|
334
|
-
regionCode: string | null;
|
|
335
|
-
postalCode: string | null;
|
|
336
|
-
displayName: string | null;
|
|
337
|
-
}
|
|
338
|
-
interface JobCompany {
|
|
339
|
-
id: string;
|
|
340
|
-
name: string | null;
|
|
341
|
-
slug: string | null;
|
|
342
|
-
logoUrl: string | null;
|
|
343
|
-
website: string | null;
|
|
344
|
-
}
|
|
345
|
-
interface RemotePermit {
|
|
346
|
-
type: string;
|
|
347
|
-
value: string;
|
|
348
|
-
}
|
|
349
|
-
interface RemoteTimezone {
|
|
350
|
-
type: string;
|
|
351
|
-
value: string;
|
|
352
|
-
plusMinus?: number;
|
|
353
|
-
}
|
|
354
|
-
interface PublicJob {
|
|
355
|
-
id: string;
|
|
356
|
-
object: 'public_job';
|
|
357
|
-
title: string;
|
|
358
|
-
slug: string | null;
|
|
359
|
-
status: string;
|
|
360
|
-
companyId: string | null;
|
|
361
|
-
employmentType: string | null;
|
|
362
|
-
remoteOption: string | null;
|
|
363
|
-
seniority: string | null;
|
|
364
|
-
salaryMin: number | null;
|
|
365
|
-
salaryMax: number | null;
|
|
366
|
-
salaryCurrency: string | null;
|
|
367
|
-
salaryTimeframe: string | null;
|
|
368
|
-
isFeatured: boolean;
|
|
369
|
-
publishedAt: string | null;
|
|
370
|
-
expiresAt: string | null;
|
|
371
|
-
createdAt: string;
|
|
372
|
-
updatedAt: string;
|
|
373
|
-
description: string | null;
|
|
374
|
-
applicationUrl: string | null;
|
|
375
|
-
/** Canonical hierarchical permit selection. */
|
|
376
|
-
remotePermits: RemotePermit[];
|
|
377
|
-
/** Read-only — derived from `remotePermits`. */
|
|
378
|
-
remoteWorldwide: boolean | null;
|
|
379
|
-
/** Canonical hierarchical timezone selection. */
|
|
380
|
-
remoteTimezones: RemoteTimezone[];
|
|
381
|
-
/** Read-only — derived from `remoteTimezones`. */
|
|
382
|
-
remoteAllowedTzOffsets: number[];
|
|
383
|
-
/** Read-only — derived from `remotePermits`. */
|
|
384
|
-
remoteWorkPermitCountryCodes: string[];
|
|
385
|
-
/** Read-only — derived from `remotePermits`. */
|
|
386
|
-
remoteWorkPermitSubdivisionCodes: string[];
|
|
387
|
-
remoteSponsorship: 'yes' | 'no' | 'unknown';
|
|
388
|
-
educationRequirements: EducationRequirement[];
|
|
389
|
-
experienceMonths: number | null;
|
|
390
|
-
experienceInPlaceOfEducation: boolean | null;
|
|
391
|
-
inOfficePeriod: 'per_week' | 'per_month' | 'per_year' | null;
|
|
392
|
-
inOfficeFrequency: number | null;
|
|
393
|
-
company: JobCompany | null;
|
|
394
|
-
officeLocations: OfficeLocation[];
|
|
395
|
-
links: {
|
|
396
|
-
public: string | null;
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
type JobsListQuery = {
|
|
400
|
-
cursor?: string;
|
|
401
|
-
/** 1–100. */
|
|
402
|
-
limit?: number;
|
|
403
|
-
companyId?: string;
|
|
404
|
-
remoteOption?: RemoteOption;
|
|
405
|
-
employmentType?: EmploymentType;
|
|
406
|
-
seniority?: Seniority;
|
|
407
|
-
};
|
|
408
|
-
interface JobsSearchBody {
|
|
409
|
-
/** Free-text query, up to 200 characters. */
|
|
410
|
-
query?: string;
|
|
411
|
-
filters?: {
|
|
412
|
-
/** Up to 10 values each. */
|
|
413
|
-
companyId?: string[];
|
|
414
|
-
remoteOption?: RemoteOption[];
|
|
415
|
-
employmentType?: EmploymentType[];
|
|
416
|
-
seniority?: Seniority[];
|
|
417
|
-
/** ISO 8601 datetime bounds. */
|
|
418
|
-
publishedAt?: {
|
|
419
|
-
gte?: string;
|
|
420
|
-
lte?: string;
|
|
421
|
-
};
|
|
422
|
-
};
|
|
423
|
-
cursor?: string;
|
|
424
|
-
/** 1–100. */
|
|
425
|
-
limit?: number;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
544
|
/**
|
|
429
545
|
* The embedded `job` is the SAME `public_job` shape the anonymous jobs
|
|
430
546
|
* list emits — saved rows and search rows render with one component.
|
|
@@ -446,6 +562,53 @@ interface SaveJobBody {
|
|
|
446
562
|
jobId: string;
|
|
447
563
|
}
|
|
448
564
|
|
|
565
|
+
interface TaxonomyGeo {
|
|
566
|
+
lat: number | null;
|
|
567
|
+
lng: number | null;
|
|
568
|
+
countryCode: string | null;
|
|
569
|
+
regionCode: string | null;
|
|
570
|
+
region: string | null;
|
|
571
|
+
city: string | null;
|
|
572
|
+
locality: string | null;
|
|
573
|
+
placeType: string | null;
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Page-meta for a resolved taxonomy slug. `sourceSlug` is the immutable
|
|
577
|
+
* English search key; `canonicalSlug` is the board-language URL; `redirectTo`
|
|
578
|
+
* is the canonical slug to 308 to when the inbound slug isn't canonical (the
|
|
579
|
+
* host app emits the redirect — the SDK never navigates). `geo` is set for
|
|
580
|
+
* place resolutions only.
|
|
581
|
+
*/
|
|
582
|
+
interface TaxonomyResolution {
|
|
583
|
+
object: 'taxonomy_resolution';
|
|
584
|
+
type: 'category' | 'skill' | 'place';
|
|
585
|
+
sourceSlug: string;
|
|
586
|
+
canonicalSlug: string;
|
|
587
|
+
displayName: string;
|
|
588
|
+
redirectTo: string | null;
|
|
589
|
+
geo: TaxonomyGeo | null;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* A place in the board's locations directory (`taxonomy.places.list()` →
|
|
593
|
+
* `GET /places`), the data the `/jobs/locations/` index renders. `jobCount` is
|
|
594
|
+
* subtree-summed (a parent counts its descendants); `id`/`parentId` carry the
|
|
595
|
+
* hierarchy so consumers rebuild the same nested tree the hosted index shows.
|
|
596
|
+
*/
|
|
597
|
+
interface PublicPlace {
|
|
598
|
+
object: 'place';
|
|
599
|
+
/** Stable place identity (locations-tree edge endpoint). */
|
|
600
|
+
id: string;
|
|
601
|
+
/** Parent place's `id`; `null` for a root place. */
|
|
602
|
+
parentId: string | null;
|
|
603
|
+
/** Public slug (links to `/jobs/locations/:slug`); `null` if unslugged. */
|
|
604
|
+
slug: string | null;
|
|
605
|
+
name: string;
|
|
606
|
+
placeType: string;
|
|
607
|
+
countryCode: string | null;
|
|
608
|
+
regionCode: string | null;
|
|
609
|
+
jobCount: number;
|
|
610
|
+
}
|
|
611
|
+
|
|
449
612
|
interface CreateBoardClientOptions {
|
|
450
613
|
baseUrl: string;
|
|
451
614
|
/** Board identifier: `pk_…` key (provisioned default) | `boards_…` ID | slug. */
|
|
@@ -490,15 +653,16 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
|
|
|
490
653
|
*/
|
|
491
654
|
context(options?: FetchOptions): Promise<PublicBoard>;
|
|
492
655
|
jobs: {
|
|
493
|
-
list(query?: JobsListQuery, options?: FetchOptions): Promise<
|
|
656
|
+
list(query?: JobsListQuery, options?: FetchOptions): Promise<JobCardListEnvelope>;
|
|
494
657
|
retrieve(jobSlug: string, query?: Record<string, never>, options?: FetchOptions): Promise<PublicJob>;
|
|
495
|
-
search(body: JobsSearchBody, query?: Record<string, never>, options?: FetchOptions): Promise<
|
|
658
|
+
search(body: JobsSearchBody, query?: Record<string, never>, options?: FetchOptions): Promise<JobCardSearchEnvelope>;
|
|
659
|
+
similar(jobSlug: string, query?: JobsSimilarQuery, options?: FetchOptions): Promise<ListEnvelope<PublicJobCard>>;
|
|
496
660
|
};
|
|
497
661
|
companies: {
|
|
498
662
|
list(query?: CompaniesListQuery, options?: FetchOptions): Promise<ListEnvelope<PublicCompany>>;
|
|
499
663
|
retrieve(companySlug: string, query?: Record<string, never>, options?: FetchOptions): Promise<PublicCompany>;
|
|
500
664
|
search(body: CompaniesSearchBody, query?: Record<string, never>, options?: FetchOptions): Promise<SearchEnvelope<PublicCompany>>;
|
|
501
|
-
listJobs(companySlug: string, query?: CompanyJobsListQuery, options?: FetchOptions): Promise<
|
|
665
|
+
listJobs(companySlug: string, query?: CompanyJobsListQuery, options?: FetchOptions): Promise<JobCardListEnvelope>;
|
|
502
666
|
};
|
|
503
667
|
blog: {
|
|
504
668
|
posts: {
|
|
@@ -532,7 +696,19 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
|
|
|
532
696
|
unsave(jobId: string, query?: Record<string, never>, options?: FetchOptions): Promise<void>;
|
|
533
697
|
};
|
|
534
698
|
};
|
|
699
|
+
taxonomy: {
|
|
700
|
+
categories: {
|
|
701
|
+
resolve(slug: string, options?: FetchOptions): Promise<TaxonomyResolution>;
|
|
702
|
+
};
|
|
703
|
+
skills: {
|
|
704
|
+
resolve(slug: string, options?: FetchOptions): Promise<TaxonomyResolution>;
|
|
705
|
+
};
|
|
706
|
+
places: {
|
|
707
|
+
list(options?: FetchOptions): Promise<ListEnvelope<PublicPlace>>;
|
|
708
|
+
resolve(slug: string, options?: FetchOptions): Promise<TaxonomyResolution>;
|
|
709
|
+
};
|
|
710
|
+
};
|
|
535
711
|
};
|
|
536
712
|
type BoardSdk = ReturnType<typeof createBoardClient>;
|
|
537
713
|
|
|
538
|
-
export { ACCESS_TOKEN_KEY, type Awaitable, type BlogAuthorEmbed, type BlogPostsListQuery, type BlogSearchBody, type BlogTagEmbed, BoardApiError, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardUser, type CompaniesListQuery, type CompaniesSearchBody, type CompanyJobsListQuery, type CreateBoardClientOptions, type CustomStorage, type EducationRequirement, type EmploymentType, type FetchOptions, type ForgotPasswordBody, type JobCompany, type JobsListQuery, type JobsSearchBody, type ListEnvelope, type Logger, type LoginBody, type LogoutBody, type OfficeLocation, type PublicBlogAuthor, type PublicBlogPost, type PublicBlogPostSummary, type PublicBlogTag, type PublicBoard, type PublicBoardAnalytics, type PublicBoardFeatures, type PublicBoardTheme, type PublicCompany, type PublicJob, REFRESH_TOKEN_KEY, type RefreshBody, type RegisterBody, type RemoteOption, type RemotePermit, type RemoteTimezone, type ResetPasswordBody, SDK_VERSION, type SaveJobBody, type SavedJob, type SavedJobsListQuery, type SearchEnvelope, type Seniority, type StorageMode, type VerifyEmailBody, createBoardClient, isBoardApiError, isConflict, isForbidden, isNotFound, isRateLimited, isUnauthorized, isValidationError };
|
|
714
|
+
export { ACCESS_TOKEN_KEY, type Awaitable, type BlogAuthorEmbed, type BlogPostsListQuery, type BlogSearchBody, type BlogTagEmbed, BoardApiError, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardUser, type CompaniesListQuery, type CompaniesSearchBody, type CompanyJobsListQuery, type CreateBoardClientOptions, type CustomStorage, type EducationRequirement, type EmploymentType, type FetchOptions, type ForgotPasswordBody, type JobCardListEnvelope, type JobCardSearchEnvelope, type JobCompany, type JobsListQuery, type JobsSearchBody, type ListEnvelope, type Logger, type LoginBody, type LogoutBody, type OfficeLocation, type PublicBlogAuthor, type PublicBlogPost, type PublicBlogPostSummary, type PublicBlogTag, type PublicBoard, type PublicBoardAnalytics, type PublicBoardFeatures, type PublicBoardTheme, type PublicCompany, type PublicJob, type PublicJobCard, type PublicPlace, REFRESH_TOKEN_KEY, type RefreshBody, type RegisterBody, type RelatedSearch, type RemoteOption, type RemotePermit, type RemoteTimezone, type ResetPasswordBody, SDK_VERSION, type SaveJobBody, type SavedJob, type SavedJobsListQuery, type SearchEnvelope, type Seniority, type StorageMode, type StorefrontPagination, type TaxonomyGeo, type TaxonomyResolution, type VerifyEmailBody, createBoardClient, isBoardApiError, isConflict, isForbidden, isNotFound, isRateLimited, isUnauthorized, isValidationError };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe-shaped success envelopes (`01-conventions.md` §5.1). The
|
|
3
|
+
* server MAY add top-level fields; consumers MUST ignore unknown
|
|
4
|
+
* fields.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Medusa-style storefront pagination fields (ADR-0037 §7), populated only by
|
|
8
|
+
* the board jobs catalog reads (browse / search / company-jobs); absent on
|
|
9
|
+
* every other list/search. `nextCursor` is preserved alongside (offset-encoded).
|
|
10
|
+
*/
|
|
11
|
+
interface StorefrontPagination {
|
|
12
|
+
/** Total matching results ("X jobs"). */
|
|
13
|
+
count?: number;
|
|
14
|
+
/** The page size used for this response. */
|
|
15
|
+
limit?: number;
|
|
16
|
+
/** Number of items skipped before this page. */
|
|
17
|
+
offset?: number;
|
|
18
|
+
/** Items hidden behind the candidate paywall for the current viewer; absent/0 when entitled. */
|
|
19
|
+
gatedCount?: number;
|
|
20
|
+
}
|
|
21
|
+
interface ListEnvelope<T> extends StorefrontPagination {
|
|
22
|
+
object: 'list';
|
|
23
|
+
url: string;
|
|
24
|
+
hasMore: boolean;
|
|
25
|
+
/** `null` when `hasMore` is false — always present, never undefined. */
|
|
26
|
+
nextCursor: string | null;
|
|
27
|
+
data: T[];
|
|
28
|
+
}
|
|
29
|
+
interface SearchEnvelope<T> extends StorefrontPagination {
|
|
30
|
+
object: 'search_result';
|
|
31
|
+
url: string;
|
|
32
|
+
hasMore: boolean;
|
|
33
|
+
nextCursor: string | null;
|
|
34
|
+
data: T[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type RemoteOption = 'on_site' | 'hybrid' | 'remote';
|
|
38
|
+
type EmploymentType = 'full_time' | 'part_time' | 'contract' | 'internship' | 'temporary' | 'volunteer' | 'other';
|
|
39
|
+
type Seniority = 'entry_level' | 'associate' | 'mid_level' | 'senior' | 'lead' | 'principal' | 'director' | 'executive';
|
|
40
|
+
type EducationRequirement = 'high_school' | 'associate_degree' | 'bachelor_degree' | 'professional_certificate' | 'postgraduate_degree' | 'no_requirements';
|
|
41
|
+
interface OfficeLocation {
|
|
42
|
+
countryCode: string | null;
|
|
43
|
+
country: string | null;
|
|
44
|
+
locality: string | null;
|
|
45
|
+
city: string | null;
|
|
46
|
+
region: string | null;
|
|
47
|
+
regionCode: string | null;
|
|
48
|
+
postalCode: string | null;
|
|
49
|
+
displayName: string | null;
|
|
50
|
+
}
|
|
51
|
+
interface JobCompany {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string | null;
|
|
54
|
+
slug: string | null;
|
|
55
|
+
logoUrl: string | null;
|
|
56
|
+
website: string | null;
|
|
57
|
+
}
|
|
58
|
+
interface RemotePermit {
|
|
59
|
+
type: string;
|
|
60
|
+
value: string;
|
|
61
|
+
}
|
|
62
|
+
interface RemoteTimezone {
|
|
63
|
+
type: string;
|
|
64
|
+
value: string;
|
|
65
|
+
plusMinus?: number;
|
|
66
|
+
}
|
|
67
|
+
interface PublicJob {
|
|
68
|
+
id: string;
|
|
69
|
+
object: 'public_job';
|
|
70
|
+
title: string;
|
|
71
|
+
slug: string | null;
|
|
72
|
+
status: string;
|
|
73
|
+
companyId: string | null;
|
|
74
|
+
employmentType: string | null;
|
|
75
|
+
remoteOption: string | null;
|
|
76
|
+
seniority: string | null;
|
|
77
|
+
salaryMin: number | null;
|
|
78
|
+
salaryMax: number | null;
|
|
79
|
+
salaryCurrency: string | null;
|
|
80
|
+
salaryTimeframe: string | null;
|
|
81
|
+
isFeatured: boolean;
|
|
82
|
+
publishedAt: string | null;
|
|
83
|
+
expiresAt: string | null;
|
|
84
|
+
createdAt: string;
|
|
85
|
+
updatedAt: string;
|
|
86
|
+
description: string | null;
|
|
87
|
+
applicationUrl: string | null;
|
|
88
|
+
/** Canonical hierarchical permit selection. */
|
|
89
|
+
remotePermits: RemotePermit[];
|
|
90
|
+
/** Read-only — derived from `remotePermits`. */
|
|
91
|
+
remoteWorldwide: boolean | null;
|
|
92
|
+
/** Canonical hierarchical timezone selection. */
|
|
93
|
+
remoteTimezones: RemoteTimezone[];
|
|
94
|
+
/** Read-only — derived from `remoteTimezones`. */
|
|
95
|
+
remoteAllowedTzOffsets: number[];
|
|
96
|
+
/** Read-only — derived from `remotePermits`. */
|
|
97
|
+
remoteWorkPermitCountryCodes: string[];
|
|
98
|
+
/** Read-only — derived from `remotePermits`. */
|
|
99
|
+
remoteWorkPermitSubdivisionCodes: string[];
|
|
100
|
+
remoteSponsorship: 'yes' | 'no' | 'unknown';
|
|
101
|
+
educationRequirements: EducationRequirement[];
|
|
102
|
+
experienceMonths: number | null;
|
|
103
|
+
experienceInPlaceOfEducation: boolean | null;
|
|
104
|
+
inOfficePeriod: 'per_week' | 'per_month' | 'per_year' | null;
|
|
105
|
+
inOfficeFrequency: number | null;
|
|
106
|
+
company: JobCompany | null;
|
|
107
|
+
officeLocations: OfficeLocation[];
|
|
108
|
+
/** Resolved taxonomy — same `{slug,name}` shape as `PublicJobCard`; names joined server-side. */
|
|
109
|
+
categories: Array<{
|
|
110
|
+
slug: string;
|
|
111
|
+
name: string;
|
|
112
|
+
}>;
|
|
113
|
+
skills: Array<{
|
|
114
|
+
slug: string;
|
|
115
|
+
name: string;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Place ancestor chain (country → region → city) for the breadcrumb. Each
|
|
119
|
+
* `slug` is the English SOURCE slug — the key `taxonomy.places.resolve()`
|
|
120
|
+
* accepts. On a localized board it may differ from the canonical
|
|
121
|
+
* board-language URL slug (the board router 308-redirects the source slug to
|
|
122
|
+
* the canonical one); link via `/jobs/locations/:slug`.
|
|
123
|
+
*/
|
|
124
|
+
placeHierarchy: Array<{
|
|
125
|
+
slug: string;
|
|
126
|
+
name: string;
|
|
127
|
+
}>;
|
|
128
|
+
links: {
|
|
129
|
+
public: string | null;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The slim listing card (ADR-0037 §1) returned by `jobs.list` / `jobs.search`
|
|
134
|
+
* / `companies.listJobs`. Full enrichment (description, officeLocations, the
|
|
135
|
+
* structured remote blocks, …) lives on `jobs.retrieve` (`PublicJob`).
|
|
136
|
+
* Transcribed from `serializeJobCard`.
|
|
137
|
+
*/
|
|
138
|
+
interface PublicJobCard {
|
|
139
|
+
id: string;
|
|
140
|
+
object: 'job_card';
|
|
141
|
+
slug: string;
|
|
142
|
+
title: string;
|
|
143
|
+
publishedAt: string | null;
|
|
144
|
+
employmentType: string | null;
|
|
145
|
+
remoteOption: string | null;
|
|
146
|
+
/** Remote-region label for remote jobs (e.g. "Worldwide"); `null` otherwise. */
|
|
147
|
+
remoteLocationLabel: string | null;
|
|
148
|
+
salaryMin: number | null;
|
|
149
|
+
salaryMax: number | null;
|
|
150
|
+
salaryCurrency: string | null;
|
|
151
|
+
salaryTimeframe: string | null;
|
|
152
|
+
isFeatured: boolean;
|
|
153
|
+
locationLabel: string | null;
|
|
154
|
+
company: {
|
|
155
|
+
slug: string;
|
|
156
|
+
name: string;
|
|
157
|
+
logoUrl: string | null;
|
|
158
|
+
} | null;
|
|
159
|
+
categories: Array<{
|
|
160
|
+
slug: string;
|
|
161
|
+
name: string;
|
|
162
|
+
}>;
|
|
163
|
+
skills: Array<{
|
|
164
|
+
slug: string;
|
|
165
|
+
name: string;
|
|
166
|
+
}>;
|
|
167
|
+
links: {
|
|
168
|
+
public: string | null;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Long-form description (HTML), or `null`. Present ONLY when the list/search
|
|
172
|
+
* was called with `fields: '+description'` (the RSS feed's sparse-fieldset
|
|
173
|
+
* opt-in); `undefined`/absent on the default slim card.
|
|
174
|
+
*/
|
|
175
|
+
description?: string | null;
|
|
176
|
+
}
|
|
177
|
+
/** Derived category/skill suggestion on the jobs browse list (ADR-0037 §8). */
|
|
178
|
+
interface RelatedSearch {
|
|
179
|
+
type: 'category' | 'skill';
|
|
180
|
+
slug: string;
|
|
181
|
+
term: string;
|
|
182
|
+
count: number;
|
|
183
|
+
}
|
|
184
|
+
/** The browse list envelope — `PublicJobCard`s + storefront fields + `relatedSearches`. */
|
|
185
|
+
interface JobCardListEnvelope extends ListEnvelope<PublicJobCard> {
|
|
186
|
+
relatedSearches?: RelatedSearch[];
|
|
187
|
+
}
|
|
188
|
+
/** The search envelope — `PublicJobCard`s + storefront fields. */
|
|
189
|
+
type JobCardSearchEnvelope = SearchEnvelope<PublicJobCard>;
|
|
190
|
+
type JobsListQuery = {
|
|
191
|
+
cursor?: string;
|
|
192
|
+
/** 1–100. */
|
|
193
|
+
limit?: number;
|
|
194
|
+
/** Storefront page offset; takes precedence over `cursor`. `offset + limit` ≤ 10,000. */
|
|
195
|
+
offset?: number;
|
|
196
|
+
/** Single or repeated (up to 10) — repeated params are OR-matched. */
|
|
197
|
+
companyId?: string | string[];
|
|
198
|
+
remoteOption?: RemoteOption | RemoteOption[];
|
|
199
|
+
employmentType?: EmploymentType | EmploymentType[];
|
|
200
|
+
seniority?: Seniority | Seniority[];
|
|
201
|
+
/** Place slug for a geo radius search; unresolvable slugs are ignored. */
|
|
202
|
+
location?: string;
|
|
203
|
+
/** Radius in km around `location` (10–250; default 50). */
|
|
204
|
+
radius?: number;
|
|
205
|
+
/** Category slug seed (the `/jobs/[keyword]` page) — server resolves it to the English source name; unresolvable → 404. */
|
|
206
|
+
category?: string;
|
|
207
|
+
/** Skill slug seed (the `/jobs/skills/[skill]` page) — server-resolved; unresolvable → 404. */
|
|
208
|
+
skill?: string;
|
|
209
|
+
/** Sparse fieldset (Medusa-style `+field`). Only `'+description'` is supported — adds `description` to each card. */
|
|
210
|
+
fields?: string;
|
|
211
|
+
};
|
|
212
|
+
type JobsSimilarQuery = {
|
|
213
|
+
/** How many similar jobs to return (1–20; default 5). */
|
|
214
|
+
limit?: number;
|
|
215
|
+
};
|
|
216
|
+
interface JobsSearchBody {
|
|
217
|
+
/** Free-text query, up to 200 characters. */
|
|
218
|
+
query?: string;
|
|
219
|
+
filters?: {
|
|
220
|
+
/** Up to 10 values each. */
|
|
221
|
+
companyId?: string[];
|
|
222
|
+
remoteOption?: RemoteOption[];
|
|
223
|
+
employmentType?: EmploymentType[];
|
|
224
|
+
seniority?: Seniority[];
|
|
225
|
+
/** ISO 8601 datetime bounds. */
|
|
226
|
+
publishedAt?: {
|
|
227
|
+
gte?: string;
|
|
228
|
+
lte?: string;
|
|
229
|
+
};
|
|
230
|
+
/** Place slug for a geo radius search. */
|
|
231
|
+
location?: string;
|
|
232
|
+
/** Radius in km around `location` (10–250; default 50). */
|
|
233
|
+
radius?: number;
|
|
234
|
+
};
|
|
235
|
+
cursor?: string;
|
|
236
|
+
/** 1–100. */
|
|
237
|
+
limit?: number;
|
|
238
|
+
/** Storefront page offset; takes precedence over `cursor`. */
|
|
239
|
+
offset?: number;
|
|
240
|
+
}
|
|
241
|
+
|
|
1
242
|
type Awaitable<T> = T | Promise<T>;
|
|
2
243
|
/**
|
|
3
244
|
* Async token storage. The SDK reads the access token from storage on
|
|
@@ -151,7 +392,7 @@ declare function isConflict(e: unknown): e is BoardApiError;
|
|
|
151
392
|
* constant because the package is platform-neutral and cannot read
|
|
152
393
|
* package.json at runtime.
|
|
153
394
|
*/
|
|
154
|
-
declare const SDK_VERSION = "1.
|
|
395
|
+
declare const SDK_VERSION = "1.1.0";
|
|
155
396
|
|
|
156
397
|
interface BoardUser {
|
|
157
398
|
id: string;
|
|
@@ -268,27 +509,6 @@ interface BlogSearchBody {
|
|
|
268
509
|
limit?: number;
|
|
269
510
|
}
|
|
270
511
|
|
|
271
|
-
/**
|
|
272
|
-
* Stripe-shaped success envelopes (`01-conventions.md` §5.1). The
|
|
273
|
-
* server MAY add top-level fields; consumers MUST ignore unknown
|
|
274
|
-
* fields.
|
|
275
|
-
*/
|
|
276
|
-
interface ListEnvelope<T> {
|
|
277
|
-
object: 'list';
|
|
278
|
-
url: string;
|
|
279
|
-
hasMore: boolean;
|
|
280
|
-
/** `null` when `hasMore` is false — always present, never undefined. */
|
|
281
|
-
nextCursor: string | null;
|
|
282
|
-
data: T[];
|
|
283
|
-
}
|
|
284
|
-
interface SearchEnvelope<T> {
|
|
285
|
-
object: 'search_result';
|
|
286
|
-
url: string;
|
|
287
|
-
hasMore: boolean;
|
|
288
|
-
nextCursor: string | null;
|
|
289
|
-
data: T[];
|
|
290
|
-
}
|
|
291
|
-
|
|
292
512
|
interface PublicCompany {
|
|
293
513
|
id: string;
|
|
294
514
|
object: 'public_company';
|
|
@@ -321,110 +541,6 @@ interface CompaniesSearchBody {
|
|
|
321
541
|
limit?: number;
|
|
322
542
|
}
|
|
323
543
|
|
|
324
|
-
type RemoteOption = 'on_site' | 'hybrid' | 'remote';
|
|
325
|
-
type EmploymentType = 'full_time' | 'part_time' | 'contract' | 'internship' | 'temporary' | 'volunteer' | 'other';
|
|
326
|
-
type Seniority = 'entry_level' | 'associate' | 'mid_level' | 'senior' | 'lead' | 'principal' | 'director' | 'executive';
|
|
327
|
-
type EducationRequirement = 'high_school' | 'associate_degree' | 'bachelor_degree' | 'professional_certificate' | 'postgraduate_degree' | 'no_requirements';
|
|
328
|
-
interface OfficeLocation {
|
|
329
|
-
countryCode: string | null;
|
|
330
|
-
country: string | null;
|
|
331
|
-
locality: string | null;
|
|
332
|
-
city: string | null;
|
|
333
|
-
region: string | null;
|
|
334
|
-
regionCode: string | null;
|
|
335
|
-
postalCode: string | null;
|
|
336
|
-
displayName: string | null;
|
|
337
|
-
}
|
|
338
|
-
interface JobCompany {
|
|
339
|
-
id: string;
|
|
340
|
-
name: string | null;
|
|
341
|
-
slug: string | null;
|
|
342
|
-
logoUrl: string | null;
|
|
343
|
-
website: string | null;
|
|
344
|
-
}
|
|
345
|
-
interface RemotePermit {
|
|
346
|
-
type: string;
|
|
347
|
-
value: string;
|
|
348
|
-
}
|
|
349
|
-
interface RemoteTimezone {
|
|
350
|
-
type: string;
|
|
351
|
-
value: string;
|
|
352
|
-
plusMinus?: number;
|
|
353
|
-
}
|
|
354
|
-
interface PublicJob {
|
|
355
|
-
id: string;
|
|
356
|
-
object: 'public_job';
|
|
357
|
-
title: string;
|
|
358
|
-
slug: string | null;
|
|
359
|
-
status: string;
|
|
360
|
-
companyId: string | null;
|
|
361
|
-
employmentType: string | null;
|
|
362
|
-
remoteOption: string | null;
|
|
363
|
-
seniority: string | null;
|
|
364
|
-
salaryMin: number | null;
|
|
365
|
-
salaryMax: number | null;
|
|
366
|
-
salaryCurrency: string | null;
|
|
367
|
-
salaryTimeframe: string | null;
|
|
368
|
-
isFeatured: boolean;
|
|
369
|
-
publishedAt: string | null;
|
|
370
|
-
expiresAt: string | null;
|
|
371
|
-
createdAt: string;
|
|
372
|
-
updatedAt: string;
|
|
373
|
-
description: string | null;
|
|
374
|
-
applicationUrl: string | null;
|
|
375
|
-
/** Canonical hierarchical permit selection. */
|
|
376
|
-
remotePermits: RemotePermit[];
|
|
377
|
-
/** Read-only — derived from `remotePermits`. */
|
|
378
|
-
remoteWorldwide: boolean | null;
|
|
379
|
-
/** Canonical hierarchical timezone selection. */
|
|
380
|
-
remoteTimezones: RemoteTimezone[];
|
|
381
|
-
/** Read-only — derived from `remoteTimezones`. */
|
|
382
|
-
remoteAllowedTzOffsets: number[];
|
|
383
|
-
/** Read-only — derived from `remotePermits`. */
|
|
384
|
-
remoteWorkPermitCountryCodes: string[];
|
|
385
|
-
/** Read-only — derived from `remotePermits`. */
|
|
386
|
-
remoteWorkPermitSubdivisionCodes: string[];
|
|
387
|
-
remoteSponsorship: 'yes' | 'no' | 'unknown';
|
|
388
|
-
educationRequirements: EducationRequirement[];
|
|
389
|
-
experienceMonths: number | null;
|
|
390
|
-
experienceInPlaceOfEducation: boolean | null;
|
|
391
|
-
inOfficePeriod: 'per_week' | 'per_month' | 'per_year' | null;
|
|
392
|
-
inOfficeFrequency: number | null;
|
|
393
|
-
company: JobCompany | null;
|
|
394
|
-
officeLocations: OfficeLocation[];
|
|
395
|
-
links: {
|
|
396
|
-
public: string | null;
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
type JobsListQuery = {
|
|
400
|
-
cursor?: string;
|
|
401
|
-
/** 1–100. */
|
|
402
|
-
limit?: number;
|
|
403
|
-
companyId?: string;
|
|
404
|
-
remoteOption?: RemoteOption;
|
|
405
|
-
employmentType?: EmploymentType;
|
|
406
|
-
seniority?: Seniority;
|
|
407
|
-
};
|
|
408
|
-
interface JobsSearchBody {
|
|
409
|
-
/** Free-text query, up to 200 characters. */
|
|
410
|
-
query?: string;
|
|
411
|
-
filters?: {
|
|
412
|
-
/** Up to 10 values each. */
|
|
413
|
-
companyId?: string[];
|
|
414
|
-
remoteOption?: RemoteOption[];
|
|
415
|
-
employmentType?: EmploymentType[];
|
|
416
|
-
seniority?: Seniority[];
|
|
417
|
-
/** ISO 8601 datetime bounds. */
|
|
418
|
-
publishedAt?: {
|
|
419
|
-
gte?: string;
|
|
420
|
-
lte?: string;
|
|
421
|
-
};
|
|
422
|
-
};
|
|
423
|
-
cursor?: string;
|
|
424
|
-
/** 1–100. */
|
|
425
|
-
limit?: number;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
544
|
/**
|
|
429
545
|
* The embedded `job` is the SAME `public_job` shape the anonymous jobs
|
|
430
546
|
* list emits — saved rows and search rows render with one component.
|
|
@@ -446,6 +562,53 @@ interface SaveJobBody {
|
|
|
446
562
|
jobId: string;
|
|
447
563
|
}
|
|
448
564
|
|
|
565
|
+
interface TaxonomyGeo {
|
|
566
|
+
lat: number | null;
|
|
567
|
+
lng: number | null;
|
|
568
|
+
countryCode: string | null;
|
|
569
|
+
regionCode: string | null;
|
|
570
|
+
region: string | null;
|
|
571
|
+
city: string | null;
|
|
572
|
+
locality: string | null;
|
|
573
|
+
placeType: string | null;
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Page-meta for a resolved taxonomy slug. `sourceSlug` is the immutable
|
|
577
|
+
* English search key; `canonicalSlug` is the board-language URL; `redirectTo`
|
|
578
|
+
* is the canonical slug to 308 to when the inbound slug isn't canonical (the
|
|
579
|
+
* host app emits the redirect — the SDK never navigates). `geo` is set for
|
|
580
|
+
* place resolutions only.
|
|
581
|
+
*/
|
|
582
|
+
interface TaxonomyResolution {
|
|
583
|
+
object: 'taxonomy_resolution';
|
|
584
|
+
type: 'category' | 'skill' | 'place';
|
|
585
|
+
sourceSlug: string;
|
|
586
|
+
canonicalSlug: string;
|
|
587
|
+
displayName: string;
|
|
588
|
+
redirectTo: string | null;
|
|
589
|
+
geo: TaxonomyGeo | null;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* A place in the board's locations directory (`taxonomy.places.list()` →
|
|
593
|
+
* `GET /places`), the data the `/jobs/locations/` index renders. `jobCount` is
|
|
594
|
+
* subtree-summed (a parent counts its descendants); `id`/`parentId` carry the
|
|
595
|
+
* hierarchy so consumers rebuild the same nested tree the hosted index shows.
|
|
596
|
+
*/
|
|
597
|
+
interface PublicPlace {
|
|
598
|
+
object: 'place';
|
|
599
|
+
/** Stable place identity (locations-tree edge endpoint). */
|
|
600
|
+
id: string;
|
|
601
|
+
/** Parent place's `id`; `null` for a root place. */
|
|
602
|
+
parentId: string | null;
|
|
603
|
+
/** Public slug (links to `/jobs/locations/:slug`); `null` if unslugged. */
|
|
604
|
+
slug: string | null;
|
|
605
|
+
name: string;
|
|
606
|
+
placeType: string;
|
|
607
|
+
countryCode: string | null;
|
|
608
|
+
regionCode: string | null;
|
|
609
|
+
jobCount: number;
|
|
610
|
+
}
|
|
611
|
+
|
|
449
612
|
interface CreateBoardClientOptions {
|
|
450
613
|
baseUrl: string;
|
|
451
614
|
/** Board identifier: `pk_…` key (provisioned default) | `boards_…` ID | slug. */
|
|
@@ -490,15 +653,16 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
|
|
|
490
653
|
*/
|
|
491
654
|
context(options?: FetchOptions): Promise<PublicBoard>;
|
|
492
655
|
jobs: {
|
|
493
|
-
list(query?: JobsListQuery, options?: FetchOptions): Promise<
|
|
656
|
+
list(query?: JobsListQuery, options?: FetchOptions): Promise<JobCardListEnvelope>;
|
|
494
657
|
retrieve(jobSlug: string, query?: Record<string, never>, options?: FetchOptions): Promise<PublicJob>;
|
|
495
|
-
search(body: JobsSearchBody, query?: Record<string, never>, options?: FetchOptions): Promise<
|
|
658
|
+
search(body: JobsSearchBody, query?: Record<string, never>, options?: FetchOptions): Promise<JobCardSearchEnvelope>;
|
|
659
|
+
similar(jobSlug: string, query?: JobsSimilarQuery, options?: FetchOptions): Promise<ListEnvelope<PublicJobCard>>;
|
|
496
660
|
};
|
|
497
661
|
companies: {
|
|
498
662
|
list(query?: CompaniesListQuery, options?: FetchOptions): Promise<ListEnvelope<PublicCompany>>;
|
|
499
663
|
retrieve(companySlug: string, query?: Record<string, never>, options?: FetchOptions): Promise<PublicCompany>;
|
|
500
664
|
search(body: CompaniesSearchBody, query?: Record<string, never>, options?: FetchOptions): Promise<SearchEnvelope<PublicCompany>>;
|
|
501
|
-
listJobs(companySlug: string, query?: CompanyJobsListQuery, options?: FetchOptions): Promise<
|
|
665
|
+
listJobs(companySlug: string, query?: CompanyJobsListQuery, options?: FetchOptions): Promise<JobCardListEnvelope>;
|
|
502
666
|
};
|
|
503
667
|
blog: {
|
|
504
668
|
posts: {
|
|
@@ -532,7 +696,19 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
|
|
|
532
696
|
unsave(jobId: string, query?: Record<string, never>, options?: FetchOptions): Promise<void>;
|
|
533
697
|
};
|
|
534
698
|
};
|
|
699
|
+
taxonomy: {
|
|
700
|
+
categories: {
|
|
701
|
+
resolve(slug: string, options?: FetchOptions): Promise<TaxonomyResolution>;
|
|
702
|
+
};
|
|
703
|
+
skills: {
|
|
704
|
+
resolve(slug: string, options?: FetchOptions): Promise<TaxonomyResolution>;
|
|
705
|
+
};
|
|
706
|
+
places: {
|
|
707
|
+
list(options?: FetchOptions): Promise<ListEnvelope<PublicPlace>>;
|
|
708
|
+
resolve(slug: string, options?: FetchOptions): Promise<TaxonomyResolution>;
|
|
709
|
+
};
|
|
710
|
+
};
|
|
535
711
|
};
|
|
536
712
|
type BoardSdk = ReturnType<typeof createBoardClient>;
|
|
537
713
|
|
|
538
|
-
export { ACCESS_TOKEN_KEY, type Awaitable, type BlogAuthorEmbed, type BlogPostsListQuery, type BlogSearchBody, type BlogTagEmbed, BoardApiError, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardUser, type CompaniesListQuery, type CompaniesSearchBody, type CompanyJobsListQuery, type CreateBoardClientOptions, type CustomStorage, type EducationRequirement, type EmploymentType, type FetchOptions, type ForgotPasswordBody, type JobCompany, type JobsListQuery, type JobsSearchBody, type ListEnvelope, type Logger, type LoginBody, type LogoutBody, type OfficeLocation, type PublicBlogAuthor, type PublicBlogPost, type PublicBlogPostSummary, type PublicBlogTag, type PublicBoard, type PublicBoardAnalytics, type PublicBoardFeatures, type PublicBoardTheme, type PublicCompany, type PublicJob, REFRESH_TOKEN_KEY, type RefreshBody, type RegisterBody, type RemoteOption, type RemotePermit, type RemoteTimezone, type ResetPasswordBody, SDK_VERSION, type SaveJobBody, type SavedJob, type SavedJobsListQuery, type SearchEnvelope, type Seniority, type StorageMode, type VerifyEmailBody, createBoardClient, isBoardApiError, isConflict, isForbidden, isNotFound, isRateLimited, isUnauthorized, isValidationError };
|
|
714
|
+
export { ACCESS_TOKEN_KEY, type Awaitable, type BlogAuthorEmbed, type BlogPostsListQuery, type BlogSearchBody, type BlogTagEmbed, BoardApiError, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardUser, type CompaniesListQuery, type CompaniesSearchBody, type CompanyJobsListQuery, type CreateBoardClientOptions, type CustomStorage, type EducationRequirement, type EmploymentType, type FetchOptions, type ForgotPasswordBody, type JobCardListEnvelope, type JobCardSearchEnvelope, type JobCompany, type JobsListQuery, type JobsSearchBody, type ListEnvelope, type Logger, type LoginBody, type LogoutBody, type OfficeLocation, type PublicBlogAuthor, type PublicBlogPost, type PublicBlogPostSummary, type PublicBlogTag, type PublicBoard, type PublicBoardAnalytics, type PublicBoardFeatures, type PublicBoardTheme, type PublicCompany, type PublicJob, type PublicJobCard, type PublicPlace, REFRESH_TOKEN_KEY, type RefreshBody, type RegisterBody, type RelatedSearch, type RemoteOption, type RemotePermit, type RemoteTimezone, type ResetPasswordBody, SDK_VERSION, type SaveJobBody, type SavedJob, type SavedJobsListQuery, type SearchEnvelope, type Seniority, type StorageMode, type StorefrontPagination, type TaxonomyGeo, type TaxonomyResolution, type VerifyEmailBody, createBoardClient, isBoardApiError, isConflict, isForbidden, isNotFound, isRateLimited, isUnauthorized, isValidationError };
|
package/dist/index.js
CHANGED
|
@@ -143,7 +143,7 @@ async function clearSession(storage) {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
// src/version.ts
|
|
146
|
-
var SDK_VERSION = "1.
|
|
146
|
+
var SDK_VERSION = "1.1.0";
|
|
147
147
|
|
|
148
148
|
// src/client.ts
|
|
149
149
|
function isRawBody(body) {
|
|
@@ -544,6 +544,23 @@ function jobsNamespace(client) {
|
|
|
544
544
|
body,
|
|
545
545
|
query
|
|
546
546
|
});
|
|
547
|
+
},
|
|
548
|
+
/**
|
|
549
|
+
* List jobs similar to one job — the same ranking that powers the
|
|
550
|
+
* on-page similar-jobs rail. Returns up to `limit` slim cards (default
|
|
551
|
+
* 5), excluding the job itself and any role at the same company.
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* const { data } = await board.jobs.similar('senior-chef', { limit: 5 });
|
|
555
|
+
*/
|
|
556
|
+
similar(jobSlug, query, options) {
|
|
557
|
+
return client.fetch(
|
|
558
|
+
`/jobs/${encodeURIComponent(jobSlug)}/similar`,
|
|
559
|
+
{
|
|
560
|
+
...options,
|
|
561
|
+
query
|
|
562
|
+
}
|
|
563
|
+
);
|
|
547
564
|
}
|
|
548
565
|
};
|
|
549
566
|
}
|
|
@@ -608,6 +625,35 @@ function meNamespace(client) {
|
|
|
608
625
|
};
|
|
609
626
|
}
|
|
610
627
|
|
|
628
|
+
// src/namespaces/taxonomy.ts
|
|
629
|
+
function taxonomyResolver(client, kind) {
|
|
630
|
+
return {
|
|
631
|
+
/**
|
|
632
|
+
* Resolve a (board-language or English) taxonomy slug to its page-meta.
|
|
633
|
+
* Rejects with a `not_found` `BoardApiError` when the slug doesn't resolve.
|
|
634
|
+
*/
|
|
635
|
+
resolve(slug, options) {
|
|
636
|
+
return client.fetch(
|
|
637
|
+
`/${kind}/${encodeURIComponent(slug)}`,
|
|
638
|
+
options
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
function taxonomyNamespace(client) {
|
|
644
|
+
return {
|
|
645
|
+
categories: taxonomyResolver(client, "categories"),
|
|
646
|
+
skills: taxonomyResolver(client, "skills"),
|
|
647
|
+
places: {
|
|
648
|
+
...taxonomyResolver(client, "places"),
|
|
649
|
+
/** List every place used by a published job, with its live job count. */
|
|
650
|
+
list(options) {
|
|
651
|
+
return client.fetch("/places", options);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
|
|
611
657
|
// src/index.ts
|
|
612
658
|
function createBoardClient(options) {
|
|
613
659
|
const client = new BoardClient({
|
|
@@ -639,6 +685,7 @@ function createBoardClient(options) {
|
|
|
639
685
|
companies: companiesNamespace(client),
|
|
640
686
|
blog: blogNamespace(client),
|
|
641
687
|
auth: authNamespace(client),
|
|
642
|
-
me: meNamespace(client)
|
|
688
|
+
me: meNamespace(client),
|
|
689
|
+
taxonomy: taxonomyNamespace(client)
|
|
643
690
|
};
|
|
644
691
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -105,7 +105,7 @@ async function clearSession(storage) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// src/version.ts
|
|
108
|
-
var SDK_VERSION = "1.
|
|
108
|
+
var SDK_VERSION = "1.1.0";
|
|
109
109
|
|
|
110
110
|
// src/client.ts
|
|
111
111
|
function isRawBody(body) {
|
|
@@ -506,6 +506,23 @@ function jobsNamespace(client) {
|
|
|
506
506
|
body,
|
|
507
507
|
query
|
|
508
508
|
});
|
|
509
|
+
},
|
|
510
|
+
/**
|
|
511
|
+
* List jobs similar to one job — the same ranking that powers the
|
|
512
|
+
* on-page similar-jobs rail. Returns up to `limit` slim cards (default
|
|
513
|
+
* 5), excluding the job itself and any role at the same company.
|
|
514
|
+
*
|
|
515
|
+
* @example
|
|
516
|
+
* const { data } = await board.jobs.similar('senior-chef', { limit: 5 });
|
|
517
|
+
*/
|
|
518
|
+
similar(jobSlug, query, options) {
|
|
519
|
+
return client.fetch(
|
|
520
|
+
`/jobs/${encodeURIComponent(jobSlug)}/similar`,
|
|
521
|
+
{
|
|
522
|
+
...options,
|
|
523
|
+
query
|
|
524
|
+
}
|
|
525
|
+
);
|
|
509
526
|
}
|
|
510
527
|
};
|
|
511
528
|
}
|
|
@@ -570,6 +587,35 @@ function meNamespace(client) {
|
|
|
570
587
|
};
|
|
571
588
|
}
|
|
572
589
|
|
|
590
|
+
// src/namespaces/taxonomy.ts
|
|
591
|
+
function taxonomyResolver(client, kind) {
|
|
592
|
+
return {
|
|
593
|
+
/**
|
|
594
|
+
* Resolve a (board-language or English) taxonomy slug to its page-meta.
|
|
595
|
+
* Rejects with a `not_found` `BoardApiError` when the slug doesn't resolve.
|
|
596
|
+
*/
|
|
597
|
+
resolve(slug, options) {
|
|
598
|
+
return client.fetch(
|
|
599
|
+
`/${kind}/${encodeURIComponent(slug)}`,
|
|
600
|
+
options
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
function taxonomyNamespace(client) {
|
|
606
|
+
return {
|
|
607
|
+
categories: taxonomyResolver(client, "categories"),
|
|
608
|
+
skills: taxonomyResolver(client, "skills"),
|
|
609
|
+
places: {
|
|
610
|
+
...taxonomyResolver(client, "places"),
|
|
611
|
+
/** List every place used by a published job, with its live job count. */
|
|
612
|
+
list(options) {
|
|
613
|
+
return client.fetch("/places", options);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
|
|
573
619
|
// src/index.ts
|
|
574
620
|
function createBoardClient(options) {
|
|
575
621
|
const client = new BoardClient({
|
|
@@ -601,7 +647,8 @@ function createBoardClient(options) {
|
|
|
601
647
|
companies: companiesNamespace(client),
|
|
602
648
|
blog: blogNamespace(client),
|
|
603
649
|
auth: authNamespace(client),
|
|
604
|
-
me: meNamespace(client)
|
|
650
|
+
me: meNamespace(client),
|
|
651
|
+
taxonomy: taxonomyNamespace(client)
|
|
605
652
|
};
|
|
606
653
|
}
|
|
607
654
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cavuno/board",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Typed isomorphic client for the Cavuno Board API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,17 +33,18 @@
|
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"@types/node": "24.9.1",
|
|
38
|
-
"tsup": "^8.4.0",
|
|
39
|
-
"vitest": "^2.1.9",
|
|
40
|
-
"@kit/tsconfig": "0.1.0"
|
|
41
|
-
},
|
|
42
36
|
"scripts": {
|
|
43
37
|
"build": "tsup",
|
|
44
38
|
"clean": "git clean -xdf .turbo dist node_modules",
|
|
45
39
|
"typecheck": "tsgo --noEmit",
|
|
46
40
|
"test": "vitest run",
|
|
47
|
-
"assert-publish-target": "node -e \"const p=require('./package.json'); if(p.name!=='@cavuno/board'){throw new Error('Refusing to publish: package.json name is '+p.name+', expected @cavuno/board')}; if(p.private){throw new Error('Refusing to publish: package.json has private:true')}\""
|
|
41
|
+
"assert-publish-target": "node -e \"const p=require('./package.json'); if(p.name!=='@cavuno/board'){throw new Error('Refusing to publish: package.json name is '+p.name+', expected @cavuno/board')}; if(p.private){throw new Error('Refusing to publish: package.json has private:true')}\"",
|
|
42
|
+
"prepublishOnly": "pnpm run assert-publish-target && pnpm run build"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@kit/tsconfig": "workspace:*",
|
|
46
|
+
"@types/node": "catalog:",
|
|
47
|
+
"tsup": "^8.4.0",
|
|
48
|
+
"vitest": "^2.1.9"
|
|
48
49
|
}
|
|
49
|
-
}
|
|
50
|
+
}
|