folderblog 0.0.2 → 0.0.3

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.
Files changed (61) hide show
  1. package/dist/{chunk-24MKFHML.cjs → chunk-2TZSVPNP.cjs} +5 -0
  2. package/dist/{chunk-HMQIQUPB.cjs → chunk-6TFXNIO6.cjs} +108 -0
  3. package/dist/{chunk-ZRUBI3GH.js → chunk-B43UAOPC.js} +106 -1
  4. package/dist/{chunk-XP5J4LFJ.js → chunk-D26H5722.js} +5 -0
  5. package/dist/chunk-E7PYGJA7.cjs +39 -0
  6. package/dist/{chunk-QA4KPPTA.cjs → chunk-J3Y3HEBF.cjs} +84 -13
  7. package/dist/{chunk-PARGDJNY.js → chunk-K76XLEC7.js} +1 -1
  8. package/dist/{chunk-IXP35S24.js → chunk-LPPBVXJ7.js} +83 -12
  9. package/dist/chunk-Q6EXKX6K.js +17 -0
  10. package/dist/{chunk-4ZJGUMHS.cjs → chunk-Q6EYTOTM.cjs} +2 -2
  11. package/dist/chunk-UCXXH2MP.cjs +20 -0
  12. package/dist/chunk-XQD3UUL5.js +34 -0
  13. package/dist/cli/bin.cjs +5 -5
  14. package/dist/cli/bin.js +4 -4
  15. package/dist/cli/index.cjs +5 -5
  16. package/dist/cli/index.js +4 -4
  17. package/dist/config-ADPY6IQS.d.cts +473 -0
  18. package/dist/config-Dctsdeo6.d.ts +473 -0
  19. package/dist/index.cjs +157 -187
  20. package/dist/index.d.cts +4 -3
  21. package/dist/index.d.ts +4 -3
  22. package/dist/index.js +16 -69
  23. package/dist/local/index.cjs +785 -0
  24. package/dist/local/index.d.cts +268 -0
  25. package/dist/local/index.d.ts +268 -0
  26. package/dist/local/index.js +772 -0
  27. package/dist/output-0P0br3Jc.d.cts +452 -0
  28. package/dist/output-0P0br3Jc.d.ts +452 -0
  29. package/dist/plugins/embed-cloudflare-ai.cjs +166 -0
  30. package/dist/plugins/embed-cloudflare-ai.d.cts +73 -0
  31. package/dist/plugins/embed-cloudflare-ai.d.ts +73 -0
  32. package/dist/plugins/embed-cloudflare-ai.js +156 -0
  33. package/dist/plugins/embed-transformers.cjs +121 -0
  34. package/dist/plugins/embed-transformers.d.cts +55 -0
  35. package/dist/plugins/embed-transformers.d.ts +55 -0
  36. package/dist/plugins/embed-transformers.js +113 -0
  37. package/dist/plugins/similarity.cjs +19 -0
  38. package/dist/plugins/similarity.d.cts +41 -0
  39. package/dist/plugins/similarity.d.ts +41 -0
  40. package/dist/plugins/similarity.js +2 -0
  41. package/dist/processor/index.cjs +123 -111
  42. package/dist/processor/index.d.cts +6 -2
  43. package/dist/processor/index.d.ts +6 -2
  44. package/dist/processor/index.js +3 -3
  45. package/dist/processor/plugins.cjs +24 -12
  46. package/dist/processor/plugins.d.cts +4 -2
  47. package/dist/processor/plugins.d.ts +4 -2
  48. package/dist/processor/plugins.js +1 -1
  49. package/dist/processor/types.cjs +16 -16
  50. package/dist/processor/types.d.cts +3 -2
  51. package/dist/processor/types.d.ts +3 -2
  52. package/dist/processor/types.js +1 -1
  53. package/dist/seo/index.cjs +289 -0
  54. package/dist/seo/index.d.cts +95 -0
  55. package/dist/seo/index.d.ts +95 -0
  56. package/dist/seo/index.js +274 -0
  57. package/dist/server/index.cjs +2 -5
  58. package/dist/server/index.js +2 -5
  59. package/package.json +36 -1
  60. package/dist/config-DFr-htlO.d.cts +0 -887
  61. package/dist/config-DFr-htlO.d.ts +0 -887
