Skip to content

Commit 7bdbe79

Browse files
committed
feat(llms): implement LLM-friendly documentation formats
- Add root /llms.txt following llmstxt.org spec pointing to .section.md files - Convert Lambda@Edge markdown generator from ES6 to CommonJS for compatibility - Add Lambda test payloads and improved error handling to deployment docs - Fix format-selector rendering on landing pages - Fix format-selector dropdown overflow issue - Remove broken section-level llms.txt generation (1,114 files) - Add S3 bucket configuration via config.json for Lambda@Edge - Update .gitignore for Lambda deployment artifacts and TS build files Lambda@Edge now generates .md files on-demand with: - Evaluated Hugo shortcodes - Proper YAML frontmatter with product metadata - Clean markdown without UI elements - Section aggregation (parent + children in single file)
1 parent 6c11757 commit 7bdbe79

File tree

15 files changed

+393
-161
lines changed

15 files changed

+393
-161
lines changed

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tmp
3838

3939
# TypeScript build output
4040
**/dist/
41+
**/dist-lambda/
4142

4243
# User context files for AI assistant tools
4344
.context/*
@@ -49,3 +50,13 @@ tmp
4950
# Lambda deployment artifacts
5051
deploy/llm-markdown/lambda-edge/markdown-generator/*.zip
5152
deploy/llm-markdown/lambda-edge/markdown-generator/package-lock.json
53+
deploy/llm-markdown/lambda-edge/markdown-generator/.package-tmp/
54+
deploy/llm-markdown/lambda-edge/markdown-generator/yarn.lock
55+
deploy/llm-markdown/lambda-edge/markdown-generator/config.json
56+
57+
# JavaScript/TypeScript build artifacts
58+
*.tsbuildinfo
59+
*.d.ts
60+
*.d.ts.map
61+
*.js.map
62+
.eslintcache

assets/styles/layouts/_landing.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
display: flex;
33
flex-direction: row;
44
position: relative;
5-
overflow: hidden;
5+
overflow: visible; // Changed from hidden to allow format-selector dropdown
66
border-radius: $radius 0 0 $radius;
77
min-height: 700px;
88
@include gradient($landing-artwork-gradient);

config/_default/hugo.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ outputs:
6969
- HTML
7070
section:
7171
- HTML
72-
- llmstxt
72+
# llmstxt disabled for sections - using .md files via Lambda@Edge instead
7373
home:
7474
- HTML
75-
- llmstxt
75+
- llmstxt # Root /llms.txt for AI agent discovery
7676

7777
# Asset processing configuration for development
7878
build:

deploy/llm-markdown/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,90 @@ node cypress/support/run-e2e-specs.js \
5656
--spec "cypress/e2e/content/markdown-content-validation.cy.js"
5757
```
5858

59+
## Testing in AWS Console
60+
61+
You can test the Lambda function directly in the AWS Console using the Test feature:
62+
63+
### Single Page Request
64+
65+
```json
66+
{
67+
"Records": [
68+
{
69+
"cf": {
70+
"request": {
71+
"uri": "/influxdb3/core/get-started/index.md",
72+
"querystring": "",
73+
"headers": {
74+
"host": [
75+
{
76+
"key": "Host",
77+
"value": "docs.influxdata.com"
78+
}
79+
]
80+
}
81+
}
82+
}
83+
}
84+
]
85+
}
86+
```
87+
88+
### Section Aggregation Request
89+
90+
```json
91+
{
92+
"Records": [
93+
{
94+
"cf": {
95+
"request": {
96+
"uri": "/influxdb3/core/get-started/index.section.md",
97+
"querystring": "",
98+
"headers": {
99+
"host": [
100+
{
101+
"key": "Host",
102+
"value": "docs.influxdata.com"
103+
}
104+
]
105+
}
106+
}
107+
}
108+
}
109+
]
110+
}
111+
```
112+
113+
**Expected Response**: Lambda\@Edge origin-request handlers return a modified request object (not the final response). The function should return the request unchanged since it's handled by S3.
114+
115+
## Code Architecture
116+
117+
### CommonJS Module System
118+
119+
The Lambda function uses CommonJS (`require`/`module.exports`) instead of ES6 modules (`import`/`export`) because:
120+
121+
1. **Lambda\@Edge Compatibility**: Lambda\@Edge Node.js 18 runtime works best with CommonJS
122+
2. **No package.json type field**: The package.json must NOT include `"type": "module"`
123+
3. **Shared Library**: The markdown-converter library (`scripts/lib/markdown-converter.js`) has been converted to CommonJS for Lambda compatibility
124+
125+
### Key Files
126+
127+
- **`index.js`**: Lambda handler using CommonJS exports (`exports.handler`)
128+
- **`lib/s3-utils.js`**: S3 operations using CommonJS (`module.exports`)
129+
- **`scripts/lib/markdown-converter.js`**: Shared conversion library (CommonJS)
130+
- **`package.json`**: Dependencies WITHOUT `"type": "module"` field
131+
132+
### Testing Module Loading
133+
134+
To verify the Lambda function loads correctly:
135+
136+
```bash
137+
cd deploy/llm-markdown/lambda-edge/markdown-generator
138+
node -e "const h = require('./index.js'); console.log('Handler type:', typeof h.handler);"
139+
```
140+
141+
Expected output: `Handler type: function`
142+
59143
## Deployment
60144

61145
### Step 1: Install Lambda Dependencies

deploy/llm-markdown/lambda-edge/markdown-generator/deploy.sh

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,85 @@ echo ""
2121

2222
# Step 2: Package function
2323
echo "📦 Step 2: Packaging Lambda function..."
24-
rm -f function.zip
25-
zip -r function.zip index.js lib/ node_modules/ > /dev/null
24+
25+
# Create temporary directory structure for packaging
26+
rm -rf .package-tmp
27+
mkdir -p .package-tmp/scripts/lib
28+
mkdir -p .package-tmp/data
29+
mkdir -p .package-tmp/lib
30+
31+
# Copy Lambda function files
32+
cp index.js .package-tmp/
33+
cp -r lib/* .package-tmp/lib/
34+
cp -r node_modules .package-tmp/
35+
36+
# Copy shared markdown converter library
37+
cp ../../../../scripts/lib/markdown-converter.js .package-tmp/scripts/lib/
38+
39+
# Copy products.yml for product detection
40+
cp ../../../../data/products.yml .package-tmp/data/
41+
42+
# Generate config.json with S3 bucket name
43+
cat > .package-tmp/config.json <<EOF
44+
{
45+
"s3Bucket": "$S3_BUCKET"
46+
}
47+
EOF
48+
echo " Generated config.json with S3_BUCKET=$S3_BUCKET"
49+
50+
# Create ZIP from temp directory
51+
cd .package-tmp
52+
rm -f ../function.zip
53+
zip -r ../function.zip * > /dev/null
54+
cd ..
55+
56+
# Clean up temp directory
57+
rm -rf .package-tmp
58+
2659
PACKAGE_SIZE=$(du -h function.zip | cut -f1)
2760
echo "✅ Package created: function.zip ($PACKAGE_SIZE)"
2861
echo ""
2962

3063
# Step 3: Check if IAM role exists
3164
echo "🔐 Step 3: Checking IAM role..."
32-
if aws iam get-role --role-name $ROLE_NAME --region $AWS_REGION > /dev/null 2>&1; then
65+
echo "DEBUG: About to call AWS CLI for role: $ROLE_NAME"
66+
67+
# Temporarily disable exit-on-error for AWS CLI call
68+
set +e
69+
70+
# Capture stdout and stderr separately
71+
ROLE_ARN=$(aws iam get-role --role-name $ROLE_NAME --query 'Role.Arn' --output text 2>/tmp/deploy-error.txt)
72+
ROLE_EXIT_CODE=$?
73+
ROLE_ERROR=$(cat /tmp/deploy-error.txt 2>/dev/null)
74+
75+
# Re-enable exit-on-error
76+
set -e
77+
78+
echo "DEBUG: AWS CLI returned - Exit code=$ROLE_EXIT_CODE, ARN='$ROLE_ARN', Error='$ROLE_ERROR'"
79+
80+
if [ $ROLE_EXIT_CODE -eq 0 ] && [[ "$ROLE_ARN" =~ ^arn:aws:iam ]]; then
3381
echo "✅ IAM role '$ROLE_NAME' already exists"
34-
ROLE_ARN=$(aws iam get-role --role-name $ROLE_NAME --region $AWS_REGION --query 'Role.Arn' --output text)
82+
elif [[ "$ROLE_ERROR" =~ "ExpiredToken" ]]; then
83+
echo "❌ AWS SSO session expired"
84+
echo ""
85+
echo " Run the following command to refresh your session:"
86+
echo " aws sso login"
87+
echo ""
88+
exit 1
89+
elif [ $ROLE_EXIT_CODE -eq 255 ]; then
90+
echo "❌ AWS CLI error - check your credentials"
91+
echo " Error: $ROLE_ERROR"
92+
echo ""
93+
echo " Make sure AWS credentials are configured:"
94+
echo " - aws sso login (for SSO)"
95+
echo " - aws configure (for access keys)"
96+
echo ""
97+
exit 1
3598
else
36-
echo "⚠️ IAM role not found. Creating..."
37-
echo " Run the following command:"
99+
echo "⚠️ IAM role not found"
100+
echo " Error: $ROLE_ERROR"
38101
echo ""
102+
echo " Run the following command to create it:"
39103
echo " ./create-iam-role.sh"
40104
echo ""
41105
exit 1

deploy/llm-markdown/lambda-edge/markdown-generator/index.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@
88
* Triggers for: *.md file requests
99
*/
1010

