doc2vec 2.8.0 → 2.9.1

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 CHANGED
@@ -229,6 +229,8 @@ Configuration is managed through two files:
229
229
  * `encoding`: (Optional) Text file encoding (defaults to `'utf8'`). Does not apply to binary files (PDF, DOC, DOCX).
230
230
  * `url_rewrite_prefix`: (Optional) URL prefix to rewrite `s3://` URLs (e.g., `'https://docs.example.com'`).
231
231
 
232
+ **S3 user metadata resolution:** The `product_name` and `version` fields support a `metadata(...)` syntax to dynamically resolve values from S3 object user metadata. For example, `product_name: 'metadata(x-amz-meta-product-name)'` will set `product_name` to the value of the `x-amz-meta-product-name` user metadata on each S3 object. If the metadata key doesn't exist on an object, an empty string is used. Literal values (without the `metadata(...)` wrapper) work as before.
233
+
232
234
  Authentication uses the AWS SDK default credential chain: environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`), `~/.aws/credentials`, IAM roles, etc.
233
235
 
234
236
  Incremental sync tracks object `LastModified` timestamps so only new or updated objects are processed on subsequent runs. Deleted objects are automatically cleaned up.
@@ -365,7 +367,7 @@ Configuration is managed through two files:
365
367
 
366
368
  # S3 bucket source example
367
369
  - type: 's3'
368
- product_name: 'my-docs'
370
+ product_name: 'metadata(x-amz-meta-product-name)'
369
371
  version: 'latest'
370
372
  bucket: 'my-documentation-bucket'
371
373
  prefix: 'docs/v2/'
@@ -1707,7 +1707,10 @@ class ContentProcessor {
1707
1707
  if (lang) {
1708
1708
  try {
1709
1709
  const codeChunker = await this.getCodeChunker(lang, sourceConfig.chunk_size);
1710
- chunks = await codeChunker.chunk(code);
1710
+ chunks = await Promise.race([
1711
+ codeChunker.chunk(code),
1712
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`CodeChunker timed out after 30s for ${normalizedPath || url}`)), 30000))
1713
+ ]);
1711
1714
  }
1712
1715
  catch (error) {
1713
1716
  logger.warn(`CodeChunker failed for ${normalizedPath || url}, falling back to token chunking:`, error);
package/dist/doc2vec.js CHANGED
@@ -783,7 +783,14 @@ class Doc2Vec {
783
783
  else {
784
784
  fileUrl = `s3://${config.bucket}/${obj.key}`;
785
785
  }
786
- const chunks = await this.contentProcessor.chunkMarkdown(content, config, fileUrl);
786
+ // Resolve metadata(...) references in product_name and version
787
+ const s3Meta = getResponse.Metadata || {};
788
+ const resolvedConfig = {
789
+ ...config,
790
+ product_name: this.resolveS3MetadataValue(config.product_name, s3Meta),
791
+ version: this.resolveS3MetadataValue(config.version, s3Meta),
792
+ };
793
+ const chunks = await this.contentProcessor.chunkMarkdown(content, resolvedConfig, fileUrl);
787
794
  logger.info(`Created ${chunks.length} chunks for ${obj.key}`);
788
795
  await this.processChunksForUrl(chunks, fileUrl, dbConnection, logger);
789
796
  processedCount++;
@@ -828,6 +835,21 @@ class Doc2Vec {
828
835
  await database_1.DatabaseManager.setMetadataValue(dbConnection, lastSyncKey, `${syncStartTimestamp}`, logger, this.embeddingDimension);
829
836
  logger.info(`Finished processing S3 bucket: ${config.bucket}`);
830
837
  }
838
+ /**
839
+ * Resolves a config value that may use the metadata(...) syntax.
840
+ * e.g. "metadata(x-amz-meta-product-name)" looks up "product-name" in the S3 object's user metadata.
841
+ * Returns the original value if no metadata(...) pattern is found.
842
+ * Returns empty string if the referenced metadata key doesn't exist on the object.
843
+ */
844
+ resolveS3MetadataValue(configValue, s3Metadata) {
845
+ const match = configValue.match(/^metadata\((.+)\)$/);
846
+ if (!match)
847
+ return configValue;
848
+ const metaKey = match[1];
849
+ // AWS SDK returns user metadata keys without the x-amz-meta- prefix
850
+ const lookupKey = metaKey.replace(/^x-amz-meta-/, '');
851
+ return s3Metadata[lookupKey] ?? '';
852
+ }
831
853
  async processCodeSource(config, parentLogger) {
832
854
  const logger = parentLogger.child('process');
833
855
  logger.info(`Starting processing for code source (${config.source})`);
@@ -1508,7 +1530,7 @@ class Doc2Vec {
1508
1530
  const response = await this.openai.embeddings.create({
1509
1531
  model: this.embeddingModel,
1510
1532
  input: safeTexts,
1511
- });
1533
+ }, { timeout: 60000 });
1512
1534
  logger.debug(`Successfully created ${response.data.length} embeddings`);
1513
1535
  return response.data.map(d => d.embedding);
1514
1536
  }
@@ -1533,5 +1555,7 @@ if (require.main === module) {
1533
1555
  process.exit(1);
1534
1556
  }
1535
1557
  const doc2Vec = new Doc2Vec(configPath);
1536
- doc2Vec.run().catch(console.error);
1558
+ doc2Vec.run()
1559
+ .then(() => process.exit(0))
1560
+ .catch((err) => { console.error(err); process.exit(1); });
1537
1561
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc2vec",
3
- "version": "2.8.0",
3
+ "version": "2.9.1",
4
4
  "type": "commonjs",
5
5
  "description": "",
6
6
  "main": "dist/doc2vec.js",