@stainless-api/docs 0.1.0-beta.52 → 0.1.0-beta.55

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.
@@ -11,12 +11,12 @@ config();
11
11
 
12
12
  const envSchema = z.object({
13
13
  // absolute path to the Stainless monorepo root
14
- STAINLESS_MONOREPO_PATH: z.string(),
14
+ STAINLESS_ROOT: z.string(),
15
15
  });
16
16
 
17
17
  const env = envSchema.parse(process.env);
18
18
 
19
- console.log(`Using Stainless monorepo at ${env.STAINLESS_MONOREPO_PATH}`);
19
+ console.log(`Using Stainless monorepo at ${env.STAINLESS_ROOT}`);
20
20
 
21
21
  if (fs.existsSync(DEPS_DIR)) {
22
22
  fs.rmSync(DEPS_DIR, { recursive: true });
@@ -25,11 +25,11 @@ if (fs.existsSync(DEPS_DIR)) {
25
25
  fs.mkdirSync(DEPS_DIR, { recursive: true });
26
26
 
27
27
  const previewWorkerPath = path.join(
28
- env.STAINLESS_MONOREPO_PATH,
28
+ env.STAINLESS_ROOT,
29
29
  '/packages/preview-worker/dist/stainless/preview.worker.docs.js',
30
30
  );
31
31
 
32
- const readmeTemplatePath = path.join(env.STAINLESS_MONOREPO_PATH, '/legacy-dir-root/templates');
32
+ const readmeTemplatePath = path.join(env.STAINLESS_ROOT, '/legacy-dir-root/templates');
33
33
 
34
34
  fs.copyFileSync(previewWorkerPath, path.join(DEPS_DIR, 'preview.worker.docs.js'));
35
35
 
package/stl-docs/index.ts CHANGED
@@ -22,6 +22,7 @@ import type * as StlDocsVirtualModule from 'virtual:stl-docs-virtual-module';
22
22
  import { resolveSrcFile } from '../resolveSrcFile';
23
23
  import { stainlessDocsMarkdownRenderer } from './proseMarkdown/proseMarkdownIntegration';
24
24
  import { setSharedLogger } from '../shared/getSharedLogger';
25
+ import { stainlessDocsProseIndexing } from './proseSearchIndexing';
25
26
 
26
27
  export * from '../plugin';
27
28
 
@@ -196,7 +197,7 @@ function stainlessDocsIntegration(
196
197
  'astro:build:done': ({ dir }) => {
197
198
  if (redirects !== null) {
198
199
  const stainlessDir = join(dir.pathname, '_stainless');
199
- mkdirSync(stainlessDir);
200
+ mkdirSync(stainlessDir, { recursive: true });
200
201
  const outputPath = join(stainlessDir, 'redirects.json');
201
202
  writeFileSync(outputPath, JSON.stringify(redirects, null, 2), {
202
203
  encoding: 'utf-8',
@@ -242,5 +243,6 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
242
243
  stainlessDocsStarlightIntegration(normalizedConfig),
243
244
  stainlessDocsIntegration(normalizedConfig, apiReferenceBasePath),
244
245
  stainlessDocsMarkdownRenderer({ enabled: normalizedConfig.enableProseMarkdownRendering }),
246
+ stainlessDocsProseIndexing(),
245
247
  ];
246
248
  }
@@ -0,0 +1,113 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ import { readFile } from 'fs/promises';
3
+ import { getSharedLogger } from '../shared/getSharedLogger';
4
+ import { bold } from '../shared/terminalUtils';
5
+ import { buildProseIndex } from '@stainless-api/docs-ui/search/providers/algolia';
6
+ import * as cheerio from 'cheerio';
7
+
8
+ function chunkByWords(content: string, chunkSize: number = 30000, chunkOverlap: number = 10) {
9
+ if (Buffer.byteLength(content) < chunkSize) return [content];
10
+
11
+ const words = content.split(/\s+/);
12
+ const chunks: string[] = [];
13
+
14
+ let currentChunk: string[] = [];
15
+ let currentSize = 0;
16
+
17
+ for (const word of words) {
18
+ const wordSize = Buffer.byteLength(word + ' ', 'utf-8');
19
+
20
+ if (currentSize + wordSize > chunkSize && currentChunk.length > 0) {
21
+ chunks.push(currentChunk.join(' '));
22
+
23
+ const overlapStart = Math.max(0, currentChunk.length - chunkOverlap);
24
+ currentChunk = currentChunk.slice(overlapStart);
25
+ currentSize = Buffer.byteLength(currentChunk.join(' '), 'utf-8');
26
+ }
27
+
28
+ currentChunk.push(word);
29
+ currentSize += wordSize;
30
+ }
31
+
32
+ if (currentChunk.length > 0) {
33
+ chunks.push(currentChunk.join(' '));
34
+ }
35
+
36
+ return chunks;
37
+ }
38
+
39
+ export function* indexHTML(content: string, root: string, pattern: string) {
40
+ const $ = cheerio.load(content);
41
+ const matches = $(root).find(pattern);
42
+
43
+ for (const match of matches) {
44
+ const rawText = $(match).text().trim();
45
+ const chunks = chunkByWords(rawText);
46
+ const chunkId = crypto.randomUUID();
47
+
48
+ for (const [chunkN, content] of chunks.entries()) {
49
+ yield {
50
+ id: $(match).attr('id'),
51
+ tag: match.tagName.toLowerCase(),
52
+ content,
53
+ chunk: {
54
+ id: chunkId,
55
+ index: chunkN,
56
+ total: chunks.length,
57
+ },
58
+ };
59
+ }
60
+ }
61
+ }
62
+
63
+ const root = 'main';
64
+ const pattern = 'h1, h2, h3, h4, h5, h6, p, li';
65
+
66
+ export function stainlessDocsProseIndexing(): AstroIntegration {
67
+ return {
68
+ name: 'stl-docs-prose-indexing',
69
+ hooks: {
70
+ 'astro:build:done': async ({ assets, logger: localLogger, dir }) => {
71
+ const logger = getSharedLogger({ fallback: localLogger });
72
+ const outputBasePath = dir.pathname;
73
+
74
+ const {
75
+ PUBLIC_ALGOLIA_APP_ID: appId,
76
+ PUBLIC_ALGOLIA_INDEX: indexName,
77
+ PRIVATE_ALGOLIA_WRITE_KEY: algoliaWriteKey,
78
+ } = process.env;
79
+
80
+ if (!appId || !indexName || !algoliaWriteKey) {
81
+ logger.info('Skipping algolia indexing due to missing environment variables');
82
+ return;
83
+ }
84
+
85
+ const starlightPagePatterns = ['/[...slug]'];
86
+ const pagesToRender = Array.from(assets.entries())
87
+ .filter(([k]) => starlightPagePatterns.includes(k))
88
+ .map(([, v]) => v)
89
+ .flat()
90
+ .map((v) => v.pathname);
91
+
92
+ logger.info(bold(`Indexing ${pagesToRender.length} prose pages for search`));
93
+
94
+ const objects = [];
95
+ for (const absHtmlPath of pagesToRender) {
96
+ const content = await readFile(absHtmlPath, 'utf-8');
97
+ const idx = indexHTML(content, root, pattern);
98
+ for (const entry of idx)
99
+ objects.push({
100
+ ...entry,
101
+ source: absHtmlPath.slice(outputBasePath.length),
102
+ });
103
+ }
104
+
105
+ try {
106
+ await buildProseIndex(appId, `${indexName}-prose`, algoliaWriteKey, objects);
107
+ } catch (err) {
108
+ logger.error(`Failed to index prose content: ${err}`);
109
+ }
110
+ },
111
+ },
112
+ };
113
+ }
@@ -1,3 +1,7 @@
1
+ declare module 'virtual:stl-playground/create' {
2
+ export const createPlayground: CreatePlayground;
3
+ }
4
+
1
5
  declare module 'virtual:stl-starlight-virtual-module' {
2
6
  import type { CreateShikiHighlighterOptions } from '@astrojs/markdown-remark';
3
7
  import type { PropertySettingsType } from '@stainless-api/docs-ui/contexts';
@@ -15,6 +19,7 @@ declare module 'virtual:stl-starlight-virtual-module' {
15
19
  export const CONTENT_PANEL_LAYOUT: 'double-pane' | 'single-pane';
16
20
  export const EXPERIMENTAL_COLLAPSIBLE_SNIPPETS: boolean | undefined;
17
21
  export const EXPERIMENTAL_COLLAPSIBLE_METHOD_DESCRIPTIONS: boolean | undefined;
22
+ export const EXPERIMENTAL_PLAYGROUNDS: boolean | undefined;
18
23
  export const PROPERTY_SETTINGS: PropertySettingsType;
19
24
  export const MIDDLEWARE: StlStarlightMiddleware;
20
25
  export const ENABLE_CONTEXT_MENU: boolean;