11-
import { fetchHtmlFromS3, listChildPages } from './lib/s3-utils.js';
12-
import {
11+
const { fetchHtmlFromS3, listChildPages } = require('./lib/s3-utils.js');
12+
const {
1313
convertToMarkdown,
1414
convertSectionToMarkdown,
15-
} from '../../../../scripts/lib/markdown-converter.js';
15+
} = require('./scripts/lib/markdown-converter.js');
1616

1717
/**
1818
* Lambda@Edge handler
1919
* @param {Object} event - CloudFront origin request event
2020
* @returns {Object} CloudFront response object
2121
*/
22-
export const handler = async (event) => {
22+
exports.handler = async (event) => {
2323
const request = event.Records[0].cf.request;
2424
const uri = request.uri;
2525

deploy/llm-markdown/lambda-edge/markdown-generator/lib/s3-utils.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,27 @@ const {
1010
ListObjectsV2Command,
1111
} = require('@aws-sdk/client-s3');
1212

13-
// S3 bucket configuration (from environment or hardcoded for staging)
14-
const BUCKET_NAME = process.env.S3_BUCKET || process.env.S3_TEST_BUCKET;
15-
const s3Client = new S3Client({ region: 'us-east-1' });
13+
// S3 bucket configuration
14+
// Try environment variable first (works for testing), then config file
15+
let BUCKET_NAME = process.env.S3_BUCKET;
16+
17+
if (!BUCKET_NAME) {
18+
try {
19+
const config = require('../config.json');
20+
BUCKET_NAME = config.s3Bucket;
21+
} catch (err) {
22+
throw new Error(
23+
'S3_BUCKET must be set via environment variable or config.json'
24+
);
25+
}
26+
}
27+
28+
// Configure S3 client with proper region handling
29+
const s3Client = new S3Client({
30+
region: process.env.AWS_REGION || 'us-east-1',
31+
// Follow bucket region redirects automatically
32+
followRegionRedirects: true,
33+
});
1634

1735
/**
1836
* Fetch HTML content from S3

deploy/llm-markdown/lambda-edge/markdown-generator/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"version": "1.0.0",
44
"description": "Lambda@Edge function for on-demand markdown generation from HTML",
55
"main": "index.js",
6-
"type": "module",
76
"scripts": {
87
"install-deps": "npm install",
98
"package": "zip -r function.zip index.js lib/ node_modules/",
@@ -12,6 +11,7 @@
1211
"dependencies": {
1312
"@aws-sdk/client-s3": "^3.484.0",
1413
"jsdom": "^23.0.1",
14+
"js-yaml": "^4.1.0",
1515
"turndown": "^7.1.2"
1616
},
1717
"devDependencies": {},

deploy/llm-markdown/lambda-edge/markdown-generator/yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,11 @@ agent-base@^7.1.0, agent-base@^7.1.2:
11261126
resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
11271127
integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
11281128

1129+
argparse@^2.0.1:
1130+
version "2.0.1"
1131+
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
1132+
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
1133+
11291134
asynckit@^0.4.0:
11301135
version "0.4.0"
11311136
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
@@ -1346,6 +1351,13 @@ is-potential-custom-element-name@^1.0.1:
13461351
resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz"
13471352
integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
13481353

1354+
js-yaml@^4.1.0:
1355+
version "4.1.1"
1356+
resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz"
1357+
integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==
1358+
dependencies:
1359+
argparse "^2.0.1"
1360+
13491361
jsdom@^23.0.1:
13501362
version "23.2.0"
13511363
resolved "https://registry.npmjs.org/jsdom/-/jsdom-23.2.0.tgz"

layouts/_default/landing-influxdb.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ <h3>Monitor & Alert</h3>
5252
</div>
5353
</div>
5454

55-
<!-- {{ partial "article.html" . }} -->
55+
<div class="article">
56+
<article class="article--content">
57+
{{ partial "article/format-selector.html" . }}
58+
</article>
59+
</div>
5660
<div class="copyright">© {{ now.Year }} InfluxData, Inc.</div>
5761
</div>
5862
</div>

0 commit comments

Comments
 (0)