@cavuno/board 3.1.0 → 3.2.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 +15 -0
- package/dist/blog-DGBHmExV.d.mts +29 -0
- package/dist/blog-iV9XEIGf.d.ts +29 -0
- package/dist/{salaries-ChSqDBAM.d.mts → board-BJbXd_9_.d.mts} +14 -27
- package/dist/{salaries-BahBpxWT.d.ts → board-JhdUWIoq.d.ts} +14 -27
- package/dist/breadcrumbs-1hMjcsqA.d.mts +171 -0
- package/dist/breadcrumbs-DexU07TT.d.ts +171 -0
- package/dist/chunk-2ETP5UH4.mjs +271 -0
- package/dist/chunk-DLSO6XXY.mjs +33 -0
- package/dist/chunk-IJCJ26SQ.mjs +596 -0
- package/dist/chunk-L7ZOYWHW.mjs +98 -0
- package/dist/chunk-LUGJWOT7.mjs +96 -0
- package/dist/chunk-NXY3OWGF.mjs +1060 -0
- package/dist/chunk-STE77MAT.mjs +844 -0
- package/dist/filters.mjs +7 -668
- package/dist/format.d.mts +2 -1
- package/dist/format.d.ts +2 -1
- package/dist/format.js +592 -523
- package/dist/format.mjs +19 -680
- package/dist/go.mjs +4 -29
- package/dist/index.d.mts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1 -1
- package/dist/index.mjs +22 -278
- package/dist/paths.mjs +20 -77
- package/dist/route-contract.mjs +30 -1079
- package/dist/seo.d.mts +14 -171
- package/dist/seo.d.ts +14 -171
- package/dist/seo.js +1 -1
- package/dist/seo.mjs +24 -1399
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.mjs +5 -31
- package/dist/sitemap.d.mts +2 -2
- package/dist/sitemap.d.ts +2 -2
- package/dist/sitemap.mjs +20 -96
- package/dist/well-known.mjs +4 -421
- package/package.json +6 -3
- package/skills/manifest.json +1 -1
- package/dist/board-NE98PlwN.d.ts +0 -16
- package/dist/board-muu8BI8P.d.mts +0 -16
package/dist/server.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BoardSdk } from './index.mjs';
|
|
2
2
|
import './_spec-nkWAraS0.mjs';
|
|
3
3
|
import './search-CCyFWPi3.mjs';
|
|
4
|
-
import './board-
|
|
4
|
+
import './board-BJbXd_9_.mjs';
|
|
5
5
|
import './jobs-lVvKCBCU.mjs';
|
|
6
|
-
import './
|
|
6
|
+
import './blog-DGBHmExV.mjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Session cookie codec — pure (no framework imports, no node imports) so it
|
package/dist/server.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BoardSdk } from './index.js';
|
|
2
2
|
import './_spec-nkWAraS0.js';
|
|
3
3
|
import './search-CyRvVMUp.js';
|
|
4
|
-
import './board-
|
|
4
|
+
import './board-JhdUWIoq.js';
|
|
5
5
|
import './jobs-BiEvL9d7.js';
|
|
6
|
-
import './
|
|
6
|
+
import './blog-iV9XEIGf.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Session cookie codec — pure (no framework imports, no node imports) so it
|
package/dist/server.mjs
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
const sanitized = board.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8
|
-
return `${sanitized}-${hash.toString(36)}`;
|
|
9
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
isNoStore,
|
|
3
|
+
isUnauthorized,
|
|
4
|
+
scopeToken
|
|
5
|
+
} from "./chunk-2ETP5UH4.mjs";
|
|
10
6
|
|
|
11
7
|
// src/server/cookie.ts
|
|
12
8
|
var COOKIE_ATTRIBUTES = "Path=/; HttpOnly; Secure; SameSite=Lax";
|
|
@@ -154,28 +150,6 @@ function getCavunoAppCanonicalRedirectUrl(params) {
|
|
|
154
150
|
return `https://${canonical}${path.startsWith("/") ? path : `/${path}`}`;
|
|
155
151
|
}
|
|
156
152
|
|
|
157
|
-
// src/errors.ts
|
|
158
|
-
function isBoardApiError(e) {
|
|
159
|
-
return e instanceof Error && e.name === "BoardApiError" && typeof e.status === "number" && typeof e.code === "string";
|
|
160
|
-
}
|
|
161
|
-
function isUnauthorized(e) {
|
|
162
|
-
return isBoardApiError(e) && e.status === 401;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// src/storage.ts
|
|
166
|
-
var NOSTORE_BRAND = /* @__PURE__ */ Symbol.for("@cavuno/board:nostore");
|
|
167
|
-
function isNoStore(storage) {
|
|
168
|
-
return storage[NOSTORE_BRAND] === true;
|
|
169
|
-
}
|
|
170
|
-
var NOSTORE = {
|
|
171
|
-
[NOSTORE_BRAND]: true,
|
|
172
|
-
getItem: () => null,
|
|
173
|
-
setItem: () => {
|
|
174
|
-
},
|
|
175
|
-
removeItem: () => {
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
|
|
179
153
|
// src/server/refresher.ts
|
|
180
154
|
function createSessionRefresher(board) {
|
|
181
155
|
if (typeof globalThis.document === "undefined" && !isNoStore(board.client.storage)) {
|
package/dist/sitemap.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BoardSdk } from './index.mjs';
|
|
2
2
|
import './_spec-nkWAraS0.mjs';
|
|
3
3
|
import './search-CCyFWPi3.mjs';
|
|
4
|
-
import './board-
|
|
4
|
+
import './board-BJbXd_9_.mjs';
|
|
5
5
|
import './jobs-lVvKCBCU.mjs';
|
|
6
|
-
import './
|
|
6
|
+
import './blog-DGBHmExV.mjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Sitemap primitives — the pure XML + bucket-filename logic behind a board
|
package/dist/sitemap.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BoardSdk } from './index.js';
|
|
2
2
|
import './_spec-nkWAraS0.js';
|
|
3
3
|
import './search-CyRvVMUp.js';
|
|
4
|
-
import './board-
|
|
4
|
+
import './board-JhdUWIoq.js';
|
|
5
5
|
import './jobs-BiEvL9d7.js';
|
|
6
|
-
import './
|
|
6
|
+
import './blog-iV9XEIGf.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Sitemap primitives — the pure XML + bucket-filename logic behind a board
|
package/dist/sitemap.mjs
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
paginate
|
|
3
|
+
} from "./chunk-DLSO6XXY.mjs";
|
|
4
|
+
import {
|
|
5
|
+
BOARD_PATHS,
|
|
6
|
+
blogAuthorPath,
|
|
7
|
+
blogPostPath,
|
|
8
|
+
blogTagPath,
|
|
9
|
+
companyMarketPath,
|
|
10
|
+
companyPath,
|
|
11
|
+
companySalaryPath,
|
|
12
|
+
jobDetailPath,
|
|
13
|
+
jobsCategoryPath,
|
|
14
|
+
jobsLocationPath,
|
|
15
|
+
jobsSkillPath,
|
|
16
|
+
salaryLocationPath,
|
|
17
|
+
salarySkillPath,
|
|
18
|
+
salaryTitlePath
|
|
19
|
+
} from "./chunk-L7ZOYWHW.mjs";
|
|
20
|
+
|
|
1
21
|
// src/sitemap/xml.ts
|
|
2
22
|
var SITEMAP_BUCKETS = [
|
|
3
23
|
"marketing",
|
|
@@ -98,102 +118,6 @@ function renderSitemapIndex(entries) {
|
|
|
98
118
|
return xml;
|
|
99
119
|
}
|
|
100
120
|
|
|
101
|
-
// src/pagination.ts
|
|
102
|
-
function paginate(listFn, query, options) {
|
|
103
|
-
async function* pages() {
|
|
104
|
-
let current = query;
|
|
105
|
-
for (; ; ) {
|
|
106
|
-
const page = await listFn(current, options);
|
|
107
|
-
yield page;
|
|
108
|
-
if (!page.hasMore || page.nextCursor === null) return;
|
|
109
|
-
const { offset: _offset, ...rest } = current ?? {};
|
|
110
|
-
current = { ...rest, cursor: page.nextCursor };
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
pages,
|
|
115
|
-
async *[Symbol.asyncIterator]() {
|
|
116
|
-
for await (const page of pages()) {
|
|
117
|
-
yield* page.data;
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
async toArray({ limit }) {
|
|
121
|
-
const items = [];
|
|
122
|
-
for await (const page of pages()) {
|
|
123
|
-
items.push(...page.data);
|
|
124
|
-
if (items.length >= limit) break;
|
|
125
|
-
}
|
|
126
|
-
return items.slice(0, limit);
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// src/paths/index.ts
|
|
132
|
-
function jobDetailPath(companySlug, jobSlug) {
|
|
133
|
-
return `/companies/${companySlug}/jobs/${jobSlug}`;
|
|
134
|
-
}
|
|
135
|
-
function jobsCategoryPath(categorySlug) {
|
|
136
|
-
return `/jobs/${categorySlug}`;
|
|
137
|
-
}
|
|
138
|
-
function jobsSkillPath(skillSlug) {
|
|
139
|
-
return `/jobs/skills/${skillSlug}`;
|
|
140
|
-
}
|
|
141
|
-
function jobsLocationPath(placeSlug) {
|
|
142
|
-
return `/jobs/locations/${placeSlug}`;
|
|
143
|
-
}
|
|
144
|
-
function companyPath(companySlug) {
|
|
145
|
-
return `/companies/${companySlug}`;
|
|
146
|
-
}
|
|
147
|
-
function companyMarketPath(marketSlug) {
|
|
148
|
-
return `/companies/markets/${marketSlug}`;
|
|
149
|
-
}
|
|
150
|
-
function companySalaryPath(companySlug) {
|
|
151
|
-
return `/companies/${companySlug}/salaries`;
|
|
152
|
-
}
|
|
153
|
-
function salaryTitlePath(titleSlug) {
|
|
154
|
-
return `/salaries/titles/${titleSlug}`;
|
|
155
|
-
}
|
|
156
|
-
function salarySkillPath(skillSlug) {
|
|
157
|
-
return `/salaries/skills/${skillSlug}`;
|
|
158
|
-
}
|
|
159
|
-
function salaryLocationPath(placeSlug) {
|
|
160
|
-
return `/salaries/locations/${placeSlug}`;
|
|
161
|
-
}
|
|
162
|
-
function blogPostPath(postSlug) {
|
|
163
|
-
return `/blog/${postSlug}`;
|
|
164
|
-
}
|
|
165
|
-
function blogTagPath(tagSlug) {
|
|
166
|
-
return `/blog/tag/${tagSlug}`;
|
|
167
|
-
}
|
|
168
|
-
function blogAuthorPath(authorSlug) {
|
|
169
|
-
return `/blog/author/${authorSlug}`;
|
|
170
|
-
}
|
|
171
|
-
var BOARD_PATHS = {
|
|
172
|
-
home: "/",
|
|
173
|
-
jobs: "/jobs",
|
|
174
|
-
companies: "/companies",
|
|
175
|
-
salaries: "/salaries",
|
|
176
|
-
salaryCompanies: "/salaries/companies",
|
|
177
|
-
salaryTitles: "/salaries/titles",
|
|
178
|
-
salarySkills: "/salaries/skills",
|
|
179
|
-
salaryLocations: "/salaries/locations",
|
|
180
|
-
blog: "/blog",
|
|
181
|
-
about: "/about",
|
|
182
|
-
privacyPolicy: "/privacy-policy",
|
|
183
|
-
termsOfService: "/terms-of-service",
|
|
184
|
-
cookiePolicy: "/cookie-policy",
|
|
185
|
-
impressum: "/impressum",
|
|
186
|
-
talent: "/talent",
|
|
187
|
-
employers: "/employers",
|
|
188
|
-
/**
|
|
189
|
-
* Alert-email surfaces. Promoted out of raw literals in
|
|
190
|
-
* the job-alerts composer so /go indirection and email composition share
|
|
191
|
-
* one definition.
|
|
192
|
-
*/
|
|
193
|
-
alertsManage: "/alerts/manage",
|
|
194
|
-
alertsConfirm: "/alerts/confirm"
|
|
195
|
-
};
|
|
196
|
-
|
|
197
121
|
// src/sitemap/walker.ts
|
|
198
122
|
var MIN_JOBS_PER_INDEXED_PAGE = 5;
|
|
199
123
|
var MAX_PAGES = 200;
|
package/dist/well-known.mjs
CHANGED
|
@@ -1,424 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function jobsCategoryPath(categorySlug) {
|
|
6
|
-
return `/jobs/${categorySlug}`;
|
|
7
|
-
}
|
|
8
|
-
function jobsSkillPath(skillSlug) {
|
|
9
|
-
return `/jobs/skills/${skillSlug}`;
|
|
10
|
-
}
|
|
11
|
-
function jobsLocationPath(placeSlug) {
|
|
12
|
-
return `/jobs/locations/${placeSlug}`;
|
|
13
|
-
}
|
|
14
|
-
function companyPath(companySlug) {
|
|
15
|
-
return `/companies/${companySlug}`;
|
|
16
|
-
}
|
|
17
|
-
function companyMarketPath(marketSlug) {
|
|
18
|
-
return `/companies/markets/${marketSlug}`;
|
|
19
|
-
}
|
|
20
|
-
function companySalaryPath(companySlug) {
|
|
21
|
-
return `/companies/${companySlug}/salaries`;
|
|
22
|
-
}
|
|
23
|
-
function salaryTitlePath(titleSlug) {
|
|
24
|
-
return `/salaries/titles/${titleSlug}`;
|
|
25
|
-
}
|
|
26
|
-
function salarySkillPath(skillSlug) {
|
|
27
|
-
return `/salaries/skills/${skillSlug}`;
|
|
28
|
-
}
|
|
29
|
-
function salaryLocationPath(placeSlug) {
|
|
30
|
-
return `/salaries/locations/${placeSlug}`;
|
|
31
|
-
}
|
|
32
|
-
function blogPostPath(postSlug) {
|
|
33
|
-
return `/blog/${postSlug}`;
|
|
34
|
-
}
|
|
35
|
-
function blogTagPath(tagSlug) {
|
|
36
|
-
return `/blog/tag/${tagSlug}`;
|
|
37
|
-
}
|
|
38
|
-
function blogAuthorPath(authorSlug) {
|
|
39
|
-
return `/blog/author/${authorSlug}`;
|
|
40
|
-
}
|
|
41
|
-
var BOARD_PATHS = {
|
|
42
|
-
home: "/",
|
|
43
|
-
jobs: "/jobs",
|
|
44
|
-
companies: "/companies",
|
|
45
|
-
salaries: "/salaries",
|
|
46
|
-
salaryCompanies: "/salaries/companies",
|
|
47
|
-
salaryTitles: "/salaries/titles",
|
|
48
|
-
salarySkills: "/salaries/skills",
|
|
49
|
-
salaryLocations: "/salaries/locations",
|
|
50
|
-
blog: "/blog",
|
|
51
|
-
about: "/about",
|
|
52
|
-
privacyPolicy: "/privacy-policy",
|
|
53
|
-
termsOfService: "/terms-of-service",
|
|
54
|
-
cookiePolicy: "/cookie-policy",
|
|
55
|
-
impressum: "/impressum",
|
|
56
|
-
talent: "/talent",
|
|
57
|
-
employers: "/employers",
|
|
58
|
-
/**
|
|
59
|
-
* Alert-email surfaces. Promoted out of raw literals in
|
|
60
|
-
* the job-alerts composer so /go indirection and email composition share
|
|
61
|
-
* one definition.
|
|
62
|
-
*/
|
|
63
|
-
alertsManage: "/alerts/manage",
|
|
64
|
-
alertsConfirm: "/alerts/confirm"
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// src/route-contract/roles.ts
|
|
68
|
-
var ROLE_PARAM_REGISTRY = {
|
|
69
|
-
jobDetail: ["companySlug", "jobSlug"],
|
|
70
|
-
jobsCategory: ["categorySlug"],
|
|
71
|
-
jobsSkill: ["skillSlug"],
|
|
72
|
-
jobsLocation: ["placeSlug"],
|
|
73
|
-
company: ["companySlug"],
|
|
74
|
-
companyMarket: ["marketSlug"],
|
|
75
|
-
companySalary: ["companySlug"],
|
|
76
|
-
salaryTitle: ["titleSlug"],
|
|
77
|
-
salarySkill: ["skillSlug"],
|
|
78
|
-
salaryLocation: ["placeSlug"],
|
|
79
|
-
blogPost: ["postSlug"],
|
|
80
|
-
blogTag: ["tagSlug"],
|
|
81
|
-
blogAuthor: ["authorSlug"],
|
|
82
|
-
home: [],
|
|
83
|
-
jobs: [],
|
|
84
|
-
companies: [],
|
|
85
|
-
salaries: [],
|
|
86
|
-
salaryCompanies: [],
|
|
87
|
-
salaryTitles: [],
|
|
88
|
-
salarySkills: [],
|
|
89
|
-
salaryLocations: [],
|
|
90
|
-
blog: [],
|
|
91
|
-
about: [],
|
|
92
|
-
privacyPolicy: [],
|
|
93
|
-
termsOfService: [],
|
|
94
|
-
cookiePolicy: [],
|
|
95
|
-
impressum: [],
|
|
96
|
-
talent: [],
|
|
97
|
-
employers: [],
|
|
98
|
-
alertsManage: [],
|
|
99
|
-
alertsConfirm: []
|
|
100
|
-
};
|
|
101
|
-
var REQUIRED_ROLES = [
|
|
102
|
-
"jobDetail",
|
|
103
|
-
"alertsManage",
|
|
104
|
-
"alertsConfirm"
|
|
105
|
-
];
|
|
106
|
-
var ALL_ROLES = Object.keys(
|
|
107
|
-
ROLE_PARAM_REGISTRY
|
|
108
|
-
);
|
|
109
|
-
var ROLE_SET = new Set(ALL_ROLES);
|
|
110
|
-
var CANONICAL_MANIFEST = {
|
|
111
|
-
version: 1,
|
|
112
|
-
roles: {
|
|
113
|
-
jobDetail: jobDetailPath(":companySlug", ":jobSlug"),
|
|
114
|
-
jobsCategory: jobsCategoryPath(":categorySlug"),
|
|
115
|
-
jobsSkill: jobsSkillPath(":skillSlug"),
|
|
116
|
-
jobsLocation: jobsLocationPath(":placeSlug"),
|
|
117
|
-
company: companyPath(":companySlug"),
|
|
118
|
-
companyMarket: companyMarketPath(":marketSlug"),
|
|
119
|
-
companySalary: companySalaryPath(":companySlug"),
|
|
120
|
-
salaryTitle: salaryTitlePath(":titleSlug"),
|
|
121
|
-
salarySkill: salarySkillPath(":skillSlug"),
|
|
122
|
-
salaryLocation: salaryLocationPath(":placeSlug"),
|
|
123
|
-
blogPost: blogPostPath(":postSlug"),
|
|
124
|
-
blogTag: blogTagPath(":tagSlug"),
|
|
125
|
-
blogAuthor: blogAuthorPath(":authorSlug"),
|
|
126
|
-
home: BOARD_PATHS.home,
|
|
127
|
-
jobs: BOARD_PATHS.jobs,
|
|
128
|
-
companies: BOARD_PATHS.companies,
|
|
129
|
-
salaries: BOARD_PATHS.salaries,
|
|
130
|
-
salaryCompanies: BOARD_PATHS.salaryCompanies,
|
|
131
|
-
salaryTitles: BOARD_PATHS.salaryTitles,
|
|
132
|
-
salarySkills: BOARD_PATHS.salarySkills,
|
|
133
|
-
salaryLocations: BOARD_PATHS.salaryLocations,
|
|
134
|
-
blog: BOARD_PATHS.blog,
|
|
135
|
-
about: BOARD_PATHS.about,
|
|
136
|
-
privacyPolicy: BOARD_PATHS.privacyPolicy,
|
|
137
|
-
termsOfService: BOARD_PATHS.termsOfService,
|
|
138
|
-
cookiePolicy: BOARD_PATHS.cookiePolicy,
|
|
139
|
-
impressum: BOARD_PATHS.impressum,
|
|
140
|
-
talent: BOARD_PATHS.talent,
|
|
141
|
-
employers: BOARD_PATHS.employers,
|
|
142
|
-
alertsManage: "/alerts/manage",
|
|
143
|
-
alertsConfirm: "/alerts/confirm"
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// src/route-contract/params.ts
|
|
148
|
-
function extractParamNames(template) {
|
|
149
|
-
const names = [];
|
|
150
|
-
const re = /:([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
151
|
-
let match;
|
|
152
|
-
while ((match = re.exec(template)) !== null) {
|
|
153
|
-
const name = match[1];
|
|
154
|
-
if (name !== void 0) names.push(name);
|
|
155
|
-
}
|
|
156
|
-
return names;
|
|
157
|
-
}
|
|
158
|
-
function sameParamSet(a, b) {
|
|
159
|
-
if (a.length !== b.length) return false;
|
|
160
|
-
const sortedA = [...a].sort();
|
|
161
|
-
const sortedB = [...b].sort();
|
|
162
|
-
for (let i = 0; i < sortedA.length; i++) {
|
|
163
|
-
if (sortedA[i] !== sortedB[i]) return false;
|
|
164
|
-
}
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
function paramSetKey(params) {
|
|
168
|
-
return [...params].sort().join("\0");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// src/route-contract/classify.ts
|
|
172
|
-
var SHARED_SIGNATURE_COUNTS = (() => {
|
|
173
|
-
const counts = /* @__PURE__ */ new Map();
|
|
174
|
-
for (const role of ALL_ROLES) {
|
|
175
|
-
const params = ROLE_PARAM_REGISTRY[role];
|
|
176
|
-
if (params.length === 0) continue;
|
|
177
|
-
const key = paramSetKey(params);
|
|
178
|
-
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
179
|
-
}
|
|
180
|
-
return counts;
|
|
181
|
-
})();
|
|
182
|
-
function isSignatureCandidate(route, role) {
|
|
183
|
-
const registry = ROLE_PARAM_REGISTRY[role];
|
|
184
|
-
const routeParams = extractParamNames(route.template);
|
|
185
|
-
if (registry.length === 0) {
|
|
186
|
-
return route.template === CANONICAL_MANIFEST.roles[role];
|
|
187
|
-
}
|
|
188
|
-
if (!sameParamSet(routeParams, registry)) return false;
|
|
189
|
-
const shareCount = SHARED_SIGNATURE_COUNTS.get(paramSetKey(registry)) ?? 0;
|
|
190
|
-
if (shareCount > 1) {
|
|
191
|
-
return route.template === CANONICAL_MANIFEST.roles[role];
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
function classifyRoutes(routes, markers) {
|
|
196
|
-
const assignments = {};
|
|
197
|
-
const ambiguities = [];
|
|
198
|
-
const claimed = /* @__PURE__ */ new Set();
|
|
199
|
-
if (markers && markers.size > 0) {
|
|
200
|
-
const claimsByRole = /* @__PURE__ */ new Map();
|
|
201
|
-
for (const route of routes) {
|
|
202
|
-
if (route.sourcePath === void 0) continue;
|
|
203
|
-
const role = markers.get(route.sourcePath);
|
|
204
|
-
if (role === void 0) continue;
|
|
205
|
-
const list = claimsByRole.get(role);
|
|
206
|
-
if (list) list.push(route);
|
|
207
|
-
else claimsByRole.set(role, [route]);
|
|
208
|
-
}
|
|
209
|
-
for (const [role, candidates] of claimsByRole) {
|
|
210
|
-
for (const c of candidates) claimed.add(c);
|
|
211
|
-
if (candidates.length === 1) {
|
|
212
|
-
assignments[role] = candidates[0];
|
|
213
|
-
} else {
|
|
214
|
-
ambiguities.push({ role, candidates: [...candidates] });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
const pool = routes.filter((r) => !claimed.has(r));
|
|
219
|
-
for (const role of ALL_ROLES) {
|
|
220
|
-
if (assignments[role] !== void 0) continue;
|
|
221
|
-
if (ambiguities.some((a) => a.role === role)) continue;
|
|
222
|
-
const candidates = pool.filter((r) => isSignatureCandidate(r, role));
|
|
223
|
-
if (candidates.length === 0) continue;
|
|
224
|
-
if (candidates.length === 1) {
|
|
225
|
-
const only = candidates[0];
|
|
226
|
-
if (claimed.has(only)) {
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
assignments[role] = only;
|
|
230
|
-
claimed.add(only);
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
ambiguities.push({ role, candidates: [...candidates] });
|
|
234
|
-
}
|
|
235
|
-
const missingRequired = REQUIRED_ROLES.filter(
|
|
236
|
-
(role) => assignments[role] === void 0
|
|
237
|
-
);
|
|
238
|
-
return { assignments, ambiguities, missingRequired };
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// src/route-contract/validate.ts
|
|
242
|
-
var TEMPLATE_CHARSET_RE = /^[A-Za-z0-9/_.:-]+$/;
|
|
243
|
-
function checkRoleTemplate(role, template) {
|
|
244
|
-
const errors = [];
|
|
245
|
-
if (typeof template !== "string" || template.length === 0) {
|
|
246
|
-
errors.push({
|
|
247
|
-
code: "invalid_template",
|
|
248
|
-
message: `role '${role}' template must be a non-empty string`,
|
|
249
|
-
role
|
|
250
|
-
});
|
|
251
|
-
return errors;
|
|
252
|
-
}
|
|
253
|
-
if (!template.startsWith("/")) {
|
|
254
|
-
errors.push({
|
|
255
|
-
code: "invalid_template",
|
|
256
|
-
message: `role '${role}' template must start with '/', got ${JSON.stringify(template)}`,
|
|
257
|
-
role
|
|
258
|
-
});
|
|
259
|
-
return errors;
|
|
260
|
-
}
|
|
261
|
-
if (/\s/.test(template)) {
|
|
262
|
-
errors.push({
|
|
263
|
-
code: "invalid_template",
|
|
264
|
-
message: `role '${role}' template must not contain whitespace, got ${JSON.stringify(template)}`,
|
|
265
|
-
role
|
|
266
|
-
});
|
|
267
|
-
return errors;
|
|
268
|
-
}
|
|
269
|
-
if (template.includes("?") || template.includes("#")) {
|
|
270
|
-
errors.push({
|
|
271
|
-
code: "template_query_or_fragment",
|
|
272
|
-
message: `role '${role}' template must not contain '?' or '#', got ${JSON.stringify(template)}`,
|
|
273
|
-
role
|
|
274
|
-
});
|
|
275
|
-
return errors;
|
|
276
|
-
}
|
|
277
|
-
if (template.startsWith("//") || template.includes("//")) {
|
|
278
|
-
errors.push({
|
|
279
|
-
code: "template_double_slash",
|
|
280
|
-
message: `role '${role}' template must not contain '//', got ${JSON.stringify(template)}`,
|
|
281
|
-
role
|
|
282
|
-
});
|
|
283
|
-
return errors;
|
|
284
|
-
}
|
|
285
|
-
for (const seg of template.split("/")) {
|
|
286
|
-
if (seg === "." || seg === "..") {
|
|
287
|
-
errors.push({
|
|
288
|
-
code: "template_dot_segment",
|
|
289
|
-
message: `role '${role}' template must not contain '.' or '..' segments, got ${JSON.stringify(template)}`,
|
|
290
|
-
role
|
|
291
|
-
});
|
|
292
|
-
return errors;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
if (!TEMPLATE_CHARSET_RE.test(template)) {
|
|
296
|
-
errors.push({
|
|
297
|
-
code: "template_illegal_charset",
|
|
298
|
-
message: `role '${role}' template contains illegal characters, got ${JSON.stringify(template)}`,
|
|
299
|
-
role
|
|
300
|
-
});
|
|
301
|
-
return errors;
|
|
302
|
-
}
|
|
303
|
-
const registry = ROLE_PARAM_REGISTRY[role];
|
|
304
|
-
const tokens = extractParamNames(template);
|
|
305
|
-
if (registry.length === 0) {
|
|
306
|
-
if (tokens.length > 0) {
|
|
307
|
-
errors.push({
|
|
308
|
-
code: "static_has_params",
|
|
309
|
-
message: `static role '${role}' template must not contain ':' tokens, got ${template}`,
|
|
310
|
-
role,
|
|
311
|
-
token: tokens[0]
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
} else {
|
|
315
|
-
const registrySet = new Set(registry);
|
|
316
|
-
for (const token of tokens) {
|
|
317
|
-
if (!registrySet.has(token)) {
|
|
318
|
-
errors.push({
|
|
319
|
-
code: "unregistered_param",
|
|
320
|
-
message: `role '${role}' template references unregistered param ':${token}'`,
|
|
321
|
-
role,
|
|
322
|
-
token
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
const retained = tokens.filter((t) => registrySet.has(t));
|
|
327
|
-
if (retained.length === 0) {
|
|
328
|
-
errors.push({
|
|
329
|
-
code: "missing_entity_param",
|
|
330
|
-
message: `role '${role}' template must contain at least one registry param (${registry.join(", ")})`,
|
|
331
|
-
role
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return errors;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// src/route-contract/compile.ts
|
|
339
|
-
var REQUIRED_SET = new Set(REQUIRED_ROLES);
|
|
340
|
-
function compileManifest(routes, markers) {
|
|
341
|
-
const { assignments, ambiguities, missingRequired } = classifyRoutes(
|
|
342
|
-
routes,
|
|
343
|
-
markers
|
|
344
|
-
);
|
|
345
|
-
const roles = {};
|
|
346
|
-
const warnings = [];
|
|
347
|
-
const blocking = new Set(missingRequired);
|
|
348
|
-
for (const role of ALL_ROLES) {
|
|
349
|
-
const entry = assignments[role];
|
|
350
|
-
if (entry === void 0) continue;
|
|
351
|
-
const templateErrors = checkRoleTemplate(role, entry.template);
|
|
352
|
-
if (templateErrors.length > 0) {
|
|
353
|
-
const exact = templateErrors.map((e) => e.message).join("; ");
|
|
354
|
-
warnings.push(
|
|
355
|
-
`role '${role}' template rejected: ${exact} \u2014 add export const cavunoPage = '${role}' on the correct page or fix the template`
|
|
356
|
-
);
|
|
357
|
-
if (REQUIRED_SET.has(role)) {
|
|
358
|
-
blocking.add(role);
|
|
359
|
-
}
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
roles[role] = entry.template;
|
|
363
|
-
}
|
|
364
|
-
for (const amb of ambiguities) {
|
|
365
|
-
const kind = REQUIRED_SET.has(amb.role) ? "required" : "optional";
|
|
366
|
-
warnings.push(
|
|
367
|
-
`${kind} role '${amb.role}' is ambiguous \u2014 add export const cavunoPage = '${amb.role}' to disambiguate`
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
for (const role of ALL_ROLES) {
|
|
371
|
-
if (REQUIRED_SET.has(role)) continue;
|
|
372
|
-
if (roles[role] !== void 0) continue;
|
|
373
|
-
if (assignments[role] !== void 0) continue;
|
|
374
|
-
if (ambiguities.some((a) => a.role === role)) continue;
|
|
375
|
-
warnings.push(`optional role '${role}' is unassigned`);
|
|
376
|
-
}
|
|
377
|
-
return {
|
|
378
|
-
manifest: { version: 1, roles },
|
|
379
|
-
blockingMissing: REQUIRED_ROLES.filter((r) => blocking.has(r)),
|
|
380
|
-
warnings,
|
|
381
|
-
ambiguities
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// src/route-contract/resolve-links.ts
|
|
386
|
-
var REQUIRED_SET2 = new Set(REQUIRED_ROLES);
|
|
387
|
-
|
|
388
|
-
// src/route-contract/match-history.ts
|
|
389
|
-
var ROLE_INDEX_PATHS = {
|
|
390
|
-
jobDetail: BOARD_PATHS.jobs,
|
|
391
|
-
jobsCategory: BOARD_PATHS.jobs,
|
|
392
|
-
jobsSkill: BOARD_PATHS.jobs,
|
|
393
|
-
jobsLocation: BOARD_PATHS.jobs,
|
|
394
|
-
company: BOARD_PATHS.companies,
|
|
395
|
-
companyMarket: BOARD_PATHS.companies,
|
|
396
|
-
companySalary: BOARD_PATHS.companies,
|
|
397
|
-
salaryTitle: BOARD_PATHS.salaries,
|
|
398
|
-
salarySkill: BOARD_PATHS.salaries,
|
|
399
|
-
salaryLocation: BOARD_PATHS.salaries,
|
|
400
|
-
salaryCompanies: BOARD_PATHS.salaries,
|
|
401
|
-
salaryTitles: BOARD_PATHS.salaries,
|
|
402
|
-
salarySkills: BOARD_PATHS.salaries,
|
|
403
|
-
salaryLocations: BOARD_PATHS.salaries,
|
|
404
|
-
salaries: BOARD_PATHS.salaries,
|
|
405
|
-
blogPost: BOARD_PATHS.blog,
|
|
406
|
-
blogTag: BOARD_PATHS.blog,
|
|
407
|
-
blogAuthor: BOARD_PATHS.blog,
|
|
408
|
-
blog: BOARD_PATHS.blog,
|
|
409
|
-
home: BOARD_PATHS.home,
|
|
410
|
-
jobs: BOARD_PATHS.jobs,
|
|
411
|
-
companies: BOARD_PATHS.companies,
|
|
412
|
-
about: BOARD_PATHS.about,
|
|
413
|
-
privacyPolicy: BOARD_PATHS.privacyPolicy,
|
|
414
|
-
termsOfService: BOARD_PATHS.termsOfService,
|
|
415
|
-
cookiePolicy: BOARD_PATHS.cookiePolicy,
|
|
416
|
-
impressum: BOARD_PATHS.impressum,
|
|
417
|
-
talent: BOARD_PATHS.talent,
|
|
418
|
-
employers: BOARD_PATHS.employers,
|
|
419
|
-
alertsManage: BOARD_PATHS.home,
|
|
420
|
-
alertsConfirm: BOARD_PATHS.home
|
|
421
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
compileManifest
|
|
3
|
+
} from "./chunk-NXY3OWGF.mjs";
|
|
4
|
+
import "./chunk-L7ZOYWHW.mjs";
|
|
422
5
|
|
|
423
6
|
// src/well-known/handler.ts
|
|
424
7
|
var WELL_KNOWN_CACHE_CONTROL = "public, max-age=300";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cavuno/board",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Build custom job boards and careers pages with Cavuno’s TypeScript SDK.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -201,9 +201,11 @@
|
|
|
201
201
|
"scripts": {
|
|
202
202
|
"build": "rm -rf dist && tsup",
|
|
203
203
|
"clean": "git clean -xdf .turbo dist node_modules src/generated",
|
|
204
|
-
"typecheck": "
|
|
204
|
+
"typecheck": "tsgo --noEmit && tsgo --noEmit -p tsconfig.node.json",
|
|
205
205
|
"test": "vitest run",
|
|
206
206
|
"check:publish": "publint --strict && attw --pack . --profile node16",
|
|
207
|
+
"check:surface": "node ../../scripts/check-public-surface.mjs",
|
|
208
|
+
"gen:surface": "node ../../scripts/check-public-surface.mjs --write",
|
|
207
209
|
"gen:skills-manifest": "tsx scripts/generate-skills-manifest.ts",
|
|
208
210
|
"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')}\"",
|
|
209
211
|
"prepublishOnly": "pnpm run assert-publish-target && pnpm run gen:skills-manifest && pnpm run build"
|
|
@@ -215,7 +217,8 @@
|
|
|
215
217
|
"tsup": "^8.4.0",
|
|
216
218
|
"tsx": "^4.19.2",
|
|
217
219
|
"vitest": "^2.1.9",
|
|
218
|
-
"typescript": "^5.9.3"
|
|
220
|
+
"typescript": "^5.9.3",
|
|
221
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2"
|
|
219
222
|
},
|
|
220
223
|
"engines": {
|
|
221
224
|
"node": ">=20"
|
package/skills/manifest.json
CHANGED