@farming-labs/docs 0.2.119 → 0.2.121
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/README.md +8 -0
- package/dist/access.d.mts +13 -0
- package/dist/access.mjs +56 -0
- package/dist/agent-conformance.d.mts +60 -0
- package/dist/agent-conformance.mjs +538 -0
- package/dist/agent-contract.d.mts +47 -0
- package/dist/agent-contract.mjs +645 -0
- package/dist/agent-detection.d.mts +6 -0
- package/dist/agent-detection.mjs +83 -0
- package/dist/agent-evals.d.mts +224 -0
- package/dist/{agent-evals-BLNLvXbG.mjs → agent-evals.mjs} +7 -565
- package/dist/agent-feedback-evaluations-node.mjs +38 -0
- package/dist/agent-feedback-evaluations.d.mts +91 -0
- package/dist/{agent-feedback-evaluations-CcMGlgsO.mjs → agent-feedback-evaluations.mjs} +2 -2
- package/dist/agent-feedback-loop.d.mts +45 -0
- package/dist/{agent-feedback-loop-CcZL_sb1.mjs → agent-feedback-loop.mjs} +1 -1
- package/dist/agent-maintenance.d.mts +71 -0
- package/dist/{agent-maintenance-CuZ7iAKq.mjs → agent-maintenance.mjs} +1 -1
- package/dist/agent-provenance.d.mts +23 -0
- package/dist/agent-provenance.mjs +77 -0
- package/dist/agent-scope.mjs +321 -0
- package/dist/agent-skills-archive.mjs +86 -0
- package/dist/agent-skills-bundle.d.mts +1 -1
- package/dist/{agent-skills-progressive-disclosure-PjPtTYL-.mjs → agent-skills-progressive-disclosure.mjs} +2 -2
- package/dist/{agent-skills-server-CTNWr23x.d.mts → agent-skills-server.d.mts} +3 -3
- package/dist/{agent-skills-server-BC7md56k.mjs → agent-skills-server.mjs} +2 -2
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/agent-skills-vite.mjs +1 -2
- package/dist/agent-surface-drift.mjs +236 -0
- package/dist/{golden-evaluations-CLUViycJ.mjs → agent-usefulness.mjs} +5 -290
- package/dist/{content-change-hydration-CvHJadhE.d.mts → agent.d.mts} +10 -411
- package/dist/agent.mjs +2729 -0
- package/dist/{analytics-B8RZiKUt.d.mts → analytics.d.mts} +2 -2
- package/dist/{analytics-p8Vhhu2P.mjs → analytics.mjs} +2 -2
- package/dist/{sitemap-server-C9r22_06.d.mts → api-reference.d.mts} +3 -6
- package/dist/api-reference.mjs +1481 -0
- package/dist/{audience-exposure-DBrFWULA.d.mts → audience-exposure.d.mts} +1 -1
- package/dist/audience-exposure.mjs +8 -0
- package/dist/audience.d.mts +44 -0
- package/dist/audience.mjs +1654 -0
- package/dist/authoring-mcp.d.mts +44 -0
- package/dist/{authoring-mcp-CiCUQe3o.mjs → authoring-mcp.mjs} +3 -3
- package/dist/browser.d.mts +6 -4
- package/dist/browser.mjs +6 -7
- package/dist/build.d.mts +8 -0
- package/dist/build.mjs +8 -0
- package/dist/changelog.d.mts +20 -0
- package/dist/changelog.mjs +39 -0
- package/dist/{agent-export-Cxljt6RP.mjs → cli/agent-export.mjs} +19 -45
- package/dist/{agent-CYk2DxY7.mjs → cli/agent.mjs} +6 -35
- package/dist/{agents-jtn256sz.mjs → cli/agents.mjs} +5 -18
- package/dist/cli/api-doctor.mjs +206 -0
- package/dist/{authoring-C2ymvYWl.mjs → cli/authoring.mjs} +2 -8
- package/dist/{cloud-6eKrlmKd.mjs → cli/cloud.mjs} +3 -3
- package/dist/{codeblocks-CHpgAwY-.mjs → cli/codeblocks.mjs} +2 -2
- package/dist/cli/config.d.mts +11 -0
- package/dist/{config-BZnKAj_Y.mjs → cli/config.mjs} +1 -1
- package/dist/cli/dev-banner.mjs +58 -0
- package/dist/{dev-Bnn-NUNa.mjs → cli/dev.mjs} +3 -57
- package/dist/{doctor-CUMgbglt.mjs → cli/doctor.mjs} +41 -226
- package/dist/{downgrade-CHMta85e.mjs → cli/downgrade.mjs} +2 -2
- package/dist/cli/errors.d.mts +4 -0
- package/dist/{errors-BtnVLhNF.mjs → cli/errors.mjs} +1 -1
- package/dist/{feedback-evals-DMilg9pY.mjs → cli/feedback-evals.mjs} +3 -36
- package/dist/{feedback-DL4T5oIO.mjs → cli/feedback.mjs} +1 -1
- package/dist/cli/git-dates.mjs +35 -0
- package/dist/cli/golden-evaluations.mjs +52 -0
- package/dist/cli/index.d.mts +2 -3
- package/dist/cli/index.mjs +38 -38
- package/dist/{init-K0LmXDZ5.mjs → cli/init.mjs} +3 -3
- package/dist/{mcp-Bvha6_mG.mjs → cli/mcp.mjs} +7 -19
- package/dist/{openapi-diff-BOESBfnP.mjs → cli/openapi-diff.mjs} +2 -7
- package/dist/{openapi-sdk-DJutz2AC.mjs → cli/openapi-sdk.mjs} +2 -7
- package/dist/{openapi-source-CiX3hwFp.mjs → cli/openapi-source.mjs} +2 -2
- package/dist/{package-version-HJhYeq4M.mjs → cli/package-version.mjs} +2 -2
- package/dist/{propose-JmUv_BTt.mjs → cli/propose.mjs} +1 -1
- package/dist/{review-C6EmbV0l.mjs → cli/review.mjs} +16 -15
- package/dist/{robots-DteZB8vl.mjs → cli/robots.mjs} +3 -7
- package/dist/{search-DKcdZgGx.mjs → cli/search.mjs} +7 -20
- package/dist/{sitemap-CBQoERNz.mjs → cli/sitemap.mjs} +7 -42
- package/dist/{skills-a90P31sJ.mjs → cli/skills.mjs} +5 -19
- package/dist/{templates-BuQ8YsGv.mjs → cli/templates.mjs} +1 -1
- package/dist/{upgrade-DlQMOFV1.mjs → cli/upgrade.mjs} +2 -2
- package/dist/{utils-C7KDrPpA.mjs → cli/utils.mjs} +1 -1
- package/dist/client/react.d.mts +2 -18
- package/dist/client/react.mjs +1 -157
- package/dist/{cloud-analytics-D14HplI7.mjs → cloud-analytics.mjs} +1 -1
- package/dist/{cloud-ask-ai-BOahlsIZ.d.mts → cloud-ask-ai.d.mts} +2 -2
- package/dist/{cloud-ask-ai-BqKhjpS5.mjs → cloud-ask-ai.mjs} +3 -3
- package/dist/code-blocks.d.mts +51 -0
- package/dist/{code-blocks-GYdvS3BH.mjs → code-blocks.mjs} +2 -2
- package/dist/code-group-mdx.d.mts +11 -0
- package/dist/code-group-mdx.mjs +57 -0
- package/dist/content-change-hydration.d.mts +87 -0
- package/dist/{openapi-mcp-BIOTLiA7.mjs → content-change-hydration.mjs} +5 -210
- package/dist/content-changes.d.mts +47 -0
- package/dist/content-changes.mjs +216 -0
- package/dist/create-theme.d.mts +48 -0
- package/dist/create-theme.mjs +57 -0
- package/dist/date.d.mts +5 -0
- package/dist/date.mjs +17 -0
- package/dist/define-docs.d.mts +9 -0
- package/dist/define-docs.mjs +46 -0
- package/dist/docs-cloud-client.d.mts +18 -0
- package/dist/docs-cloud-client.mjs +161 -0
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/docs-cloud-server.mjs +2 -3
- package/dist/heading-toc.d.mts +10 -0
- package/dist/heading-toc.mjs +23 -0
- package/dist/http-body.d.mts +14 -0
- package/dist/{http-body-DkAPk6D5.mjs → http-body.mjs} +1 -1
- package/dist/http-cache.d.mts +25 -0
- package/dist/http-cache.mjs +140 -0
- package/dist/http-link.mjs +81 -0
- package/dist/i18n.d.mts +18 -0
- package/dist/{i18n-B1gJ9EW0.mjs → i18n.mjs} +1 -1
- package/dist/index.d.mts +43 -675
- package/dist/index.mjs +40 -14
- package/dist/markdown-rendering.mjs +1 -1
- package/dist/markdown-section-cache.mjs +49 -0
- package/dist/markdown-sections.d.mts +47 -0
- package/dist/{markdown-sections-9Oxr33b-.mjs → markdown-sections.mjs} +29 -703
- package/dist/mcp-auth.d.mts +14 -0
- package/dist/mcp-auth.mjs +99 -0
- package/dist/mcp.d.mts +5 -3
- package/dist/mcp.mjs +39 -9
- package/dist/mdx.d.mts +6 -0
- package/dist/mdx.mjs +7 -0
- package/dist/metadata.d.mts +60 -0
- package/dist/{metadata-BOHn0Y5K.mjs → metadata.mjs} +2 -2
- package/dist/native-api-reference.mjs +968 -0
- package/dist/okf.d.mts +42 -0
- package/dist/okf.mjs +145 -0
- package/dist/openapi-contract.mjs +154 -0
- package/dist/{openapi-mcp-node-C4jUpZG6.mjs → openapi-mcp-node.mjs} +1 -1
- package/dist/openapi-mcp.d.mts +26 -0
- package/dist/openapi-mcp.mjs +132 -0
- package/dist/openapi-operations.d.mts +71 -0
- package/dist/{openapi-operations-DFpaqOqA.mjs → openapi-operations.mjs} +1 -1
- package/dist/openapi-overlays.mjs +221 -0
- package/dist/openapi-references.mjs +233 -0
- package/dist/pagination.d.mts +7 -0
- package/dist/pagination.mjs +100 -0
- package/dist/prompt-references.d.mts +12 -0
- package/dist/prompt-references.mjs +132 -0
- package/dist/prompt-utils.d.mts +36 -0
- package/dist/{prompt-utils-B5g-bv7o.mjs → prompt-utils.mjs} +1 -57
- package/dist/reading-time.d.mts +23 -0
- package/dist/reading-time.mjs +58 -0
- package/dist/related.d.mts +7 -0
- package/dist/related.mjs +50 -0
- package/dist/retrieval-digest.d.mts +16 -0
- package/dist/{retrieval-digest-CT-eIEcp.mjs → retrieval-digest.mjs} +1 -1
- package/dist/review.d.mts +69 -0
- package/dist/review.mjs +562 -0
- package/dist/robots.d.mts +54 -0
- package/dist/{robots-BYJAVeI6.mjs → robots.mjs} +5 -3
- package/dist/runtime.d.mts +3 -3
- package/dist/runtime.mjs +3 -9
- package/dist/search.d.mts +210 -0
- package/dist/search.mjs +3401 -0
- package/dist/server.d.mts +22 -198
- package/dist/server.mjs +21 -19
- package/dist/sidebar.d.mts +15 -0
- package/dist/sidebar.mjs +73 -0
- package/dist/sitemap-server.d.mts +7 -0
- package/dist/{sitemap-server-Lg3YhUx4.mjs → sitemap-server.mjs} +2 -2
- package/dist/{sitemap-DafdOrxK.d.mts → sitemap.d.mts} +3 -3
- package/dist/sitemap.mjs +254 -0
- package/dist/{standards-discovery-1fiUVDAo.d.mts → standards-discovery.d.mts} +2 -2
- package/dist/{standards-discovery-sSEojU80.mjs → standards-discovery.mjs} +3 -139
- package/dist/telemetry-runtime.d.mts +42 -0
- package/dist/telemetry-runtime.mjs +238 -0
- package/dist/telemetry.d.mts +15 -0
- package/dist/telemetry.mjs +117 -0
- package/dist/{types-BncG8J3g.d.mts → types.d.mts} +21 -3
- package/dist/urls.d.mts +7 -0
- package/dist/urls.mjs +21 -0
- package/dist/utils.d.mts +8 -0
- package/dist/utils.mjs +22 -0
- package/package.json +21 -3
- package/dist/agent-DkAidqtV.mjs +0 -9026
- package/dist/api-reference-By_LokQ-.mjs +0 -3033
- package/dist/prompt-references-DMgbu_dz.mjs +0 -1082
- package/dist/retrieval-digest-DLAQsQmx.d.mts +0 -367
- package/dist/sidebar-C2LKcU7n.d.mts +0 -63
- package/dist/sidebar-CFHBj29f.mjs +0 -421
- /package/dist/{openapi-CfCzX_a1.mjs → cli/openapi.mjs} +0 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { paths, query } from "jsonpath-rfc9535";
|
|
2
|
+
|
|
3
|
+
//#region src/openapi-overlays.ts
|
|
4
|
+
var OpenApiOverlayError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "OpenApiOverlayError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
function isJsonObject(value) {
|
|
11
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
function isJsonPrimitive(value) {
|
|
14
|
+
return value === null || typeof value !== "object";
|
|
15
|
+
}
|
|
16
|
+
function assertAllowedFields(value, allowed, location) {
|
|
17
|
+
const allowedSet = new Set(allowed);
|
|
18
|
+
const unexpected = Object.keys(value).find((key) => !allowedSet.has(key) && !key.startsWith("x-"));
|
|
19
|
+
if (unexpected) throw new OpenApiOverlayError(`${location} contains an unsupported \`${unexpected}\` field.`);
|
|
20
|
+
}
|
|
21
|
+
function requireNonEmptyString(value, location) {
|
|
22
|
+
if (typeof value !== "string" || !value.trim()) throw new OpenApiOverlayError(`${location} must be a non-empty string.`);
|
|
23
|
+
return value.trim();
|
|
24
|
+
}
|
|
25
|
+
function assertValidOpenApiOverlayDocument(value, source = "OpenAPI Overlay document") {
|
|
26
|
+
if (!isJsonObject(value)) throw new OpenApiOverlayError(`${source} must contain an object.`);
|
|
27
|
+
const overlayVersion = requireNonEmptyString(value.overlay, `${source} \`overlay\``);
|
|
28
|
+
const match = /^1\.(0|1)\.\d+$/.exec(overlayVersion);
|
|
29
|
+
if (!match) throw new OpenApiOverlayError(`${source} uses unsupported Overlay version \`${overlayVersion}\`. Supported versions are 1.0.x and 1.1.x.`);
|
|
30
|
+
const featureVersion = match[1] === "0" ? "1.0" : "1.1";
|
|
31
|
+
assertAllowedFields(value, [
|
|
32
|
+
"overlay",
|
|
33
|
+
"info",
|
|
34
|
+
"extends",
|
|
35
|
+
"actions"
|
|
36
|
+
], source);
|
|
37
|
+
if (!isJsonObject(value.info)) throw new OpenApiOverlayError(`${source} \`info\` must be an object.`);
|
|
38
|
+
assertAllowedFields(value.info, featureVersion === "1.1" ? [
|
|
39
|
+
"title",
|
|
40
|
+
"version",
|
|
41
|
+
"description"
|
|
42
|
+
] : ["title", "version"], `${source} \`info\``);
|
|
43
|
+
requireNonEmptyString(value.info.title, `${source} \`info.title\``);
|
|
44
|
+
requireNonEmptyString(value.info.version, `${source} \`info.version\``);
|
|
45
|
+
if (value.extends !== void 0 && typeof value.extends !== "string") throw new OpenApiOverlayError(`${source} \`extends\` must be a URI-reference string.`);
|
|
46
|
+
if (!Array.isArray(value.actions) || value.actions.length === 0) throw new OpenApiOverlayError(`${source} \`actions\` must contain at least one action.`);
|
|
47
|
+
const serializedActions = /* @__PURE__ */ new Set();
|
|
48
|
+
value.actions.forEach((action, index) => {
|
|
49
|
+
const location = `${source} action ${index + 1}`;
|
|
50
|
+
if (!isJsonObject(action)) throw new OpenApiOverlayError(`${location} must be an object.`);
|
|
51
|
+
assertAllowedFields(action, featureVersion === "1.1" ? [
|
|
52
|
+
"target",
|
|
53
|
+
"description",
|
|
54
|
+
"update",
|
|
55
|
+
"copy",
|
|
56
|
+
"remove"
|
|
57
|
+
] : [
|
|
58
|
+
"target",
|
|
59
|
+
"description",
|
|
60
|
+
"update",
|
|
61
|
+
"remove"
|
|
62
|
+
], location);
|
|
63
|
+
if (!requireNonEmptyString(action.target, `${location} \`target\``).startsWith("$")) throw new OpenApiOverlayError(`${location} \`target\` must start with \`$\`.`);
|
|
64
|
+
if (action.description !== void 0 && typeof action.description !== "string") throw new OpenApiOverlayError(`${location} \`description\` must be a string.`);
|
|
65
|
+
if (action.remove !== void 0 && typeof action.remove !== "boolean") throw new OpenApiOverlayError(`${location} \`remove\` must be a boolean.`);
|
|
66
|
+
if (action.copy !== void 0) {
|
|
67
|
+
if (!requireNonEmptyString(action.copy, `${location} \`copy\``).startsWith("$")) throw new OpenApiOverlayError(`${location} \`copy\` must start with \`$\`.`);
|
|
68
|
+
}
|
|
69
|
+
const serialized = JSON.stringify(action);
|
|
70
|
+
if (serializedActions.has(serialized)) throw new OpenApiOverlayError(`${location} duplicates an earlier action.`);
|
|
71
|
+
serializedActions.add(serialized);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function validateOverlay(value, source) {
|
|
75
|
+
assertValidOpenApiOverlayDocument(value, source);
|
|
76
|
+
return {
|
|
77
|
+
version: String(value.overlay).startsWith("1.0.") ? "1.0" : "1.1",
|
|
78
|
+
actions: value.actions
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function decodeNormalizedPathKey(value) {
|
|
82
|
+
return value.replace(/\\(?:['\\bfnrt]|u[\da-fA-F]{4})/g, (match) => {
|
|
83
|
+
const escape = match.slice(1);
|
|
84
|
+
if (escape.startsWith("u")) return String.fromCharCode(Number.parseInt(escape.slice(1), 16));
|
|
85
|
+
return {
|
|
86
|
+
"'": "'",
|
|
87
|
+
"\\": "\\",
|
|
88
|
+
b: "\b",
|
|
89
|
+
f: "\f",
|
|
90
|
+
n: "\n",
|
|
91
|
+
r: "\r",
|
|
92
|
+
t: " "
|
|
93
|
+
}[escape];
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function parseNormalizedJsonPath(path) {
|
|
97
|
+
if (path === "$") return [];
|
|
98
|
+
const segments = [];
|
|
99
|
+
const segmentPattern = /\[(?:(\d+)|'((?:\\.|[^'])*)')\]/gy;
|
|
100
|
+
segmentPattern.lastIndex = 1;
|
|
101
|
+
while (segmentPattern.lastIndex < path.length) {
|
|
102
|
+
const match = segmentPattern.exec(path);
|
|
103
|
+
if (!match) throw new OpenApiOverlayError(`JSONPath returned an unsupported normalized path: ${path}`);
|
|
104
|
+
segments.push(match[1] === void 0 ? decodeNormalizedPathKey(match[2] ?? "") : Number(match[1]));
|
|
105
|
+
}
|
|
106
|
+
return segments;
|
|
107
|
+
}
|
|
108
|
+
function getAtPath(root, path) {
|
|
109
|
+
let value = root;
|
|
110
|
+
for (const segment of path) {
|
|
111
|
+
if (Array.isArray(value) && typeof segment === "number") {
|
|
112
|
+
value = value[segment];
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (isJsonObject(value) && typeof segment === "string") {
|
|
116
|
+
value = value[segment];
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
throw new OpenApiOverlayError("An Overlay action selected a node that no longer exists.");
|
|
120
|
+
}
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
function setAtPath(root, path, value) {
|
|
124
|
+
if (path.length === 0) return value;
|
|
125
|
+
const parent = getAtPath(root, path.slice(0, -1));
|
|
126
|
+
const key = path[path.length - 1];
|
|
127
|
+
if (Array.isArray(parent) && typeof key === "number") parent[key] = value;
|
|
128
|
+
else if (isJsonObject(parent) && typeof key === "string") parent[key] = value;
|
|
129
|
+
else throw new OpenApiOverlayError("An Overlay action selected an invalid parent node.");
|
|
130
|
+
return root;
|
|
131
|
+
}
|
|
132
|
+
function removeAtPath(root, path) {
|
|
133
|
+
if (path.length === 0) throw new OpenApiOverlayError("An Overlay action cannot remove the document root.");
|
|
134
|
+
const parent = getAtPath(root, path.slice(0, -1));
|
|
135
|
+
const key = path[path.length - 1];
|
|
136
|
+
if (Array.isArray(parent) && typeof key === "number") parent.splice(key, 1);
|
|
137
|
+
else if (isJsonObject(parent) && typeof key === "string") delete parent[key];
|
|
138
|
+
else throw new OpenApiOverlayError("An Overlay remove action selected an invalid parent node.");
|
|
139
|
+
}
|
|
140
|
+
function mergeObjectValues(target, update, location) {
|
|
141
|
+
const result = structuredClone(target);
|
|
142
|
+
for (const [key, updateValue] of Object.entries(update)) {
|
|
143
|
+
if (!(key in result)) {
|
|
144
|
+
result[key] = structuredClone(updateValue);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const targetValue = result[key];
|
|
148
|
+
if (isJsonObject(targetValue) && isJsonObject(updateValue)) result[key] = mergeObjectValues(targetValue, updateValue, `${location}.${key}`);
|
|
149
|
+
else if (Array.isArray(targetValue) && Array.isArray(updateValue)) result[key] = [...targetValue, ...structuredClone(updateValue)];
|
|
150
|
+
else if (isJsonPrimitive(targetValue) && isJsonPrimitive(updateValue)) result[key] = updateValue;
|
|
151
|
+
else throw new OpenApiOverlayError(`${location} cannot merge incompatible values for \`${key}\`.`);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
function applyUpdate(target, update, version, location) {
|
|
156
|
+
if (isJsonObject(target)) {
|
|
157
|
+
if (!isJsonObject(update)) throw new OpenApiOverlayError(`${location} must use an object update for an object target.`);
|
|
158
|
+
return mergeObjectValues(target, update, location);
|
|
159
|
+
}
|
|
160
|
+
if (Array.isArray(target)) return Array.isArray(update) ? [...target, ...structuredClone(update)] : [...target, structuredClone(update)];
|
|
161
|
+
if (version === "1.0") throw new OpenApiOverlayError(`${location} selects a primitive, which Overlay 1.0 cannot update.`);
|
|
162
|
+
if (!isJsonPrimitive(update)) throw new OpenApiOverlayError(`${location} must use a primitive update for a primitive target.`);
|
|
163
|
+
return update;
|
|
164
|
+
}
|
|
165
|
+
function queryPaths(document, expression, location) {
|
|
166
|
+
try {
|
|
167
|
+
return paths(document, expression);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
throw new OpenApiOverlayError(`${location} contains invalid RFC 9535 JSONPath: ${error instanceof Error ? error.message : String(error)}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function queryCopyValue(document, expression, location) {
|
|
173
|
+
let values;
|
|
174
|
+
try {
|
|
175
|
+
values = query(document, expression);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
throw new OpenApiOverlayError(`${location} contains invalid RFC 9535 JSONPath: ${error instanceof Error ? error.message : String(error)}`);
|
|
178
|
+
}
|
|
179
|
+
if (values.length !== 1) throw new OpenApiOverlayError(`${location} must select exactly one node, but selected ${values.length}.`);
|
|
180
|
+
return structuredClone(values[0]);
|
|
181
|
+
}
|
|
182
|
+
function compareRemovalPaths(a, b) {
|
|
183
|
+
if (a.length !== b.length) return b.length - a.length;
|
|
184
|
+
const aLast = a[a.length - 1];
|
|
185
|
+
const bLast = b[b.length - 1];
|
|
186
|
+
return typeof aLast === "number" && typeof bLast === "number" ? bLast - aLast : 0;
|
|
187
|
+
}
|
|
188
|
+
function getJsonValueKind(value) {
|
|
189
|
+
if (Array.isArray(value)) return "array";
|
|
190
|
+
return isJsonObject(value) ? "object" : "primitive";
|
|
191
|
+
}
|
|
192
|
+
function applyOpenApiOverlayDocuments(document, overlays) {
|
|
193
|
+
let result = structuredClone(document);
|
|
194
|
+
for (const overlaySource of overlays) {
|
|
195
|
+
const overlay = validateOverlay(overlaySource.document, overlaySource.source);
|
|
196
|
+
for (const [actionIndex, action] of overlay.actions.entries()) {
|
|
197
|
+
const location = `${overlaySource.source} action ${actionIndex + 1}`;
|
|
198
|
+
const normalizedPaths = queryPaths(result, action.target, `${location} \`target\``);
|
|
199
|
+
if (normalizedPaths.length === 0) throw new OpenApiOverlayError(`${location} target \`${action.target}\` did not match any nodes.`);
|
|
200
|
+
const selectedPaths = normalizedPaths.map(parseNormalizedJsonPath);
|
|
201
|
+
if (action.remove === true) {
|
|
202
|
+
for (const path of selectedPaths.sort(compareRemovalPaths)) removeAtPath(result, path);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const hasUpdate = Object.prototype.hasOwnProperty.call(action, "update");
|
|
206
|
+
const hasCopy = typeof action.copy === "string";
|
|
207
|
+
if (!hasUpdate && !hasCopy) continue;
|
|
208
|
+
if (new Set(selectedPaths.map((path) => getJsonValueKind(getAtPath(result, path)))).size > 1) throw new OpenApiOverlayError(`${location} must select only objects, only arrays, or only primitives for an update or copy action.`);
|
|
209
|
+
const updateValue = hasUpdate ? action.update : queryCopyValue(result, action.copy, `${location} \`copy\``);
|
|
210
|
+
for (const path of selectedPaths) {
|
|
211
|
+
const updated = applyUpdate(getAtPath(result, path), updateValue, overlay.version, location);
|
|
212
|
+
result = setAtPath(result, path, updated);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!isJsonObject(result)) throw new OpenApiOverlayError("OpenAPI Overlay actions must leave an object document root.");
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
//#endregion
|
|
221
|
+
export { applyOpenApiOverlayDocuments };
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
//#region src/openapi-references.ts
|
|
4
|
+
const OPENAPI_BUNDLED_REFERENCES_EXTENSION = "x-farming-labs-references";
|
|
5
|
+
const OPENAPI_REFERENCE_MAX_DOCUMENTS = 32;
|
|
6
|
+
function resolveOpenApiReferencesSync(document, options) {
|
|
7
|
+
const sourceUri = normalizeDocumentUri(options.sourceUri);
|
|
8
|
+
const entry = createDocumentState({
|
|
9
|
+
uri: sourceUri,
|
|
10
|
+
document
|
|
11
|
+
}, true);
|
|
12
|
+
const documents = /* @__PURE__ */ new Map();
|
|
13
|
+
registerDocument(documents, entry, sourceUri);
|
|
14
|
+
const bundle = {};
|
|
15
|
+
const maxDocuments = normalizeMaxDocuments(options.maxDocuments);
|
|
16
|
+
const getDocument = (requestedUri, fromUri) => {
|
|
17
|
+
const normalizedRequest = normalizeDocumentUri(requestedUri);
|
|
18
|
+
const cached = documents.get(normalizedRequest);
|
|
19
|
+
if (cached) return cached;
|
|
20
|
+
if (!options.loadDocument) throw new Error(`OpenAPI reference requires an external document: ${normalizedRequest}`);
|
|
21
|
+
if (countDocuments(documents) >= maxDocuments) throw new Error(`OpenAPI references exceed the ${maxDocuments}-document limit.`);
|
|
22
|
+
const state = createDocumentState(options.loadDocument(new URL(normalizedRequest), new URL(fromUri)), false);
|
|
23
|
+
registerDocument(documents, state, normalizedRequest);
|
|
24
|
+
return state;
|
|
25
|
+
};
|
|
26
|
+
const processDocument = (state) => {
|
|
27
|
+
if (state.processed || state.processing) return state.output;
|
|
28
|
+
state.processing = true;
|
|
29
|
+
state.output = structuredClone(state.document);
|
|
30
|
+
if (!state.entry) {
|
|
31
|
+
state.bundleKey = createBundleKey(state.retrievalUri);
|
|
32
|
+
bundle[state.bundleKey] = state.output;
|
|
33
|
+
}
|
|
34
|
+
rewriteReferencesSync(state.output, state, getDocument, processDocument);
|
|
35
|
+
state.processing = false;
|
|
36
|
+
state.processed = true;
|
|
37
|
+
return state.output;
|
|
38
|
+
};
|
|
39
|
+
const output = processDocument(entry);
|
|
40
|
+
if (!isRecord(output)) throw new Error("The OpenAPI entry document must be an object.");
|
|
41
|
+
if (Object.keys(bundle).length > 0) {
|
|
42
|
+
if (Object.hasOwn(output, OPENAPI_BUNDLED_REFERENCES_EXTENSION)) throw new Error(`The OpenAPI document uses the reserved \`${OPENAPI_BUNDLED_REFERENCES_EXTENSION}\` extension.`);
|
|
43
|
+
output[OPENAPI_BUNDLED_REFERENCES_EXTENSION] = bundle;
|
|
44
|
+
}
|
|
45
|
+
return output;
|
|
46
|
+
}
|
|
47
|
+
async function resolveOpenApiReferences(document, options) {
|
|
48
|
+
const sourceUri = normalizeDocumentUri(options.sourceUri);
|
|
49
|
+
const entry = createDocumentState({
|
|
50
|
+
uri: sourceUri,
|
|
51
|
+
document
|
|
52
|
+
}, true);
|
|
53
|
+
const documents = /* @__PURE__ */ new Map();
|
|
54
|
+
registerDocument(documents, entry, sourceUri);
|
|
55
|
+
const bundle = {};
|
|
56
|
+
const maxDocuments = normalizeMaxDocuments(options.maxDocuments);
|
|
57
|
+
const getDocument = async (requestedUri, fromUri) => {
|
|
58
|
+
const normalizedRequest = normalizeDocumentUri(requestedUri);
|
|
59
|
+
const cached = documents.get(normalizedRequest);
|
|
60
|
+
if (cached) return cached;
|
|
61
|
+
if (!options.loadDocument) throw new Error(`OpenAPI reference requires an external document: ${normalizedRequest}`);
|
|
62
|
+
if (countDocuments(documents) >= maxDocuments) throw new Error(`OpenAPI references exceed the ${maxDocuments}-document limit.`);
|
|
63
|
+
const state = createDocumentState(await options.loadDocument(new URL(normalizedRequest), new URL(fromUri)), false);
|
|
64
|
+
registerDocument(documents, state, normalizedRequest);
|
|
65
|
+
return state;
|
|
66
|
+
};
|
|
67
|
+
const processDocument = async (state) => {
|
|
68
|
+
if (state.processed || state.processing) return state.output;
|
|
69
|
+
state.processing = true;
|
|
70
|
+
state.output = structuredClone(state.document);
|
|
71
|
+
if (!state.entry) {
|
|
72
|
+
state.bundleKey = createBundleKey(state.retrievalUri);
|
|
73
|
+
bundle[state.bundleKey] = state.output;
|
|
74
|
+
}
|
|
75
|
+
await rewriteReferences(state.output, state, getDocument, processDocument);
|
|
76
|
+
state.processing = false;
|
|
77
|
+
state.processed = true;
|
|
78
|
+
return state.output;
|
|
79
|
+
};
|
|
80
|
+
const output = await processDocument(entry);
|
|
81
|
+
if (!isRecord(output)) throw new Error("The OpenAPI entry document must be an object.");
|
|
82
|
+
if (Object.keys(bundle).length > 0) {
|
|
83
|
+
if (Object.hasOwn(output, OPENAPI_BUNDLED_REFERENCES_EXTENSION)) throw new Error(`The OpenAPI document uses the reserved \`${OPENAPI_BUNDLED_REFERENCES_EXTENSION}\` extension.`);
|
|
84
|
+
output[OPENAPI_BUNDLED_REFERENCES_EXTENSION] = bundle;
|
|
85
|
+
}
|
|
86
|
+
return output;
|
|
87
|
+
}
|
|
88
|
+
function rewriteReferencesSync(value, currentDocument, getDocument, processDocument, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
89
|
+
if (!value || typeof value !== "object") return;
|
|
90
|
+
if (ancestors.has(value)) throw new Error("OpenAPI source documents cannot contain cyclic YAML aliases.");
|
|
91
|
+
ancestors.add(value);
|
|
92
|
+
if (Array.isArray(value)) {
|
|
93
|
+
for (const item of value) rewriteReferencesSync(item, currentDocument, getDocument, processDocument, ancestors);
|
|
94
|
+
ancestors.delete(value);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const record = value;
|
|
98
|
+
if (Object.hasOwn(record, "$ref")) record.$ref = rewriteReferenceSync(record.$ref, currentDocument, getDocument, processDocument);
|
|
99
|
+
for (const [key, child] of Object.entries(record)) {
|
|
100
|
+
if (key === "$ref") continue;
|
|
101
|
+
rewriteReferencesSync(child, currentDocument, getDocument, processDocument, ancestors);
|
|
102
|
+
}
|
|
103
|
+
ancestors.delete(value);
|
|
104
|
+
}
|
|
105
|
+
async function rewriteReferences(value, currentDocument, getDocument, processDocument, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
106
|
+
if (!value || typeof value !== "object") return;
|
|
107
|
+
if (ancestors.has(value)) throw new Error("OpenAPI source documents cannot contain cyclic YAML aliases.");
|
|
108
|
+
ancestors.add(value);
|
|
109
|
+
if (Array.isArray(value)) {
|
|
110
|
+
for (const item of value) await rewriteReferences(item, currentDocument, getDocument, processDocument, ancestors);
|
|
111
|
+
ancestors.delete(value);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const record = value;
|
|
115
|
+
if (Object.hasOwn(record, "$ref")) record.$ref = await rewriteReference(record.$ref, currentDocument, getDocument, processDocument);
|
|
116
|
+
for (const [key, child] of Object.entries(record)) {
|
|
117
|
+
if (key === "$ref") continue;
|
|
118
|
+
await rewriteReferences(child, currentDocument, getDocument, processDocument, ancestors);
|
|
119
|
+
}
|
|
120
|
+
ancestors.delete(value);
|
|
121
|
+
}
|
|
122
|
+
function rewriteReferenceSync(reference, currentDocument, getDocument, processDocument) {
|
|
123
|
+
const target = resolveReference(reference, currentDocument.baseUri);
|
|
124
|
+
const targetDocument = getDocument(target.documentUri, currentDocument.baseUri);
|
|
125
|
+
assertReferenceTarget(targetDocument.document, target.pointer, reference);
|
|
126
|
+
processDocument(targetDocument);
|
|
127
|
+
return buildBundledReference(targetDocument, target.pointer);
|
|
128
|
+
}
|
|
129
|
+
async function rewriteReference(reference, currentDocument, getDocument, processDocument) {
|
|
130
|
+
const target = resolveReference(reference, currentDocument.baseUri);
|
|
131
|
+
const targetDocument = await getDocument(target.documentUri, currentDocument.baseUri);
|
|
132
|
+
assertReferenceTarget(targetDocument.document, target.pointer, reference);
|
|
133
|
+
await processDocument(targetDocument);
|
|
134
|
+
return buildBundledReference(targetDocument, target.pointer);
|
|
135
|
+
}
|
|
136
|
+
function resolveReference(reference, baseUri) {
|
|
137
|
+
if (typeof reference !== "string" || !reference.trim()) throw new Error("OpenAPI `$ref` values must be non-empty URI strings.");
|
|
138
|
+
let url;
|
|
139
|
+
try {
|
|
140
|
+
url = new URL(reference, baseUri);
|
|
141
|
+
} catch {
|
|
142
|
+
throw new Error(`OpenAPI reference is not a valid URI: ${reference}`);
|
|
143
|
+
}
|
|
144
|
+
const pointer = normalizePointerFragment(url.hash, reference);
|
|
145
|
+
url.hash = "";
|
|
146
|
+
return {
|
|
147
|
+
documentUri: url.href,
|
|
148
|
+
pointer
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function normalizePointerFragment(hash, reference) {
|
|
152
|
+
if (!hash || hash === "#") return "";
|
|
153
|
+
let decoded;
|
|
154
|
+
try {
|
|
155
|
+
decoded = decodeURIComponent(hash.slice(1));
|
|
156
|
+
} catch {
|
|
157
|
+
throw new Error(`OpenAPI reference has an invalid encoded fragment: ${String(reference)}`);
|
|
158
|
+
}
|
|
159
|
+
if (!decoded.startsWith("/")) throw new Error(`OpenAPI reference anchors are not supported yet; use a JSON Pointer fragment: ${String(reference)}`);
|
|
160
|
+
return decoded;
|
|
161
|
+
}
|
|
162
|
+
function assertReferenceTarget(document, pointer, reference) {
|
|
163
|
+
if (!pointer) return;
|
|
164
|
+
let current = document;
|
|
165
|
+
for (const token of pointer.slice(1).split("/")) {
|
|
166
|
+
if (!current || typeof current !== "object") throw new Error(`OpenAPI reference target was not found: ${String(reference)}`);
|
|
167
|
+
const key = decodeJsonPointerToken(token, reference);
|
|
168
|
+
if (!Object.hasOwn(current, key)) throw new Error(`OpenAPI reference target was not found: ${String(reference)}`);
|
|
169
|
+
current = current[key];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function decodeJsonPointerToken(token, reference) {
|
|
173
|
+
if (/~(?:[^01]|$)/.test(token)) throw new Error(`OpenAPI reference has an invalid JSON Pointer fragment: ${String(reference)}`);
|
|
174
|
+
return token.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
175
|
+
}
|
|
176
|
+
function buildBundledReference(document, pointer) {
|
|
177
|
+
if (document.entry) return `#${pointer}`;
|
|
178
|
+
if (!document.bundleKey) throw new Error(`OpenAPI reference document was not bundled: ${document.retrievalUri}`);
|
|
179
|
+
return `#/${OPENAPI_BUNDLED_REFERENCES_EXTENSION}/${escapeJsonPointer(document.bundleKey)}${pointer}`;
|
|
180
|
+
}
|
|
181
|
+
function createDocumentState(loaded, entry) {
|
|
182
|
+
const retrievalUri = normalizeDocumentUri(loaded.uri);
|
|
183
|
+
const self = isRecord(loaded.document) ? loaded.document.$self : void 0;
|
|
184
|
+
let baseUri = retrievalUri;
|
|
185
|
+
if (typeof self === "string" && self.trim()) try {
|
|
186
|
+
baseUri = normalizeDocumentUri(new URL(self, retrievalUri).href);
|
|
187
|
+
} catch {
|
|
188
|
+
throw new Error(`OpenAPI document has an invalid \`$self\` URI: ${self}`);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
retrievalUri,
|
|
192
|
+
baseUri,
|
|
193
|
+
document: loaded.document,
|
|
194
|
+
entry,
|
|
195
|
+
processing: false,
|
|
196
|
+
processed: false
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function registerDocument(documents, document, requestedUri) {
|
|
200
|
+
for (const uri of [
|
|
201
|
+
requestedUri,
|
|
202
|
+
document.retrievalUri,
|
|
203
|
+
document.baseUri
|
|
204
|
+
]) {
|
|
205
|
+
const normalized = normalizeDocumentUri(uri);
|
|
206
|
+
const existing = documents.get(normalized);
|
|
207
|
+
if (existing && existing !== document) throw new Error(`Multiple OpenAPI documents claim the same base URI: ${normalized}`);
|
|
208
|
+
documents.set(normalized, document);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function countDocuments(documents) {
|
|
212
|
+
return new Set(documents.values()).size;
|
|
213
|
+
}
|
|
214
|
+
function normalizeDocumentUri(value) {
|
|
215
|
+
const url = new URL(value);
|
|
216
|
+
url.hash = "";
|
|
217
|
+
return url.href;
|
|
218
|
+
}
|
|
219
|
+
function normalizeMaxDocuments(value) {
|
|
220
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : OPENAPI_REFERENCE_MAX_DOCUMENTS;
|
|
221
|
+
}
|
|
222
|
+
function createBundleKey(uri) {
|
|
223
|
+
return `ref-${createHash("sha256").update(uri).digest("hex").slice(0, 16)}`;
|
|
224
|
+
}
|
|
225
|
+
function escapeJsonPointer(value) {
|
|
226
|
+
return value.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
227
|
+
}
|
|
228
|
+
function isRecord(value) {
|
|
229
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
//#endregion
|
|
233
|
+
export { resolveOpenApiReferences, resolveOpenApiReferencesSync };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { digestDocsRetrievalContent } from "./retrieval-digest.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/pagination.ts
|
|
4
|
+
const DOCS_PAGINATION_CURSOR_VERSION = 1;
|
|
5
|
+
const MAX_DOCS_PAGINATION_CURSOR_CHARS = 4096;
|
|
6
|
+
const MAX_DOCS_PAGINATION_STATE_CHARS = 1024;
|
|
7
|
+
const MAX_DOCS_PAGINATION_OFFSET = 1e7;
|
|
8
|
+
const DOCS_PAGINATION_DIGEST_PATTERN = /^sha256:[a-f\d]{64}$/u;
|
|
9
|
+
var DocsPaginationCursorError = class extends Error {
|
|
10
|
+
code = "invalid_cursor";
|
|
11
|
+
constructor() {
|
|
12
|
+
super("Invalid or stale pagination cursor.");
|
|
13
|
+
this.name = "DocsPaginationCursorError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function paginationDigest(label, value) {
|
|
17
|
+
return digestDocsRetrievalContent(`${label}\0${value}`);
|
|
18
|
+
}
|
|
19
|
+
function cursorChecksum(payload) {
|
|
20
|
+
return paginationDigest("docs-pagination-checksum.v1", JSON.stringify(payload));
|
|
21
|
+
}
|
|
22
|
+
function encodeBase64Url(value) {
|
|
23
|
+
const bytes = new TextEncoder().encode(value);
|
|
24
|
+
let binary = "";
|
|
25
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
26
|
+
return btoa(binary).replace(/\+/gu, "-").replace(/\//gu, "_").replace(/=+$/u, "");
|
|
27
|
+
}
|
|
28
|
+
function decodeBase64Url(value) {
|
|
29
|
+
const padded = `${value.replace(/-/gu, "+").replace(/_/gu, "/")}${"=".repeat((4 - value.length % 4) % 4)}`;
|
|
30
|
+
const binary = atob(padded);
|
|
31
|
+
const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
32
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
33
|
+
}
|
|
34
|
+
function isDigest(value) {
|
|
35
|
+
return typeof value === "string" && DOCS_PAGINATION_DIGEST_PATTERN.test(value);
|
|
36
|
+
}
|
|
37
|
+
function assertCursorOptions(options) {
|
|
38
|
+
if (!/^[a-z][a-z\d._/-]{0,127}$/u.test(options.kind) || typeof options.scope !== "string" || typeof options.snapshot !== "string") throw new TypeError("Pagination cursor options must contain a valid kind, scope, and snapshot.");
|
|
39
|
+
}
|
|
40
|
+
function createDocsPaginationCursor(offset, options) {
|
|
41
|
+
assertCursorOptions(options);
|
|
42
|
+
if (!Number.isSafeInteger(offset) || offset <= 0 || offset > MAX_DOCS_PAGINATION_OFFSET) throw new TypeError("Pagination cursor offsets must be positive safe integers.");
|
|
43
|
+
if (options.state !== void 0 && (options.state.length === 0 || options.state.length > MAX_DOCS_PAGINATION_STATE_CHARS)) throw new TypeError("Pagination provider state must be a bounded, non-empty string.");
|
|
44
|
+
const unsigned = [
|
|
45
|
+
DOCS_PAGINATION_CURSOR_VERSION,
|
|
46
|
+
options.kind,
|
|
47
|
+
offset,
|
|
48
|
+
paginationDigest("docs-pagination-scope.v1", options.scope),
|
|
49
|
+
paginationDigest("docs-pagination-snapshot.v1", options.snapshot),
|
|
50
|
+
options.state ?? null
|
|
51
|
+
];
|
|
52
|
+
return encodeBase64Url(JSON.stringify([...unsigned, cursorChecksum(unsigned)]));
|
|
53
|
+
}
|
|
54
|
+
function resolveDocsPaginationCursor(cursor, options) {
|
|
55
|
+
assertCursorOptions(options);
|
|
56
|
+
if (cursor === void 0) return { offset: 0 };
|
|
57
|
+
if (cursor.length === 0 || cursor.length > MAX_DOCS_PAGINATION_CURSOR_CHARS || !/^[A-Za-z\d_-]+$/u.test(cursor)) throw new DocsPaginationCursorError();
|
|
58
|
+
let parsed;
|
|
59
|
+
try {
|
|
60
|
+
parsed = JSON.parse(decodeBase64Url(cursor));
|
|
61
|
+
} catch {
|
|
62
|
+
throw new DocsPaginationCursorError();
|
|
63
|
+
}
|
|
64
|
+
if (!Array.isArray(parsed) || parsed.length !== 7 || encodeBase64Url(JSON.stringify(parsed)) !== cursor) throw new DocsPaginationCursorError();
|
|
65
|
+
const [version, kind, offset, scopeDigest, snapshotDigest, state, checksum] = parsed;
|
|
66
|
+
const unsigned = [
|
|
67
|
+
version,
|
|
68
|
+
kind,
|
|
69
|
+
offset,
|
|
70
|
+
scopeDigest,
|
|
71
|
+
snapshotDigest,
|
|
72
|
+
state
|
|
73
|
+
];
|
|
74
|
+
if (version !== DOCS_PAGINATION_CURSOR_VERSION || kind !== options.kind || !Number.isSafeInteger(offset) || offset <= 0 || offset > MAX_DOCS_PAGINATION_OFFSET || !isDigest(scopeDigest) || !isDigest(snapshotDigest) || !(state === null || typeof state === "string" && state.length > 0 && state.length <= MAX_DOCS_PAGINATION_STATE_CHARS) || !isDigest(checksum) || scopeDigest !== paginationDigest("docs-pagination-scope.v1", options.scope) || snapshotDigest !== paginationDigest("docs-pagination-snapshot.v1", options.snapshot) || checksum !== cursorChecksum(unsigned)) throw new DocsPaginationCursorError();
|
|
75
|
+
return {
|
|
76
|
+
offset,
|
|
77
|
+
...typeof state === "string" ? { state } : {}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function resolveDocsPaginationOffset(cursor, options) {
|
|
81
|
+
return resolveDocsPaginationCursor(cursor, options).offset;
|
|
82
|
+
}
|
|
83
|
+
function paginateDocsItems(items, options) {
|
|
84
|
+
if (!Number.isSafeInteger(options.pageSize) || options.pageSize <= 0) throw new TypeError("Pagination page sizes must be positive safe integers.");
|
|
85
|
+
const offset = resolveDocsPaginationOffset(options.cursor, options);
|
|
86
|
+
if (offset >= items.length && options.cursor !== void 0) throw new DocsPaginationCursorError();
|
|
87
|
+
const pageItems = items.slice(offset, offset + options.pageSize);
|
|
88
|
+
const nextOffset = offset + pageItems.length;
|
|
89
|
+
const hasMore = nextOffset < items.length;
|
|
90
|
+
return {
|
|
91
|
+
items: pageItems,
|
|
92
|
+
resultCount: pageItems.length,
|
|
93
|
+
total: items.length,
|
|
94
|
+
hasMore,
|
|
95
|
+
...hasMore ? { nextCursor: createDocsPaginationCursor(nextOffset, options) } : {}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
export { DocsPaginationCursorError, createDocsPaginationCursor, paginateDocsItems, resolveDocsPaginationCursor, resolveDocsPaginationOffset };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/prompt-references.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Keep `<Prompt>` children literal before Markdown reference definitions are
|
|
4
|
+
* resolved by the MDX compiler.
|
|
5
|
+
*
|
|
6
|
+
* Definitions inside Prompt are copyable source, not page-level definitions.
|
|
7
|
+
* References inside Prompt always remain source text, while references outside
|
|
8
|
+
* Prompt only remain live when they have a definition outside Prompt.
|
|
9
|
+
*/
|
|
10
|
+
declare function isolateDocsMarkdownPromptReferences(root: unknown, value?: unknown): void;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { isolateDocsMarkdownPromptReferences };
|