@@ -0,0 +1,73 @@
1
+ import { T as TextEmbeddingPlugin, P as PluginContext } from '../config-Dctsdeo6.js';
2
+ import '../output-0P0br3Jc.js';
3
+
4
+ /**
5
+ * Cloudflare Workers AI Text Embedding Plugin
6
+ *
7
+ * Uses Cloudflare Workers AI for text embeddings.
8
+ * Supports both:
9
+ * - Binding mode: When running inside a Cloudflare Worker (env.AI)
10
+ * - REST API mode: When running outside CF (uses fetch)
11
+ *
12
+ * Available models:
13
+ * - @cf/baai/bge-small-en-v1.5 (384 dims, fast, English)
14
+ * - @cf/baai/bge-base-en-v1.5 (768 dims, balanced, English)
15
+ * - @cf/baai/bge-large-en-v1.5 (1024 dims, best quality, English)
16
+ * - @cf/baai/bge-m3 (1024 dims, multilingual)
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // In a Cloudflare Worker:
21
+ * import { createCloudflareAIEmbedderWithBinding } from 'folderblog/plugins/embed-cloudflare-ai';
22
+ * const embedder = createCloudflareAIEmbedderWithBinding(env.AI);
23
+ *
24
+ * // External via REST API:
25
+ * import { createCloudflareAIEmbedderFromEnv } from 'folderblog/plugins/embed-cloudflare-ai';
26
+ * const embedder = createCloudflareAIEmbedderFromEnv();
27
+ * ```
28
+ */
29
+
30
+ interface CloudflareAIBinding {
31
+ run<T = unknown>(model: string, input: Record<string, unknown>): Promise<T>;
32
+ }
33
+ type PoolingStrategy = 'mean' | 'cls';
34
+ interface CloudflareAIEmbedderOptions {
35
+ /** Cloudflare Workers AI binding (env.AI). When provided, uses direct binding. */
36
+ readonly binding?: CloudflareAIBinding;
37
+ /** Cloudflare Account ID (required for REST API mode) */
38
+ readonly accountId?: string;
39
+ /** Cloudflare API Token with Workers AI permissions (required for REST API mode) */
40
+ readonly apiToken?: string;
41
+ /** Model ID (default: '@cf/baai/bge-small-en-v1.5') */
42
+ readonly modelId?: string;
43
+ /** Pooling strategy (default: 'cls' for better accuracy) */
44
+ readonly pooling?: PoolingStrategy;
45
+ /** Batch size for concurrent requests (default: 100) */
46
+ readonly batchSize?: number;
47
+ /** Request timeout in ms (default: 30000) */
48
+ readonly timeout?: number;
49
+ }
50
+ declare const DEFAULT_MODEL = "@cf/baai/bge-small-en-v1.5";
51
+ declare const MODEL_DIMENSIONS: Record<string, number>;
52
+ declare class CloudflareAITextEmbedder implements TextEmbeddingPlugin {
53
+ readonly name: "textEmbedder";
54
+ readonly model: string;
55
+ readonly dimensions: number;
56
+ private ready;
57
+ private context;
58
+ private options;
59
+ constructor(options?: CloudflareAIEmbedderOptions);
60
+ initialize(context: PluginContext): Promise<void>;
61
+ isReady(): boolean;
62
+ dispose(): Promise<void>;
63
+ embed(text: string): Promise<readonly number[]>;
64
+ batchEmbed(texts: readonly string[]): Promise<readonly (readonly number[])[]>;
65
+ private embedBatch;
66
+ private embedWithBinding;
67
+ private embedWithRestApi;
68
+ }
69
+ declare const createCloudflareAIEmbedderWithBinding: (binding: CloudflareAIBinding, options?: Omit<CloudflareAIEmbedderOptions, "binding" | "accountId" | "apiToken">) => TextEmbeddingPlugin;
70
+ declare const createCloudflareAIEmbedderWithRestApi: (accountId: string, apiToken: string, options?: Omit<CloudflareAIEmbedderOptions, "binding" | "accountId" | "apiToken">) => TextEmbeddingPlugin;
71
+ declare const createCloudflareAIEmbedderFromEnv: (options?: Omit<CloudflareAIEmbedderOptions, "binding" | "accountId" | "apiToken">) => TextEmbeddingPlugin;
72
+
73
+ export { DEFAULT_MODEL as CLOUDFLARE_DEFAULT_MODEL, MODEL_DIMENSIONS as CLOUDFLARE_MODEL_DIMENSIONS, type CloudflareAIBinding, type CloudflareAIEmbedderOptions, CloudflareAITextEmbedder, type PoolingStrategy, createCloudflareAIEmbedderFromEnv, createCloudflareAIEmbedderWithBinding, createCloudflareAIEmbedderWithRestApi, CloudflareAITextEmbedder as default };
@@ -0,0 +1,156 @@
1
+ import '../chunk-3RG5ZIWI.js';
2
+
3
+ // src/plugins/embed-cloudflare-ai.ts
4
+ var DEFAULT_MODEL = "@cf/baai/bge-small-en-v1.5";
5
+ var MODEL_DIMENSIONS = {
6
+ "@cf/baai/bge-small-en-v1.5": 384,
7
+ "@cf/baai/bge-base-en-v1.5": 768,
8
+ "@cf/baai/bge-large-en-v1.5": 1024,
9
+ "@cf/baai/bge-m3": 1024
10
+ };
11
+ var CloudflareAITextEmbedder = class {
12
+ name = "textEmbedder";
13
+ model;
14
+ dimensions;
15
+ ready = false;
16
+ context = null;
17
+ options;
18
+ constructor(options = {}) {
19
+ this.options = {
20
+ binding: options.binding,
21
+ accountId: options.accountId,
22
+ apiToken: options.apiToken,
23
+ modelId: options.modelId ?? DEFAULT_MODEL,
24
+ pooling: options.pooling ?? "cls",
25
+ batchSize: options.batchSize ?? 100,
26
+ timeout: options.timeout ?? 3e4
27
+ };
28
+ this.model = this.options.modelId;
29
+ this.dimensions = MODEL_DIMENSIONS[this.model] ?? 384;
30
+ }
31
+ async initialize(context) {
32
+ this.context = context;
33
+ const mode = this.options.binding ? "binding" : "REST API";
34
+ context.log(
35
+ `Initializing CloudflareAITextEmbedder (${mode} mode, model: ${this.model}, pooling: ${this.options.pooling})`,
36
+ "info"
37
+ );
38
+ if (!this.options.binding && (!this.options.accountId || !this.options.apiToken)) {
39
+ throw new Error(
40
+ "CloudflareAITextEmbedder requires either a binding (env.AI) or accountId + apiToken for REST API mode"
41
+ );
42
+ }
43
+ try {
44
+ await this.embed("test");
45
+ context.log(
46
+ `CloudflareAITextEmbedder initialized (${this.dimensions} dimensions)`,
47
+ "info"
48
+ );
49
+ this.ready = true;
50
+ } catch (error) {
51
+ const msg = error instanceof Error ? error.message : String(error);
52
+ context.log(`Failed to initialize Cloudflare AI embedder: ${msg}`, "error");
53
+ throw error;
54
+ }
55
+ }
56
+ isReady() {
57
+ return this.ready;
58
+ }
59
+ async dispose() {
60
+ this.ready = false;
61
+ }
62
+ async embed(text) {
63
+ const results = await this.batchEmbed([text]);
64
+ const result = results[0];
65
+ if (!result) {
66
+ throw new Error("Failed to generate embedding");
67
+ }
68
+ return result;
69
+ }
70
+ async batchEmbed(texts) {
71
+ if (texts.length === 0) {
72
+ return [];
73
+ }
74
+ const results = [];
75
+ const batchSize = this.options.batchSize;
76
+ for (let i = 0; i < texts.length; i += batchSize) {
77
+ const batch = texts.slice(i, i + batchSize);
78
+ const batchResults = await this.embedBatch(batch);
79
+ results.push(...batchResults);
80
+ if (texts.length > 50 && this.context) {
81
+ this.context.log(
82
+ `Embedding progress: ${Math.min(i + batchSize, texts.length)}/${texts.length}`,
83
+ "debug"
84
+ );
85
+ }
86
+ }
87
+ return results;
88
+ }
89
+ async embedBatch(texts) {
90
+ if (this.options.binding) {
91
+ return this.embedWithBinding(texts);
92
+ }
93
+ return this.embedWithRestApi(texts);
94
+ }
95
+ async embedWithBinding(texts) {
96
+ const binding = this.options.binding;
97
+ const response = await binding.run(this.model, {
98
+ text: texts,
99
+ pooling: this.options.pooling
100
+ });
101
+ if (!response?.data) {
102
+ throw new Error("Invalid response from Cloudflare AI binding");
103
+ }
104
+ return response.data;
105
+ }
106
+ async embedWithRestApi(texts) {
107
+ const url = `https://api.cloudflare.com/client/v4/accounts/${this.options.accountId}/ai/run/${this.model}`;
108
+ const controller = new AbortController();
109
+ const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
110
+ try {
111
+ const response = await fetch(url, {
112
+ method: "POST",
113
+ headers: {
114
+ "Authorization": `Bearer ${this.options.apiToken}`,
115
+ "Content-Type": "application/json"
116
+ },
117
+ body: JSON.stringify({
118
+ text: texts,
119
+ pooling: this.options.pooling
120
+ }),
121
+ signal: controller.signal
122
+ });
123
+ if (!response.ok) {
124
+ const errorText = await response.text();
125
+ throw new Error(`Cloudflare AI API error (${response.status}): ${errorText}`);
126
+ }
127
+ const data = await response.json();
128
+ if (!data.success || !data.result?.data) {
129
+ const errorMsg = data.errors?.[0]?.message ?? "Unknown error";
130
+ throw new Error(`Cloudflare AI API error: ${errorMsg}`);
131
+ }
132
+ return data.result.data;
133
+ } finally {
134
+ clearTimeout(timeoutId);
135
+ }
136
+ }
137
+ };
138
+ var createCloudflareAIEmbedderWithBinding = (binding, options) => {
139
+ return new CloudflareAITextEmbedder({ ...options, binding });
140
+ };
141
+ var createCloudflareAIEmbedderWithRestApi = (accountId, apiToken, options) => {
142
+ return new CloudflareAITextEmbedder({ ...options, accountId, apiToken });
143
+ };
144
+ var createCloudflareAIEmbedderFromEnv = (options) => {
145
+ const accountId = process.env["CLOUDFLARE_ACCOUNT_ID"];
146
+ const apiToken = process.env["CLOUDFLARE_API_TOKEN"];
147
+ if (!accountId || !apiToken) {
148
+ throw new Error(
149
+ "CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN environment variables are required"
150
+ );
151
+ }
152
+ return new CloudflareAITextEmbedder({ ...options, accountId, apiToken });
153
+ };
154
+ var embed_cloudflare_ai_default = CloudflareAITextEmbedder;
155
+
156
+ export { DEFAULT_MODEL as CLOUDFLARE_DEFAULT_MODEL, MODEL_DIMENSIONS as CLOUDFLARE_MODEL_DIMENSIONS, CloudflareAITextEmbedder, createCloudflareAIEmbedderFromEnv, createCloudflareAIEmbedderWithBinding, createCloudflareAIEmbedderWithRestApi, embed_cloudflare_ai_default as default };
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ require('../chunk-OBGZSXTJ.cjs');
6
+
7
+ // src/plugins/embed-transformers.ts
8
+ var DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
9
+ var MODEL_DIMENSIONS = {
10
+ "Xenova/all-MiniLM-L6-v2": 384,
11
+ "Xenova/all-mpnet-base-v2": 768,
12
+ "Xenova/paraphrase-MiniLM-L6-v2": 384,
13
+ "Xenova/bge-small-en-v1.5": 384,
14
+ "Xenova/bge-base-en-v1.5": 768
15
+ };
16
+ var TransformersTextEmbedder = class {
17
+ name = "textEmbedder";
18
+ model;
19
+ dimensions;
20
+ ready = false;
21
+ context = null;
22
+ pipeline = null;
23
+ options;
24
+ constructor(options = {}) {
25
+ this.options = {
26
+ modelId: options.modelId ?? DEFAULT_MODEL,
27
+ pooling: options.pooling ?? "mean",
28
+ normalize: options.normalize ?? true,
29
+ maxLength: options.maxLength ?? 512
30
+ };
31
+ this.model = this.options.modelId;
32
+ this.dimensions = MODEL_DIMENSIONS[this.model] ?? 384;
33
+ }
34
+ async initialize(context) {
35
+ this.context = context;
36
+ context.log(`Initializing TransformersTextEmbedder with ${this.model}...`, "info");
37
+ try {
38
+ const { pipeline } = await import('@huggingface/transformers');
39
+ this.pipeline = await pipeline("feature-extraction", this.model);
40
+ context.log(
41
+ `TransformersTextEmbedder initialized (${this.dimensions} dimensions)`,
42
+ "info"
43
+ );
44
+ this.ready = true;
45
+ } catch (error) {
46
+ const msg = error instanceof Error ? error.message : String(error);
47
+ context.log(`Failed to initialize embedding model: ${msg}`, "error");
48
+ throw error;
49
+ }
50
+ }
51
+ isReady() {
52
+ return this.ready;
53
+ }
54
+ async dispose() {
55
+ this.pipeline = null;
56
+ this.ready = false;
57
+ }
58
+ async embed(text) {
59
+ if (!this.pipeline) {
60
+ throw new Error("TransformersTextEmbedder not initialized");
61
+ }
62
+ const result = await this.pipeline(text, {
63
+ pooling: this.options.pooling,
64
+ normalize: this.options.normalize
65
+ });
66
+ return this.extractEmbedding(result);
67
+ }
68
+ async batchEmbed(texts) {
69
+ if (!this.pipeline) {
70
+ throw new Error("TransformersTextEmbedder not initialized");
71
+ }
72
+ const batchSize = 16;
73
+ const results = [];
74
+ for (let i = 0; i < texts.length; i += batchSize) {
75
+ const batch = texts.slice(i, i + batchSize);
76
+ for (const text of batch) {
77
+ const result = await this.pipeline(text, {
78
+ pooling: this.options.pooling,
79
+ normalize: this.options.normalize
80
+ });
81
+ results.push(this.extractEmbedding(result));
82
+ }
83
+ if (texts.length > 50 && this.context) {
84
+ this.context.log(
85
+ `Embedding progress: ${Math.min(i + batchSize, texts.length)}/${texts.length}`,
86
+ "debug"
87
+ );
88
+ }
89
+ }
90
+ return results;
91
+ }
92
+ extractEmbedding(result) {
93
+ if (result && typeof result.tolist === "function") {
94
+ const list = result.tolist();
95
+ if (Array.isArray(list) && list.length === 1) {
96
+ return list[0];
97
+ }
98
+ return list;
99
+ }
100
+ if (result && result.data) {
101
+ return Array.from(result.data);
102
+ }
103
+ if (Array.isArray(result)) {
104
+ if (Array.isArray(result[0])) {
105
+ return result[0];
106
+ }
107
+ return result;
108
+ }
109
+ return new Array(this.dimensions).fill(0);
110
+ }
111
+ };
112
+ var createTransformersEmbedder = (options) => {
113
+ return new TransformersTextEmbedder(options);
114
+ };
115
+ var embed_transformers_default = TransformersTextEmbedder;
116
+
117
+ exports.DEFAULT_MODEL = DEFAULT_MODEL;
118
+ exports.MODEL_DIMENSIONS = MODEL_DIMENSIONS;
119
+ exports.TransformersTextEmbedder = TransformersTextEmbedder;
120
+ exports.createTransformersEmbedder = createTransformersEmbedder;
121
+ exports.default = embed_transformers_default;
@@ -0,0 +1,55 @@
1
+ import { T as TextEmbeddingPlugin, P as PluginContext } from '../config-ADPY6IQS.cjs';
2
+ import '../output-0P0br3Jc.cjs';
3
+
4
+ /**
5
+ * Transformers.js Text Embedding Plugin
6
+ *
7
+ * Uses HuggingFace Transformers.js for local text embeddings.
8
+ * Supports various sentence transformer models.
9
+ *
10
+ * Requires: `@huggingface/transformers` (optional peer dependency)
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { createTransformersEmbedder } from 'folderblog/plugins/embed-transformers';
15
+ *
16
+ * const embedder = createTransformersEmbedder({
17
+ * modelId: 'Xenova/all-MiniLM-L6-v2',
18
+ * });
19
+ * ```
20
+ */
21
+
22
+ interface TransformersEmbedderOptions {
23
+ /** Model ID from HuggingFace (default: 'Xenova/all-MiniLM-L6-v2') */
24
+ readonly modelId?: string;
25
+ /** Pooling strategy (default: 'mean') */
26
+ readonly pooling?: 'mean' | 'cls' | 'none';
27
+ /** Normalize embeddings (default: true) */
28
+ readonly normalize?: boolean;
29
+ /** Maximum sequence length (default: 512) */
30
+ readonly maxLength?: number;
31
+ }
32
+ declare const DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
33
+ declare const MODEL_DIMENSIONS: Record<string, number>;
34
+ declare class TransformersTextEmbedder implements TextEmbeddingPlugin {
35
+ readonly name: "textEmbedder";
36
+ readonly model: string;
37
+ readonly dimensions: number;
38
+ private ready;
39
+ private context;
40
+ private pipeline;
41
+ private options;
42
+ constructor(options?: TransformersEmbedderOptions);
43
+ initialize(context: PluginContext): Promise<void>;
44
+ isReady(): boolean;
45
+ dispose(): Promise<void>;
46
+ embed(text: string): Promise<readonly number[]>;
47
+ batchEmbed(texts: readonly string[]): Promise<readonly (readonly number[])[]>;
48
+ private extractEmbedding;
49
+ }
50
+ /**
51
+ * Create a Transformers.js text embedder plugin
52
+ */
53
+ declare const createTransformersEmbedder: (options?: TransformersEmbedderOptions) => TextEmbeddingPlugin;
54
+
55
+ export { DEFAULT_MODEL, MODEL_DIMENSIONS, type TransformersEmbedderOptions, TransformersTextEmbedder, createTransformersEmbedder, TransformersTextEmbedder as default };
@@ -0,0 +1,55 @@
1
+ import { T as TextEmbeddingPlugin, P as PluginContext } from '../config-Dctsdeo6.js';
2
+ import '../output-0P0br3Jc.js';
3
+
4
+ /**
5
+ * Transformers.js Text Embedding Plugin
6
+ *
7
+ * Uses HuggingFace Transformers.js for local text embeddings.
8
+ * Supports various sentence transformer models.
9
+ *
10
+ * Requires: `@huggingface/transformers` (optional peer dependency)
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { createTransformersEmbedder } from 'folderblog/plugins/embed-transformers';
15
+ *
16
+ * const embedder = createTransformersEmbedder({
17
+ * modelId: 'Xenova/all-MiniLM-L6-v2',
18
+ * });
19
+ * ```
20
+ */
21
+
22
+ interface TransformersEmbedderOptions {
23
+ /** Model ID from HuggingFace (default: 'Xenova/all-MiniLM-L6-v2') */
24
+ readonly modelId?: string;
25
+ /** Pooling strategy (default: 'mean') */
26
+ readonly pooling?: 'mean' | 'cls' | 'none';
27
+ /** Normalize embeddings (default: true) */
28
+ readonly normalize?: boolean;
29
+ /** Maximum sequence length (default: 512) */
30
+ readonly maxLength?: number;
31
+ }
32
+ declare const DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
33
+ declare const MODEL_DIMENSIONS: Record<string, number>;
34
+ declare class TransformersTextEmbedder implements TextEmbeddingPlugin {
35
+ readonly name: "textEmbedder";
36
+ readonly model: string;
37
+ readonly dimensions: number;
38
+ private ready;
39
+ private context;
40
+ private pipeline;
41
+ private options;
42
+ constructor(options?: TransformersEmbedderOptions);
43
+ initialize(context: PluginContext): Promise<void>;
44
+ isReady(): boolean;
45
+ dispose(): Promise<void>;
46
+ embed(text: string): Promise<readonly number[]>;
47
+ batchEmbed(texts: readonly string[]): Promise<readonly (readonly number[])[]>;
48
+ private extractEmbedding;
49
+ }
50
+ /**
51
+ * Create a Transformers.js text embedder plugin
52
+ */
53
+ declare const createTransformersEmbedder: (options?: TransformersEmbedderOptions) => TextEmbeddingPlugin;
54
+
55
+ export { DEFAULT_MODEL, MODEL_DIMENSIONS, type TransformersEmbedderOptions, TransformersTextEmbedder, createTransformersEmbedder, TransformersTextEmbedder as default };
@@ -0,0 +1,113 @@
1
+ import '../chunk-3RG5ZIWI.js';
2
+
3
+ // src/plugins/embed-transformers.ts
4
+ var DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
5
+ var MODEL_DIMENSIONS = {
6
+ "Xenova/all-MiniLM-L6-v2": 384,
7
+ "Xenova/all-mpnet-base-v2": 768,
8
+ "Xenova/paraphrase-MiniLM-L6-v2": 384,
9
+ "Xenova/bge-small-en-v1.5": 384,
10
+ "Xenova/bge-base-en-v1.5": 768
11
+ };
12
+ var TransformersTextEmbedder = class {
13
+ name = "textEmbedder";
14
+ model;
15
+ dimensions;
16
+ ready = false;
17
+ context = null;
18
+ pipeline = null;
19
+ options;
20
+ constructor(options = {}) {
21
+ this.options = {
22
+ modelId: options.modelId ?? DEFAULT_MODEL,
23
+ pooling: options.pooling ?? "mean",
24
+ normalize: options.normalize ?? true,
25
+ maxLength: options.maxLength ?? 512
26
+ };
27
+ this.model = this.options.modelId;
28
+ this.dimensions = MODEL_DIMENSIONS[this.model] ?? 384;
29
+ }
30
+ async initialize(context) {
31
+ this.context = context;
32
+ context.log(`Initializing TransformersTextEmbedder with ${this.model}...`, "info");
33
+ try {
34
+ const { pipeline } = await import('@huggingface/transformers');
35
+ this.pipeline = await pipeline("feature-extraction", this.model);
36
+ context.log(
37
+ `TransformersTextEmbedder initialized (${this.dimensions} dimensions)`,
38
+ "info"
39
+ );
40
+ this.ready = true;
41
+ } catch (error) {
42
+ const msg = error instanceof Error ? error.message : String(error);
43
+ context.log(`Failed to initialize embedding model: ${msg}`, "error");
44
+ throw error;
45
+ }
46
+ }
47
+ isReady() {
48
+ return this.ready;
49
+ }
50
+ async dispose() {
51
+ this.pipeline = null;
52
+ this.ready = false;
53
+ }
54
+ async embed(text) {
55
+ if (!this.pipeline) {
56
+ throw new Error("TransformersTextEmbedder not initialized");
57
+ }
58
+ const result = await this.pipeline(text, {
59
+ pooling: this.options.pooling,
60
+ normalize: this.options.normalize
61
+ });
62
+ return this.extractEmbedding(result);
63
+ }
64
+ async batchEmbed(texts) {
65
+ if (!this.pipeline) {
66
+ throw new Error("TransformersTextEmbedder not initialized");
67
+ }
68
+ const batchSize = 16;
69
+ const results = [];
70
+ for (let i = 0; i < texts.length; i += batchSize) {
71
+ const batch = texts.slice(i, i + batchSize);
72
+ for (const text of batch) {
73
+ const result = await this.pipeline(text, {
74
+ pooling: this.options.pooling,
75
+ normalize: this.options.normalize
76
+ });
77
+ results.push(this.extractEmbedding(result));
78
+ }
79
+ if (texts.length > 50 && this.context) {
80
+ this.context.log(
81
+ `Embedding progress: ${Math.min(i + batchSize, texts.length)}/${texts.length}`,
82
+ "debug"
83
+ );
84
+ }
85
+ }
86
+ return results;
87
+ }
88
+ extractEmbedding(result) {
89
+ if (result && typeof result.tolist === "function") {
90
+ const list = result.tolist();
91
+ if (Array.isArray(list) && list.length === 1) {
92
+ return list[0];
93
+ }
94
+ return list;
95
+ }
96
+ if (result && result.data) {
97
+ return Array.from(result.data);
98
+ }
99
+ if (Array.isArray(result)) {
100
+ if (Array.isArray(result[0])) {
101
+ return result[0];
102
+ }
103
+ return result;
104
+ }
105
+ return new Array(this.dimensions).fill(0);
106
+ }
107
+ };
108
+ var createTransformersEmbedder = (options) => {
109
+ return new TransformersTextEmbedder(options);
110
+ };
111
+ var embed_transformers_default = TransformersTextEmbedder;
112
+
113
+ export { DEFAULT_MODEL, MODEL_DIMENSIONS, TransformersTextEmbedder, createTransformersEmbedder, embed_transformers_default as default };
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ var chunk6TFXNIO6_cjs = require('../chunk-6TFXNIO6.cjs');
4
+ require('../chunk-OBGZSXTJ.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "CosineSimilarityPlugin", {
9
+ enumerable: true,
10
+ get: function () { return chunk6TFXNIO6_cjs.CosineSimilarityPlugin; }
11
+ });
12
+ Object.defineProperty(exports, "cosineSimilarity", {
13
+ enumerable: true,
14
+ get: function () { return chunk6TFXNIO6_cjs.cosineSimilarity; }
15
+ });
16
+ Object.defineProperty(exports, "createSimilarityPlugin", {
17
+ enumerable: true,
18
+ get: function () { return chunk6TFXNIO6_cjs.createSimilarityPlugin; }
19
+ });
@@ -0,0 +1,41 @@
1
+ import { y as SimilarityPlugin, P as PluginContext, z as SimilarityResult } from '../config-ADPY6IQS.cjs';
2
+ import { d as ProcessedPost } from '../output-0P0br3Jc.cjs';
3
+
4
+ /**
5
+ * Cosine Similarity Plugin
6
+ *
7
+ * Computes post similarity from text embedding vectors.
8
+ * Pure math — no external dependencies.
9
+ */
10
+
11
+ interface SimilarityPluginOptions {
12
+ /** Number of similar posts to return per post (default: 5) */
13
+ readonly topN?: number;
14
+ /** Minimum similarity score threshold (default: 0) */
15
+ readonly threshold?: number;
16
+ }
17
+ declare class CosineSimilarityPlugin implements SimilarityPlugin {
18
+ readonly name: "similarity";
19
+ readonly requires: readonly ["textEmbedder"];
20
+ private ready;
21
+ private context;
22
+ private readonly topN;
23
+ private readonly threshold;
24
+ constructor(options?: SimilarityPluginOptions);
25
+ initialize(context: PluginContext): Promise<void>;
26
+ isReady(): boolean;
27
+ dispose(): Promise<void>;
28
+ computeSimilarity(a: readonly number[], b: readonly number[]): number;
29
+ generateSimilarityMap(posts: readonly ProcessedPost[]): Promise<SimilarityResult>;
30
+ }
31
+ /**
32
+ * Compute cosine similarity between two vectors.
33
+ * Returns 0 if either vector has zero magnitude.
34
+ */
35
+ declare function cosineSimilarity(a: readonly number[], b: readonly number[]): number;
36
+ /**
37
+ * Create a cosine similarity plugin
38
+ */
39
+ declare const createSimilarityPlugin: (options?: SimilarityPluginOptions) => SimilarityPlugin;
40
+
41
+ export { CosineSimilarityPlugin, type SimilarityPluginOptions, cosineSimilarity, createSimilarityPlugin };
@@ -0,0 +1,41 @@
1
+ import { y as SimilarityPlugin, P as PluginContext, z as SimilarityResult } from '../config-Dctsdeo6.js';
2
+ import { d as ProcessedPost } from '../output-0P0br3Jc.js';
3
+
4
+ /**
5
+ * Cosine Similarity Plugin
6
+ *
7
+ * Computes post similarity from text embedding vectors.
8
+ * Pure math — no external dependencies.
9
+ */
10
+
11
+ interface SimilarityPluginOptions {
12
+ /** Number of similar posts to return per post (default: 5) */
13
+ readonly topN?: number;
14
+ /** Minimum similarity score threshold (default: 0) */
15
+ readonly threshold?: number;
16
+ }
17
+ declare class CosineSimilarityPlugin implements SimilarityPlugin {
18
+ readonly name: "similarity";
19
+ readonly requires: readonly ["textEmbedder"];
20
+ private ready;
21
+ private context;
22
+ private readonly topN;
23
+ private readonly threshold;
24
+ constructor(options?: SimilarityPluginOptions);
25
+ initialize(context: PluginContext): Promise<void>;
26
+ isReady(): boolean;
27
+ dispose(): Promise<void>;
28
+ computeSimilarity(a: readonly number[], b: readonly number[]): number;
29
+ generateSimilarityMap(posts: readonly ProcessedPost[]): Promise<SimilarityResult>;
30
+ }
31
+ /**
32
+ * Compute cosine similarity between two vectors.
33
+ * Returns 0 if either vector has zero magnitude.
34
+ */
35
+ declare function cosineSimilarity(a: readonly number[], b: readonly number[]): number;
36
+ /**
37
+ * Create a cosine similarity plugin
38
+ */
39
+ declare const createSimilarityPlugin: (options?: SimilarityPluginOptions) => SimilarityPlugin;
40
+
41
+ export { CosineSimilarityPlugin, type SimilarityPluginOptions, cosineSimilarity, createSimilarityPlugin };
@@ -0,0 +1,2 @@
1
+ export { CosineSimilarityPlugin, cosineSimilarity, createSimilarityPlugin } from '../chunk-B43UAOPC.js';
2
+ import '../chunk-3RG5ZIWI.js';