@shoalrun/cli 0.1.0-alpha.19 → 1.0.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 +30 -0
- package/CODE-REFERENCES.md +137 -0
- package/README.md +19 -6
- package/adapters/python/requirements.txt +1 -0
- package/adapters/python/shoalrun_reference.py +234 -0
- package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +7 -3
- package/agent-docs/SNAPSHOT.json +5 -5
- package/agent-docs/about.md +3 -3
- package/agent-docs/api-docs/code-reference-settings.md +160 -0
- package/agent-docs/api-docs/code-reference-settings.sections/catalog-settings.md +50 -0
- package/agent-docs/api-docs/code-reference-settings.sections/complete-reference-page.md +46 -0
- package/agent-docs/api-docs/code-reference-settings.sections/converter-snapshot.md +58 -0
- package/agent-docs/api-docs/code-reference-settings.sections/descriptions-type-links-and-source-links.md +40 -0
- package/agent-docs/api-docs/code-reference-settings.sections/html-markdown-and-agents.md +38 -0
- package/agent-docs/api-docs/code-reference-settings.sections/metadata-and-selection.md +38 -0
- package/agent-docs/api-docs/code-reference-settings.sections/publication-sources.md +54 -0
- package/agent-docs/api-docs/code-reference-settings.sections/python-adapter-limits.md +38 -0
- package/agent-docs/api-docs/code-reference-settings.sections/related-reading.md +32 -0
- package/agent-docs/api-docs/code-reference-settings.sections/symbol-fields.md +56 -0
- package/agent-docs/api-docs/code-references.md +143 -0
- package/agent-docs/author/agent-overview.md +2 -2
- package/agent-docs/author/components/code-blocks.md +46 -1
- package/agent-docs/author/frontmatter-reference.md +1 -0
- package/agent-docs/author/frontmatter-reference.sections/categorize-connect-and-present-the-page.md +1 -0
- package/agent-docs/author/workspace.md +2 -2
- package/agent-docs/author/writing-style.md +9 -3
- package/agent-docs/author/writing-style.sections/adapt-this-example.md +1 -1
- package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +2 -2
- package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +1 -1
- package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +1 -1
- package/agent-docs/author/writing-style.sections/feature-availability.md +1 -1
- package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +1 -1
- package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +2 -2
- package/agent-docs/author/writing-style.sections/procedures-and-examples.md +1 -1
- package/agent-docs/author/writing-style.sections/related-reading.md +1 -1
- package/agent-docs/author/writing-style.sections/release-notes.md +30 -0
- package/agent-docs/author/writing-style.sections/review-a-draft.md +1 -1
- package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +1 -1
- package/agent-docs/author/writing-style.sections/voice-and-explanations.md +1 -1
- package/agent-docs/changelog/2026-10-16-navigation-layouts.md +1 -1
- package/agent-docs/changelog/code-api-references.md +44 -0
- package/agent-docs/changelog/pdf-custom-languages.md +48 -0
- package/agent-docs/changelog.md +17 -1
- package/agent-docs/cli.md +11 -1
- package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +1 -1
- package/agent-docs/cli.sections/author-pages.md +1 -1
- package/agent-docs/cli.sections/build-and-serve.md +1 -1
- package/agent-docs/cli.sections/inspect-config-and-operations.md +1 -1
- package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +1 -1
- package/agent-docs/cli.sections/related-reading.md +1 -1
- package/agent-docs/cli.sections/search-and-chat.md +1 -1
- package/agent-docs/cli.sections/start-a-project.md +1 -1
- package/agent-docs/cli.sections/validate-code-reference-snapshots.md +41 -0
- package/agent-docs/cli.sections/working-tree-authoring-tools.md +1 -1
- package/agent-docs/config/apis.md +5 -1
- package/agent-docs/config/examples.md +3 -3
- package/agent-docs/config/examples.sections/feature-showcase.md +3 -3
- package/agent-docs/config/examples.sections/minimal-site.md +2 -2
- package/agent-docs/config/examples.sections/multilingual-help-center.md +2 -2
- package/agent-docs/config/examples.sections/parcel-api-documentation.md +2 -2
- package/agent-docs/config/examples.sections/related-reading.md +2 -2
- package/agent-docs/config/examples.sections/shared-company-preset.md +2 -2
- package/agent-docs/config/outputs.md +33 -12
- package/agent-docs/config/outputs.sections/exports.md +3 -3
- package/agent-docs/config/outputs.sections/metadata.md +3 -3
- package/agent-docs/config/outputs.sections/pdf-output.md +51 -0
- package/agent-docs/config/outputs.sections/related-reading.md +3 -3
- package/agent-docs/config.md +2 -2
- package/agent-docs/configuration.md +2 -2
- package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +1 -1
- package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +1 -1
- package/agent-docs/configuration.sections/extract-a-section-with-include.md +1 -1
- package/agent-docs/configuration.sections/inspect-and-validate-changes.md +1 -1
- package/agent-docs/configuration.sections/related-reading.md +1 -1
- package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +1 -1
- package/agent-docs/configuration.sections/share-defaults-through-extends.md +1 -1
- package/agent-docs/configuration.sections/start-with-one-working-file.md +2 -2
- package/agent-docs/configuration.sections/understand-the-three-stages.md +1 -1
- package/agent-docs/configuration.sections/understand-where-paths-point.md +1 -1
- package/agent-docs/contribute/agent-skills.md +3 -1
- package/agent-docs/documents.json +1009 -356
- package/agent-docs/features.md +6 -2
- package/agent-docs/index.md +2 -2
- package/agent-docs/provenance.json +6 -6
- package/agent-docs/publish/api-references.md +3 -1
- package/agent-docs/publish/api-references.sections/author-the-reference-page.md +3 -1
- package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +3 -1
- package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +3 -1
- package/agent-docs/publish/api-references.sections/next-steps.md +3 -1
- package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +3 -1
- package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +3 -1
- package/agent-docs/publish/api-references.sections/register-the-operation.md +3 -1
- package/agent-docs/publish/api-references.sections/related-reading.md +3 -1
- package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +3 -1
- package/agent-docs/publish/api-references.sections/what-readers-get.md +3 -1
- package/agent-docs/publish/content-export.md +2 -0
- package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +2 -0
- package/agent-docs/publish/content-export.sections/check-the-result.md +2 -0
- package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +2 -0
- package/agent-docs/publish/content-export.sections/prerequisites.md +2 -0
- package/agent-docs/publish/content-export.sections/related-reading.md +2 -0
- package/agent-docs/publish/content-export.sections/review-exported-api-material.md +2 -0
- package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +2 -0
- package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +2 -0
- package/agent-docs/publish/pdf.md +184 -0
- package/agent-docs/publish/pdf.sections/apply-print-styling.md +65 -0
- package/agent-docs/publish/pdf.sections/check-the-result.md +33 -0
- package/agent-docs/publish/pdf.sections/export-a-page-or-publication.md +61 -0
- package/agent-docs/publish/pdf.sections/html-markdown-and-agents.md +31 -0
- package/agent-docs/publish/pdf.sections/offer-browser-page-printing.md +49 -0
- package/agent-docs/publish/pdf.sections/offer-direct-downloads-through-a-node-server.md +46 -0
- package/agent-docs/publish/pdf.sections/prerequisites.md +37 -0
- package/agent-docs/publish/pdf.sections/publish-an-optional-manual-download.md +39 -0
- package/agent-docs/publish.md +2 -0
- package/agent-docs/reference/agent-skills.md +7 -3
- package/agent-docs/search-index.json +1 -1
- package/agent-docs/start.md +4 -4
- package/agent-docs/start.sections/add-the-page-to-navigation.md +2 -2
- package/agent-docs/start.sections/build-and-check-both-outputs.md +2 -2
- package/agent-docs/start.sections/build-this-site.md +2 -2
- package/agent-docs/start.sections/check-writing-style.md +2 -2
- package/agent-docs/start.sections/create-a-page.md +2 -2
- package/agent-docs/start.sections/make-it-yours.md +2 -2
- package/agent-docs/start.sections/migrating-from-github-packages.md +2 -2
- package/agent-docs/start.sections/prerequisites.md +2 -2
- package/agent-docs/start.sections/related-reading.md +2 -2
- package/agent-docs/start.sections/start-your-own-project.md +4 -4
- package/agent-docs/status.md +9 -5
- package/agent-docs/styling/themes.md +7 -3
- package/agent-docs/what-is-shoalrun.md +2 -2
- package/assets/copy-markdown.js +1 -1
- package/assets/print-view.js +165 -0
- package/assets/print.js +63 -0
- package/dist/artifact-bundle.d.ts +2 -0
- package/dist/artifact-bundle.js +13 -3
- package/dist/authoring-snapshot.js +1 -1
- package/dist/browser-print-assets.d.ts +9 -0
- package/dist/browser-print-assets.js +45 -0
- package/dist/cli-discovery.d.ts +1 -1
- package/dist/cli-discovery.js +1 -0
- package/dist/cli.js +7 -0
- package/dist/code-reference-model.d.ts +85 -0
- package/dist/code-reference-model.js +73 -0
- package/dist/code-references.d.ts +23 -0
- package/dist/code-references.js +371 -0
- package/dist/compiler-config.d.ts +1 -0
- package/dist/compiler.d.ts +4 -2
- package/dist/compiler.js +33 -7
- package/dist/config.js +1 -1
- package/dist/content-export-command.d.ts +77 -1
- package/dist/content-export-command.js +5 -2
- package/dist/content-export-config.d.ts +4 -1
- package/dist/content-export-config.js +10 -5
- package/dist/content-export-render.d.ts +9 -3
- package/dist/content-export-render.js +11 -7
- package/dist/content-export.d.ts +126 -0
- package/dist/content-export.js +267 -124
- package/dist/content-source.d.ts +2 -0
- package/dist/content-workspace.d.ts +1 -0
- package/dist/content-workspace.js +2 -0
- package/dist/fonts.d.ts +9 -0
- package/dist/fonts.js +58 -3
- package/dist/frontmatter.js +5 -2
- package/dist/highlight-languages.d.ts +9 -0
- package/dist/highlight-languages.js +52 -0
- package/dist/highlight.d.ts +4 -1
- package/dist/highlight.js +20 -5
- package/dist/output-commit.d.ts +1 -1
- package/dist/output-commit.js +4 -2
- package/dist/page-materialization.js +3 -2
- package/dist/page-renderer.d.ts +1 -0
- package/dist/page-renderer.js +8 -1
- package/dist/pdf-button.d.ts +22 -0
- package/dist/pdf-button.js +55 -0
- package/dist/pdf-config.d.ts +28 -0
- package/dist/pdf-config.js +43 -0
- package/dist/pdf-http.d.ts +36 -0
- package/dist/pdf-http.js +132 -0
- package/dist/pdf-project.d.ts +6 -0
- package/dist/pdf-project.js +31 -0
- package/dist/pdf-renderer.d.ts +45 -0
- package/dist/pdf-renderer.js +208 -0
- package/dist/pdf-site.d.ts +37 -0
- package/dist/pdf-site.js +65 -0
- package/dist/pdf-stylesheet.d.ts +1 -0
- package/dist/pdf-stylesheet.js +57 -0
- package/dist/publication-render.d.ts +2 -1
- package/dist/publication-render.js +2 -2
- package/dist/representation-tree.js +5 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.js +35 -8
- package/dist/vercel.js +6 -0
- package/examples/code-references/content/start.md +53 -0
- package/examples/code-references/docs.config.yaml +262 -0
- package/examples/code-references/python/orchard/__init__.py +11 -0
- package/examples/code-references/python/orchard/client.py +212 -0
- package/examples/code-references/python/orchard/errors.py +31 -0
- package/examples/code-references/python/orchard/models.py +69 -0
- package/examples/code-references/python/orchard/pagination.py +39 -0
- package/examples/code-references/reference.json +1244 -0
- package/examples/custom-language/README.md +32 -0
- package/examples/custom-language/content/start.mdx +28 -0
- package/examples/custom-language/docs.config.yaml +18 -0
- package/examples/custom-language/grammars/custompy.tmLanguage.json +7 -0
- package/examples/pdf/README.md +27 -0
- package/examples/pdf/content/operations.mdx +26 -0
- package/examples/pdf/content/start.mdx +28 -0
- package/examples/pdf/docs.config.yaml +29 -0
- package/examples/pdf/print.css +9 -0
- package/package.json +11 -2
- package/schemas/code-reference.schema.json +306 -0
- package/skills/shoalrun-author/SKILL.md +6 -0
- package/skills/shoalrun-author/references/code-api-references.md +15 -0
- package/skills/shoalrun-author/references/pdf-export.md +15 -0
- package/skills/shoalrun-brand/SKILL.md +2 -0
- package/skills/shoalrun-pdf/SKILL.md +49 -0
- package/skills/shoalrun-pdf/assets/print.css +49 -0
- package/skills/shoalrun-pdf/references/print-design.md +75 -0
- package/styles/site.css +64 -3
|
@@ -53,7 +53,7 @@ export function publicTree(tree, representation, documentRoutes, mode = 'light',
|
|
|
53
53
|
if (node.type === 'docReaderSection') {
|
|
54
54
|
const children = node.children.flatMap(walk);
|
|
55
55
|
return representation === 'markdown' ? [paragraph({ type: 'strong', children: [text(`For ${node.description}.`)] }), ...children]
|
|
56
|
-
: [element('section', { className: ['reader-section'], 'data-reader-filters': JSON.stringify(node.selection) }, children)];
|
|
56
|
+
: [element('section', { className: ['reader-section'], 'data-reader-filters': JSON.stringify(node.selection), 'data-reader-print-label': `For ${node.description}.` }, children)];
|
|
57
57
|
}
|
|
58
58
|
if (node.type === 'docReaderChoice') {
|
|
59
59
|
if (representation === 'markdown') {
|
|
@@ -66,6 +66,10 @@ export function publicTree(tree, representation, documentRoutes, mode = 'light',
|
|
|
66
66
|
if (node.type === 'docReaderFilter') {
|
|
67
67
|
return representation === 'markdown' ? [] : [element('div', { className: ['reader-filter-slot'], 'data-reader-filter': JSON.stringify(node.control) }, [])];
|
|
68
68
|
}
|
|
69
|
+
if (node.type === 'table' && node.data?.referenceTableLabel && representation === 'html') {
|
|
70
|
+
const table = { ...node, children: node.children.flatMap(walk) };
|
|
71
|
+
return [element('div', { className: ['code-reference-table-scroll'], role: 'region', 'aria-label': node.data.referenceTableLabel, tabIndex: 0 }, [table])];
|
|
72
|
+
}
|
|
69
73
|
if (node.type === 'docTable') {
|
|
70
74
|
const table = node.children.flatMap(walk);
|
|
71
75
|
if (representation === 'markdown')
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type Server, type ServerResponse } from 'node:http';
|
|
2
|
+
export declare function canonicalSitePath(url: string): string;
|
|
3
|
+
export declare function privateSitePath(pathname: string): boolean;
|
|
2
4
|
export type PreviewStatus = {
|
|
3
5
|
profile?: string;
|
|
4
6
|
profileDigest?: string;
|
package/dist/server.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { loadMcpRuntime, createMcpHttpHandler } from './mcp-http.js';
|
|
2
2
|
import { bridgeMcp } from './mcp-node.js';
|
|
3
|
+
import { loadPdfRuntime, createPdfHttpHandler } from './pdf-http.js';
|
|
3
4
|
import { notFoundPage, addNotFoundTwin } from './not-found.js';
|
|
4
5
|
import { createServer } from 'node:http';
|
|
5
6
|
import { readFile, realpath, stat } from 'node:fs/promises';
|
|
6
7
|
import path from 'node:path';
|
|
7
8
|
import { homeUrl, negotiatedDocument } from './negotiation.js';
|
|
8
|
-
|
|
9
|
+
export function canonicalSitePath(url) {
|
|
10
|
+
const decoded = decodeURIComponent(new URL(url, 'http://localhost').pathname).replace(/\\/g, '/');
|
|
11
|
+
if (decoded.includes('\0') || decoded.split('/').some(segment => segment === '..' || segment === '.'))
|
|
12
|
+
throw new Error('Invalid path');
|
|
13
|
+
return decoded.replace(/\/{2,}/g, '/');
|
|
14
|
+
}
|
|
15
|
+
export function privateSitePath(pathname) {
|
|
16
|
+
const internal = pathname.toLowerCase().replace(/\/+$/, '');
|
|
17
|
+
return ['/mcp-runtime.json', '/pdf-runtime.json', '/__shoalrun/mcp-data', '/__shoalrun/pdf-data'].some(privatePath => internal === privatePath || internal.startsWith(privatePath + '/'));
|
|
18
|
+
}
|
|
19
|
+
const types = { '.pdf': 'application/pdf', '.html': 'text/html; charset=utf-8', '.md': 'text/markdown; charset=utf-8', '.xml': 'application/xml; charset=utf-8', '.json': 'application/json', '.yaml': 'application/yaml', '.yml': 'application/yaml', '.css': 'text/css; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.txt': 'text/plain; charset=utf-8', '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.svg': 'image/svg+xml', '.woff2': 'font/woff2', '.woff': 'font/woff', '.ttf': 'font/ttf', '.otf': 'font/otf' };
|
|
9
20
|
const escapeHtml = (value) => value.replace(/[&<>"']/g, character => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[character]));
|
|
10
21
|
const scriptJson = (value) => JSON.stringify(value).replace(/</g, '\\u003c');
|
|
11
22
|
export function previewMarkup(basePath, preview) {
|
|
@@ -58,6 +69,9 @@ export async function createSiteServer(directory, liveClients, extras = {}) {
|
|
|
58
69
|
let mcp = await loadMcpRuntime(root);
|
|
59
70
|
let mcpHandler = mcp ? createMcpHttpHandler(mcp) : undefined;
|
|
60
71
|
let mcpBuild = mcp?.runtime.buildId;
|
|
72
|
+
let pdf = await loadPdfRuntime(root);
|
|
73
|
+
let pdfHandler = pdf ? createPdfHttpHandler(pdf) : undefined;
|
|
74
|
+
let pdfBuild = initialState.manifest.buildId;
|
|
61
75
|
async function siteFile(route) {
|
|
62
76
|
const file = path.resolve(root, `.${route}`);
|
|
63
77
|
if (file !== root && !file.startsWith(`${root}${path.sep}`))
|
|
@@ -73,9 +87,7 @@ export async function createSiteServer(directory, liveClients, extras = {}) {
|
|
|
73
87
|
let pathname = '';
|
|
74
88
|
let recoveryState = initialState;
|
|
75
89
|
try {
|
|
76
|
-
pathname =
|
|
77
|
-
if (pathname.includes('\0') || pathname.split('/').includes('..'))
|
|
78
|
-
throw new Error('Invalid path');
|
|
90
|
+
pathname = canonicalSitePath(request.url ?? '/');
|
|
79
91
|
const { headers, manifest, redirects, search, errorHtml, home, routes } = liveClients ? await loadState() : initialState;
|
|
80
92
|
recoveryState = { headers, manifest, redirects, search, errorHtml, home, routes };
|
|
81
93
|
const basePath = manifest.basePath ?? '';
|
|
@@ -85,12 +97,28 @@ export async function createSiteServer(directory, liveClients, extras = {}) {
|
|
|
85
97
|
mcpHandler = next ? createMcpHttpHandler(next) : undefined;
|
|
86
98
|
mcpBuild = manifest.buildId;
|
|
87
99
|
}
|
|
88
|
-
|
|
89
|
-
if (internalPath === '/mcp-runtime.json' || internalPath === '/__shoalrun/mcp-data' || internalPath.startsWith('/__shoalrun/mcp-data/')) {
|
|
100
|
+
if (privateSitePath(pathname)) {
|
|
90
101
|
response.writeHead(404);
|
|
91
102
|
response.end();
|
|
92
103
|
return;
|
|
93
104
|
}
|
|
105
|
+
if (liveClients && manifest.buildId !== pdfBuild) {
|
|
106
|
+
pdf = await loadPdfRuntime(root);
|
|
107
|
+
pdfHandler = pdf ? createPdfHttpHandler(pdf) : undefined;
|
|
108
|
+
pdfBuild = manifest.buildId;
|
|
109
|
+
}
|
|
110
|
+
if (pdf && pdfHandler && pathname === pdf.runtime.endpoint) {
|
|
111
|
+
try {
|
|
112
|
+
await bridge(request, response, pdfHandler);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
if (!response.headersSent) {
|
|
116
|
+
response.writeHead(503, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
|
|
117
|
+
response.end('{"error":"PDF generation is unavailable."}');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
94
122
|
if (mcp && mcpHandler && pathname === mcp.runtime.path) {
|
|
95
123
|
await bridgeMcp(request, response, mcpHandler);
|
|
96
124
|
return;
|
|
@@ -201,8 +229,7 @@ export async function createSiteServer(directory, liveClients, extras = {}) {
|
|
|
201
229
|
mcpHandler = next ? createMcpHttpHandler(next) : undefined;
|
|
202
230
|
mcpBuild = manifest.buildId;
|
|
203
231
|
}
|
|
204
|
-
|
|
205
|
-
if (internalPath === '/mcp-runtime.json' || internalPath === '/__shoalrun/mcp-data' || internalPath.startsWith('/__shoalrun/mcp-data/')) {
|
|
232
|
+
if (privateSitePath(pathname)) {
|
|
206
233
|
response.writeHead(404);
|
|
207
234
|
response.end();
|
|
208
235
|
return;
|
package/dist/vercel.js
CHANGED
|
@@ -5,6 +5,9 @@ import path from 'node:path';
|
|
|
5
5
|
import { compile } from './compiler.js';
|
|
6
6
|
import { homeUrl } from './negotiation.js';
|
|
7
7
|
import { addAskFunction } from './vercel-function.js';
|
|
8
|
+
import { loadConfig } from './config.js';
|
|
9
|
+
import { resolvedCompilerConfig } from './compiler-config.js';
|
|
10
|
+
import { resolvePdfButton } from './pdf-button.js';
|
|
8
11
|
function exact(route) {
|
|
9
12
|
return route.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
10
13
|
}
|
|
@@ -28,6 +31,9 @@ async function removeStaleFunctions(directory, keep = new Set()) {
|
|
|
28
31
|
await visit(directory);
|
|
29
32
|
}
|
|
30
33
|
export async function buildVercel(configFile, outputDirectory, provenance = {}, options = {}) {
|
|
34
|
+
const settings = resolvedCompilerConfig((await loadConfig(configFile, { profile: options.profile })).value);
|
|
35
|
+
if (resolvePdfButton(settings.outputs)?.mode === 'endpoint')
|
|
36
|
+
throw new Error('On-demand PDF generation requires a Node server with an installed Chromium browser. Use outputs.html.pdf.mode: print for Vercel builds.');
|
|
31
37
|
const output = path.resolve(outputDirectory);
|
|
32
38
|
const staticDirectory = path.join(output, 'static');
|
|
33
39
|
if (options.profile && options.chat)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: guide.start
|
|
3
|
+
title: Python SDK
|
|
4
|
+
summary: Explore a typed SDK with synchronous and async clients, models, pagination, and exceptions.
|
|
5
|
+
type: guide
|
|
6
|
+
slug: /
|
|
7
|
+
channel: production
|
|
8
|
+
version: current
|
|
9
|
+
language: en
|
|
10
|
+
access: { policy: public }
|
|
11
|
+
---
|
|
12
|
+
This example SDK manages records. Its reference pages are generated from Python source and docstrings, then rendered with Shoalrun's normal theme, navigation, search, and Markdown output.
|
|
13
|
+
|
|
14
|
+
The sample client stores records in memory. It doesn't connect to a live service.
|
|
15
|
+
|
|
16
|
+
## Fetch a typed record
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from orchard import Client
|
|
20
|
+
|
|
21
|
+
client = Client("demo-key")
|
|
22
|
+
record = client.fetch("rec_42")
|
|
23
|
+
print(record.title)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Read [Client](doc:reference.client) for configuration and [fetch](doc:reference.fetch) for its typed and raw-response overloads.
|
|
27
|
+
|
|
28
|
+
## Work with more than one page
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from orchard import RecordStatus
|
|
32
|
+
|
|
33
|
+
for record in client.iter_records(page_size=50, status=RecordStatus.READY):
|
|
34
|
+
print(record.id, record.title)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Choose [list_records](doc:reference.Client.list_records) when your application needs explicit cursor control, or [Page.map](doc:reference.pagination.Page.map) to transform a response without losing its pagination metadata.
|
|
38
|
+
|
|
39
|
+
## Use an async client
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from orchard import AsyncClient
|
|
43
|
+
|
|
44
|
+
client = AsyncClient("demo-key")
|
|
45
|
+
async for record in client.iter_records(page_size=50):
|
|
46
|
+
print(record.title)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Browse [AsyncClient](doc:reference.AsyncClient), [Record](doc:reference.models.Record), and the [typed exceptions](doc:reference.errors) to see how the generated reference fits together.
|
|
50
|
+
|
|
51
|
+
## Choose how to browse
|
|
52
|
+
|
|
53
|
+
Read the [Client class with member details inline](doc:reference.client), or open the [complete Python SDK reference](doc:reference.complete) to browse everything on one page. The example uses `layout: classes` and enables `singlePage` in its catalog configuration. Individual symbol links remain available.
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
schemaVersion: 1
|
|
2
|
+
site:
|
|
3
|
+
title: Python SDK documentation
|
|
4
|
+
publications:
|
|
5
|
+
channels:
|
|
6
|
+
production: {}
|
|
7
|
+
versions:
|
|
8
|
+
current: {}
|
|
9
|
+
defaults:
|
|
10
|
+
channel: production
|
|
11
|
+
version: current
|
|
12
|
+
language: en
|
|
13
|
+
enabled:
|
|
14
|
+
- channel: production
|
|
15
|
+
version: current
|
|
16
|
+
language: en
|
|
17
|
+
codeReferences:
|
|
18
|
+
sdk:
|
|
19
|
+
source:
|
|
20
|
+
kind: file
|
|
21
|
+
path: ./reference.json
|
|
22
|
+
symbols:
|
|
23
|
+
orchard:
|
|
24
|
+
documentId: reference.orchard
|
|
25
|
+
slug: /reference/orchard
|
|
26
|
+
orchard.client:
|
|
27
|
+
documentId: reference.clients
|
|
28
|
+
slug: /reference/clients
|
|
29
|
+
orchard.client.AsyncClient:
|
|
30
|
+
documentId: reference.AsyncClient
|
|
31
|
+
slug: /reference/async-client
|
|
32
|
+
orchard.client.AsyncClient.__init__:
|
|
33
|
+
documentId: reference.AsyncClient.__init__
|
|
34
|
+
slug: /reference/async-client/constructor
|
|
35
|
+
orchard.client.AsyncClient.fetch:
|
|
36
|
+
documentId: reference.AsyncClient.fetch
|
|
37
|
+
slug: /reference/async-client/fetch
|
|
38
|
+
orchard.client.AsyncClient.iter_records:
|
|
39
|
+
documentId: reference.AsyncClient.iter_records
|
|
40
|
+
slug: /reference/async-client/iter-records
|
|
41
|
+
orchard.client.Client:
|
|
42
|
+
documentId: reference.client
|
|
43
|
+
slug: /reference/client
|
|
44
|
+
orchard.client.Client.__init__:
|
|
45
|
+
documentId: reference.Client.__init__
|
|
46
|
+
slug: /reference/client/constructor
|
|
47
|
+
orchard.client.Client.base_url:
|
|
48
|
+
documentId: reference.Client.base_url
|
|
49
|
+
slug: /reference/client/base-url
|
|
50
|
+
orchard.client.Client.bulk_create:
|
|
51
|
+
documentId: reference.Client.bulk_create
|
|
52
|
+
slug: /reference/client/bulk-create
|
|
53
|
+
orchard.client.Client.create_record:
|
|
54
|
+
documentId: reference.Client.create_record
|
|
55
|
+
slug: /reference/client/create-record
|
|
56
|
+
orchard.client.Client.fetch:
|
|
57
|
+
documentId: reference.fetch
|
|
58
|
+
slug: /reference/client/fetch
|
|
59
|
+
orchard.client.Client.iter_records:
|
|
60
|
+
documentId: reference.Client.iter_records
|
|
61
|
+
slug: /reference/client/iter-records
|
|
62
|
+
orchard.client.Client.list_records:
|
|
63
|
+
documentId: reference.Client.list_records
|
|
64
|
+
slug: /reference/client/list-records
|
|
65
|
+
orchard.client.Client.max_retries:
|
|
66
|
+
documentId: reference.Client.max_retries
|
|
67
|
+
slug: /reference/client/max-retries
|
|
68
|
+
orchard.client.Client.timeout:
|
|
69
|
+
documentId: reference.Client.timeout
|
|
70
|
+
slug: /reference/client/timeout
|
|
71
|
+
orchard.errors:
|
|
72
|
+
documentId: reference.errors
|
|
73
|
+
slug: /reference/errors
|
|
74
|
+
orchard.errors.APIError:
|
|
75
|
+
documentId: reference.errors.APIError
|
|
76
|
+
slug: /reference/errors/apierror
|
|
77
|
+
orchard.errors.APIError.__init__:
|
|
78
|
+
documentId: reference.errors.APIError.__init__
|
|
79
|
+
slug: /reference/errors/apierror/constructor
|
|
80
|
+
orchard.errors.APIError.request_id:
|
|
81
|
+
documentId: reference.errors.APIError.request_id
|
|
82
|
+
slug: /reference/errors/apierror/request-id
|
|
83
|
+
orchard.errors.AuthenticationError:
|
|
84
|
+
documentId: reference.errors.AuthenticationError
|
|
85
|
+
slug: /reference/errors/authenticationerror
|
|
86
|
+
orchard.errors.NotFoundError:
|
|
87
|
+
documentId: reference.errors.NotFoundError
|
|
88
|
+
slug: /reference/errors/notfounderror
|
|
89
|
+
orchard.errors.RateLimitError:
|
|
90
|
+
documentId: reference.errors.RateLimitError
|
|
91
|
+
slug: /reference/errors/ratelimiterror
|
|
92
|
+
orchard.errors.RateLimitError.__init__:
|
|
93
|
+
documentId: reference.errors.RateLimitError.__init__
|
|
94
|
+
slug: /reference/errors/ratelimiterror/constructor
|
|
95
|
+
orchard.errors.RateLimitError.retry_after:
|
|
96
|
+
documentId: reference.errors.RateLimitError.retry_after
|
|
97
|
+
slug: /reference/errors/ratelimiterror/retry-after
|
|
98
|
+
orchard.models:
|
|
99
|
+
documentId: reference.models
|
|
100
|
+
slug: /reference/models
|
|
101
|
+
orchard.models.Record:
|
|
102
|
+
documentId: reference.models.Record
|
|
103
|
+
slug: /reference/models/record
|
|
104
|
+
orchard.models.Record.created_at:
|
|
105
|
+
documentId: reference.models.Record.created_at
|
|
106
|
+
slug: /reference/models/record/created-at
|
|
107
|
+
orchard.models.Record.id:
|
|
108
|
+
documentId: reference.models.Record.id
|
|
109
|
+
slug: /reference/models/record/id
|
|
110
|
+
orchard.models.Record.labels:
|
|
111
|
+
documentId: reference.models.Record.labels
|
|
112
|
+
slug: /reference/models/record/labels
|
|
113
|
+
orchard.models.Record.status:
|
|
114
|
+
documentId: reference.models.Record.status
|
|
115
|
+
slug: /reference/models/record/status
|
|
116
|
+
orchard.models.Record.title:
|
|
117
|
+
documentId: reference.models.Record.title
|
|
118
|
+
slug: /reference/models/record/title
|
|
119
|
+
orchard.models.Record.to_dict:
|
|
120
|
+
documentId: reference.models.Record.to_dict
|
|
121
|
+
slug: /reference/models/record/to-dict
|
|
122
|
+
orchard.models.RecordDict:
|
|
123
|
+
documentId: reference.models.RecordDict
|
|
124
|
+
slug: /reference/models/recorddict
|
|
125
|
+
orchard.models.RecordDict.id:
|
|
126
|
+
documentId: reference.models.RecordDict.id
|
|
127
|
+
slug: /reference/models/recorddict/id
|
|
128
|
+
orchard.models.RecordDict.status:
|
|
129
|
+
documentId: reference.models.RecordDict.status
|
|
130
|
+
slug: /reference/models/recorddict/status
|
|
131
|
+
orchard.models.RecordDict.title:
|
|
132
|
+
documentId: reference.models.RecordDict.title
|
|
133
|
+
slug: /reference/models/recorddict/title
|
|
134
|
+
orchard.models.RecordInput:
|
|
135
|
+
documentId: reference.models.RecordInput
|
|
136
|
+
slug: /reference/models/recordinput
|
|
137
|
+
orchard.models.RecordInput.labels:
|
|
138
|
+
documentId: reference.models.RecordInput.labels
|
|
139
|
+
slug: /reference/models/recordinput/labels
|
|
140
|
+
orchard.models.RecordInput.title:
|
|
141
|
+
documentId: reference.models.RecordInput.title
|
|
142
|
+
slug: /reference/models/recordinput/title
|
|
143
|
+
orchard.models.RecordStatus:
|
|
144
|
+
documentId: reference.models.RecordStatus
|
|
145
|
+
slug: /reference/models/recordstatus
|
|
146
|
+
orchard.models.RecordStatus.FAILED:
|
|
147
|
+
documentId: reference.models.RecordStatus.FAILED
|
|
148
|
+
slug: /reference/models/recordstatus/failed
|
|
149
|
+
orchard.models.RecordStatus.PENDING:
|
|
150
|
+
documentId: reference.models.RecordStatus.PENDING
|
|
151
|
+
slug: /reference/models/recordstatus/pending
|
|
152
|
+
orchard.models.RecordStatus.READY:
|
|
153
|
+
documentId: reference.models.RecordStatus.READY
|
|
154
|
+
slug: /reference/models/recordstatus/ready
|
|
155
|
+
orchard.pagination:
|
|
156
|
+
documentId: reference.pagination
|
|
157
|
+
slug: /reference/pagination
|
|
158
|
+
orchard.pagination.Page:
|
|
159
|
+
documentId: reference.pagination.Page
|
|
160
|
+
slug: /reference/pagination/page
|
|
161
|
+
orchard.pagination.Page.has_more:
|
|
162
|
+
documentId: reference.pagination.Page.has_more
|
|
163
|
+
slug: /reference/pagination/page/has-more
|
|
164
|
+
orchard.pagination.Page.items:
|
|
165
|
+
documentId: reference.pagination.Page.items
|
|
166
|
+
slug: /reference/pagination/page/items
|
|
167
|
+
orchard.pagination.Page.map:
|
|
168
|
+
documentId: reference.pagination.Page.map
|
|
169
|
+
slug: /reference/pagination/page/map
|
|
170
|
+
orchard.pagination.Page.next_cursor:
|
|
171
|
+
documentId: reference.pagination.Page.next_cursor
|
|
172
|
+
slug: /reference/pagination/page/next-cursor
|
|
173
|
+
orchard.pagination.Page.total:
|
|
174
|
+
documentId: reference.pagination.Page.total
|
|
175
|
+
slug: /reference/pagination/page/total
|
|
176
|
+
orchard.pagination.T:
|
|
177
|
+
documentId: reference.pagination.T
|
|
178
|
+
slug: /reference/pagination/t
|
|
179
|
+
orchard.pagination.U:
|
|
180
|
+
documentId: reference.pagination.U
|
|
181
|
+
slug: /reference/pagination/u
|
|
182
|
+
layout: classes
|
|
183
|
+
singlePage:
|
|
184
|
+
documentId: reference.complete
|
|
185
|
+
slug: /reference/all
|
|
186
|
+
title: Complete Python SDK reference
|
|
187
|
+
summary: Browse every public module, class, method, and field on one page.
|
|
188
|
+
navigation:
|
|
189
|
+
- id: start
|
|
190
|
+
doc: guide.start
|
|
191
|
+
- id: complete
|
|
192
|
+
doc: reference.complete
|
|
193
|
+
- id: overview
|
|
194
|
+
label: Package
|
|
195
|
+
items:
|
|
196
|
+
- id: orchard
|
|
197
|
+
doc: reference.orchard
|
|
198
|
+
- id: orchard.client
|
|
199
|
+
doc: reference.clients
|
|
200
|
+
- id: client
|
|
201
|
+
label: Synchronous client
|
|
202
|
+
items:
|
|
203
|
+
- id: orchard.client.Client
|
|
204
|
+
doc: reference.client
|
|
205
|
+
- id: orchard.client.Client.__init__
|
|
206
|
+
doc: reference.Client.__init__
|
|
207
|
+
- id: orchard.client.Client.fetch
|
|
208
|
+
doc: reference.fetch
|
|
209
|
+
- id: orchard.client.Client.list_records
|
|
210
|
+
doc: reference.Client.list_records
|
|
211
|
+
- id: orchard.client.Client.iter_records
|
|
212
|
+
doc: reference.Client.iter_records
|
|
213
|
+
- id: orchard.client.Client.create_record
|
|
214
|
+
doc: reference.Client.create_record
|
|
215
|
+
- id: orchard.client.Client.bulk_create
|
|
216
|
+
doc: reference.Client.bulk_create
|
|
217
|
+
- id: async
|
|
218
|
+
label: Asynchronous client
|
|
219
|
+
items:
|
|
220
|
+
- id: orchard.client.AsyncClient
|
|
221
|
+
doc: reference.AsyncClient
|
|
222
|
+
- id: orchard.client.AsyncClient.fetch
|
|
223
|
+
doc: reference.AsyncClient.fetch
|
|
224
|
+
- id: orchard.client.AsyncClient.iter_records
|
|
225
|
+
doc: reference.AsyncClient.iter_records
|
|
226
|
+
- id: models
|
|
227
|
+
label: Models
|
|
228
|
+
items:
|
|
229
|
+
- id: orchard.models
|
|
230
|
+
doc: reference.models
|
|
231
|
+
- id: orchard.models.Record
|
|
232
|
+
doc: reference.models.Record
|
|
233
|
+
- id: orchard.models.RecordInput
|
|
234
|
+
doc: reference.models.RecordInput
|
|
235
|
+
- id: orchard.models.RecordDict
|
|
236
|
+
doc: reference.models.RecordDict
|
|
237
|
+
- id: orchard.models.RecordStatus
|
|
238
|
+
doc: reference.models.RecordStatus
|
|
239
|
+
- id: orchard.models.Record.to_dict
|
|
240
|
+
doc: reference.models.Record.to_dict
|
|
241
|
+
- id: pagination
|
|
242
|
+
label: Pagination
|
|
243
|
+
items:
|
|
244
|
+
- id: orchard.pagination.Page
|
|
245
|
+
doc: reference.pagination.Page
|
|
246
|
+
- id: orchard.pagination.Page.map
|
|
247
|
+
doc: reference.pagination.Page.map
|
|
248
|
+
- id: orchard.pagination.Page.has_more
|
|
249
|
+
doc: reference.pagination.Page.has_more
|
|
250
|
+
- id: errors
|
|
251
|
+
label: Exceptions
|
|
252
|
+
items:
|
|
253
|
+
- id: orchard.errors
|
|
254
|
+
doc: reference.errors
|
|
255
|
+
- id: orchard.errors.APIError
|
|
256
|
+
doc: reference.errors.APIError
|
|
257
|
+
- id: orchard.errors.AuthenticationError
|
|
258
|
+
doc: reference.errors.AuthenticationError
|
|
259
|
+
- id: orchard.errors.NotFoundError
|
|
260
|
+
doc: reference.errors.NotFoundError
|
|
261
|
+
- id: orchard.errors.RateLimitError
|
|
262
|
+
doc: reference.errors.RateLimitError
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""A sample SDK for working with records, collections, and paginated results.
|
|
2
|
+
|
|
3
|
+
Use [Client](symbol:orchard.client.Client) in synchronous applications, or
|
|
4
|
+
[AsyncClient](symbol:orchard.client.AsyncClient) in an async service. Models,
|
|
5
|
+
pagination helpers, and typed exceptions have their own reference pages.
|
|
6
|
+
|
|
7
|
+
This package is documentation example code. It doesn't contact a live service.
|
|
8
|
+
"""
|
|
9
|
+
from .client import AsyncClient, Client
|
|
10
|
+
from .models import Record, RecordInput, RecordStatus
|
|
11
|
+
from .pagination import Page
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Synchronous and asynchronous clients for the sample records SDK."""
|
|
2
|
+
from collections.abc import AsyncIterator, Iterator, Sequence
|
|
3
|
+
from typing import Literal, overload
|
|
4
|
+
from .errors import AuthenticationError, NotFoundError
|
|
5
|
+
from .models import Record, RecordDict, RecordInput, RecordStatus
|
|
6
|
+
from .pagination import Page
|
|
7
|
+
|
|
8
|
+
class Client:
|
|
9
|
+
"""Manage records from a synchronous Python application.
|
|
10
|
+
|
|
11
|
+
Create one client per API credential and reuse it across requests. Use
|
|
12
|
+
[AsyncClient](symbol:orchard.client.AsyncClient) in an async application.
|
|
13
|
+
|
|
14
|
+
The sample client keeps records in memory; it doesn't make network calls.
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, api_key: str, *, base_url: str = "https://api.example.com/v1", timeout: float = 10.0, max_retries: int = 2):
|
|
17
|
+
"""Configure a reusable client.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
api_key: Credential used to identify the application.
|
|
21
|
+
base_url: Root URL of the API deployment.
|
|
22
|
+
timeout: Default request timeout, in seconds.
|
|
23
|
+
max_retries: Number of retries for transient failures.
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
AuthenticationError: If the API key is empty.
|
|
27
|
+
"""
|
|
28
|
+
if not api_key:
|
|
29
|
+
raise AuthenticationError("API key must not be empty")
|
|
30
|
+
self.base_url = base_url
|
|
31
|
+
self.timeout = timeout
|
|
32
|
+
self.max_retries = max_retries
|
|
33
|
+
self._records: dict[str, Record] = {"rec_42": Record("rec_42", "Getting started")}
|
|
34
|
+
|
|
35
|
+
@overload
|
|
36
|
+
def fetch(self, record_id: str, *, raw: Literal[False] = False, timeout: float | None = None) -> Record: ...
|
|
37
|
+
@overload
|
|
38
|
+
def fetch(self, record_id: str, *, raw: Literal[True], timeout: float | None = None) -> RecordDict: ...
|
|
39
|
+
def fetch(self, record_id: str, *, raw: bool = False, timeout: float | None = None) -> Record | RecordDict:
|
|
40
|
+
"""Retrieve a record by its stable identifier.
|
|
41
|
+
|
|
42
|
+
The default response is a typed [Record](symbol:orchard.models.Record).
|
|
43
|
+
Set `raw=True` to receive a dictionary for serialization or a legacy
|
|
44
|
+
integration. An explicit timeout overrides the client's default.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
record_id: Stable identifier of the record to retrieve.
|
|
48
|
+
raw: Return a wire-format dictionary instead of a model.
|
|
49
|
+
timeout: Request timeout override, in seconds.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
The record model, or a dictionary when `raw=True`.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If the record identifier is empty.
|
|
56
|
+
NotFoundError: If no record matches the identifier.
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
>>> client = Client("demo-key")
|
|
60
|
+
>>> record = client.fetch("rec_42")
|
|
61
|
+
>>> record.title
|
|
62
|
+
'Getting started'
|
|
63
|
+
>>> payload = client.fetch("rec_42", raw=True)
|
|
64
|
+
>>> payload["status"]
|
|
65
|
+
'ready'
|
|
66
|
+
"""
|
|
67
|
+
if not record_id:
|
|
68
|
+
raise ValueError("record_id must not be empty")
|
|
69
|
+
if record_id not in self._records:
|
|
70
|
+
raise NotFoundError(f"Record {record_id} was not found")
|
|
71
|
+
record = self._records[record_id]
|
|
72
|
+
return record.to_dict() if raw else record
|
|
73
|
+
|
|
74
|
+
def list_records(self, *, limit: int = 20, cursor: str | None = None, status: RecordStatus | None = None) -> Page[Record]:
|
|
75
|
+
"""List a single page of records with optional status filtering.
|
|
76
|
+
|
|
77
|
+
Use [iter_records](symbol:orchard.client.Client.iter_records) when you
|
|
78
|
+
want to read every page without managing continuation cursors.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
limit: Maximum number of records in a page, from 1 to 100.
|
|
82
|
+
cursor: Opaque continuation token from an earlier response.
|
|
83
|
+
status: Include only records with this processing status.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
A page of matching records with an optional continuation cursor.
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
ValueError: If the page size is outside the supported range.
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
>>> page = client.list_records(limit=10, status=RecordStatus.READY)
|
|
93
|
+
>>> titles = page.map(lambda record: record.title)
|
|
94
|
+
"""
|
|
95
|
+
if not 1 <= limit <= 100:
|
|
96
|
+
raise ValueError("limit must be between 1 and 100")
|
|
97
|
+
records = [r for r in self._records.values() if status is None or r.status == status]
|
|
98
|
+
start = int(cursor or "0")
|
|
99
|
+
end = start + limit
|
|
100
|
+
return Page(records[start:end], str(end) if end < len(records) else None, len(records))
|
|
101
|
+
|
|
102
|
+
def iter_records(self, *, page_size: int = 20, status: RecordStatus | None = None) -> Iterator[Record]:
|
|
103
|
+
"""Iterate through records across every page.
|
|
104
|
+
|
|
105
|
+
Pagination is lazy: another page is read only when the iterator needs it.
|
|
106
|
+
Stop iteration early to avoid fetching pages your application won't use.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
page_size: Number of records requested per page, from 1 to 100.
|
|
110
|
+
status: Optional processing status filter.
|
|
111
|
+
|
|
112
|
+
Yields:
|
|
113
|
+
Records in the service's response order.
|
|
114
|
+
|
|
115
|
+
Examples:
|
|
116
|
+
>>> for record in client.iter_records(page_size=50):
|
|
117
|
+
... print(record.id, record.title)
|
|
118
|
+
"""
|
|
119
|
+
cursor = None
|
|
120
|
+
while True:
|
|
121
|
+
page = self.list_records(limit=page_size, cursor=cursor, status=status)
|
|
122
|
+
yield from page.items
|
|
123
|
+
if not page.has_more:
|
|
124
|
+
return
|
|
125
|
+
cursor = page.next_cursor
|
|
126
|
+
|
|
127
|
+
def create_record(self, data: RecordInput, *, idempotency_key: str | None = None) -> Record:
|
|
128
|
+
"""Create a record from a typed input model.
|
|
129
|
+
|
|
130
|
+
Use an idempotency key when retrying a request after a timeout. Reuse the
|
|
131
|
+
same key only for retries of the same logical operation.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
data: Title and labels for the new record.
|
|
135
|
+
idempotency_key: Application-generated retry token.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
An immutable snapshot of the created record.
|
|
139
|
+
|
|
140
|
+
Examples:
|
|
141
|
+
>>> data = RecordInput(title="Deployment notes", labels={"team": "platform"})
|
|
142
|
+
>>> record = client.create_record(data, idempotency_key="deploy-42")
|
|
143
|
+
"""
|
|
144
|
+
record = Record(f"rec_{len(self._records) + 1}", data.title, labels=data.labels)
|
|
145
|
+
self._records[record.id] = record
|
|
146
|
+
return record
|
|
147
|
+
|
|
148
|
+
def bulk_create(self, records: Sequence[RecordInput], *, batch_size: int = 25) -> list[Record]:
|
|
149
|
+
"""Create multiple records in bounded batches.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
records: Input models to create, in submission order.
|
|
153
|
+
batch_size: Maximum number of records per batch, from 1 to 100.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Created records in the same order as the submitted inputs.
|
|
157
|
+
|
|
158
|
+
Raises:
|
|
159
|
+
ValueError: If the batch size is outside the supported range.
|
|
160
|
+
"""
|
|
161
|
+
if not 1 <= batch_size <= 100:
|
|
162
|
+
raise ValueError("batch_size must be between 1 and 100")
|
|
163
|
+
return [self.create_record(item) for item in records]
|
|
164
|
+
|
|
165
|
+
class AsyncClient:
|
|
166
|
+
"""Use the records SDK from an async Python application.
|
|
167
|
+
|
|
168
|
+
Await individual operations, or use `async for` to consume a record iterator.
|
|
169
|
+
This example delegates to an in-memory client; no network calls are made.
|
|
170
|
+
"""
|
|
171
|
+
def __init__(self, api_key: str, *, timeout: float = 10.0):
|
|
172
|
+
"""Configure an async client.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
api_key: Application credential.
|
|
176
|
+
timeout: Default request timeout, in seconds.
|
|
177
|
+
"""
|
|
178
|
+
self._client = Client(api_key, timeout=timeout)
|
|
179
|
+
|
|
180
|
+
async def fetch(self, record_id: str, *, timeout: float | None = None) -> Record:
|
|
181
|
+
"""Await a typed record response.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
record_id: Stable record identifier.
|
|
185
|
+
timeout: Optional request timeout override, in seconds.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
The matching record model.
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
NotFoundError: If the record doesn't exist.
|
|
192
|
+
|
|
193
|
+
Examples:
|
|
194
|
+
>>> record = await client.fetch("rec_42")
|
|
195
|
+
"""
|
|
196
|
+
return self._client.fetch(record_id, timeout=timeout)
|
|
197
|
+
|
|
198
|
+
async def iter_records(self, *, page_size: int = 20) -> AsyncIterator[Record]:
|
|
199
|
+
"""Consume paginated records using asynchronous iteration.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
page_size: Maximum number of records read in one page.
|
|
203
|
+
|
|
204
|
+
Yields:
|
|
205
|
+
Typed records from successive pages.
|
|
206
|
+
|
|
207
|
+
Examples:
|
|
208
|
+
>>> async for record in client.iter_records(page_size=50):
|
|
209
|
+
... print(record.title)
|
|
210
|
+
"""
|
|
211
|
+
for record in self._client.iter_records(page_size=page_size):
|
|
212
|
+
yield record
|