@samesake/core 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.
@@ -0,0 +1,316 @@
1
+ export { MatchCandidate, MatchComponents, MatchResult, ResolvedMatch } from './schemas.cjs';
2
+ import 'zod';
3
+
4
+ interface FieldDef {
5
+ type: "text" | "number";
6
+ required?: boolean;
7
+ optional?: boolean;
8
+ maxLength?: number;
9
+ }
10
+ /**
11
+ * `source` is either:
12
+ * - a field name on the entity data (e.g. "name")
13
+ * - a template expression with $-prefixed field refs (e.g. "$brand $item_canonical")
14
+ *
15
+ * Functions aren't supported — they can't survive HTTP transport.
16
+ *
17
+ * `model` is an opaque identifier (e.g. "gemini-embedding-001", "text-embedding-3-small",
18
+ * "nomic-embed-text"). @samesake/server passes it through to the consumer's `embed`
19
+ * function untouched; the consumer's embedder decides what to do with it. The matcher
20
+ * uses it to namespace the embedding cache.
21
+ *
22
+ * `dim` is the vector dimension. It IS load-bearing for samesake: the per-project
23
+ * entity_<kind>_match table is created with `vector(<dim>)` columns.
24
+ *
25
+ * `taskType` is opaque metadata that @samesake/server forwards to the consumer's
26
+ * embedder. Useful for provider-specific hints like Gemini's "SEMANTIC_SIMILARITY"
27
+ * vs "RETRIEVAL_QUERY"/"RETRIEVAL_DOCUMENT".
28
+ */
29
+ interface EmbeddingDef {
30
+ source: string;
31
+ model: string;
32
+ dim: number;
33
+ taskType?: string;
34
+ }
35
+ interface PhoneticDef {
36
+ source: string;
37
+ algorithm: "indic-soundex" | "soundex" | "metaphone";
38
+ }
39
+ /**
40
+ * Marks an entity as "parse-shape" — the matcher will call the consumer-provided
41
+ * `parse` function on createMatcher to extract structured product/asset fields
42
+ * (brand, item_canonical, size_value, size_unit, variant, internal_code, ...)
43
+ * from the entity's source text. Those parsed fields then drive gated matching:
44
+ * a brand mismatch downweights a candidate by 5x; a size mismatch drops it.
45
+ *
46
+ * The parse OUTPUT shape (ParsedProductSchema) is owned by @samesake/server
47
+ * because the SQL match function generation depends on its columns. Consumers
48
+ * can override `instructions` to tune the prompt for their domain (medication
49
+ * vs grocery vs hardware), and `model` to pick a model — both forwarded to the
50
+ * consumer's parse function untouched.
51
+ */
52
+ interface ParseDef {
53
+ /** Field on entity.data to extract from. Defaults to the "name" field. */
54
+ source?: string;
55
+ /**
56
+ * Opaque model identifier passed to the consumer's parse function (e.g.
57
+ * "gemini-2.5-flash-lite", "gpt-4o-mini"). Defaults are decided by the
58
+ * consumer's parse function.
59
+ */
60
+ model?: string;
61
+ /**
62
+ * Override the default product-parse system prompt. Use this when your domain
63
+ * has specific extraction rules — e.g. "Sinhala medication strengths must
64
+ * preserve units (mg/g/ml) verbatim."
65
+ */
66
+ instructions?: string;
67
+ /** Cache TTL hint, e.g. "30d". Currently advisory; the cache always uses 90d. */
68
+ cacheTtl?: string;
69
+ }
70
+ interface ScorerDef {
71
+ kind: "cosine" | "trigram" | "phoneticEq" | "phoneExact" | "aliasHit" | "internalCodeExact" | "sizeUnitGate" | "brandGate";
72
+ weight?: number;
73
+ field?: string;
74
+ embedding?: string;
75
+ phonetic?: string;
76
+ value?: string;
77
+ unit?: string;
78
+ shortCircuit?: boolean;
79
+ matchBoost?: number;
80
+ mismatchFactor?: number;
81
+ latinOnlyPartial?: boolean;
82
+ }
83
+ type CosineScorer<E extends string> = {
84
+ kind: "cosine";
85
+ embedding: E;
86
+ weight: number;
87
+ };
88
+ type TrigramScorer<F extends string> = {
89
+ kind: "trigram";
90
+ field: F;
91
+ weight: number;
92
+ latinOnlyPartial?: boolean;
93
+ };
94
+ type PhoneticEqScorer<P extends string> = {
95
+ kind: "phoneticEq";
96
+ phonetic: P;
97
+ weight: number;
98
+ };
99
+ type PhoneExactScorer<F extends string> = {
100
+ kind: "phoneExact";
101
+ field: F;
102
+ weight: number;
103
+ };
104
+ type AliasHitScorer = {
105
+ kind: "aliasHit";
106
+ weight: number;
107
+ };
108
+ type InternalCodeExactScorer = {
109
+ kind: "internalCodeExact";
110
+ field: string;
111
+ shortCircuit?: boolean;
112
+ };
113
+ type SizeUnitGateScorer = {
114
+ kind: "sizeUnitGate";
115
+ value: string;
116
+ unit: string;
117
+ };
118
+ type BrandGateScorer = {
119
+ kind: "brandGate";
120
+ field: string;
121
+ matchBoost?: number;
122
+ mismatchFactor?: number;
123
+ };
124
+ /**
125
+ * The discriminated union the `scoring.channels` array accepts at the
126
+ * entity() call site. Generic over the entity's own field/embedding/
127
+ * phonetic key sets so e.g. `Scorers.cosine({ embedding: "name_emb" })`
128
+ * only compiles when "name_emb" is a key of the entity's embeddings.
129
+ */
130
+ type TypedScorer<F extends string, E extends string, P extends string> = CosineScorer<E> | TrigramScorer<F> | PhoneticEqScorer<P> | PhoneExactScorer<F> | AliasHitScorer | InternalCodeExactScorer | SizeUnitGateScorer | BrandGateScorer;
131
+ interface ScoringDef {
132
+ channels: ScorerDef[];
133
+ combiner?: "probabilistic-or" | "rrf" | "fellegi-sunter";
134
+ thresholds?: {
135
+ autoLink?: number;
136
+ suggest?: number;
137
+ };
138
+ }
139
+ interface EntityDef {
140
+ name?: string;
141
+ fields: Record<string, FieldDef>;
142
+ scopes: string[];
143
+ embeddings?: Record<string, EmbeddingDef>;
144
+ phonetic?: Record<string, PhoneticDef>;
145
+ scoring?: ScoringDef;
146
+ parse?: ParseDef;
147
+ }
148
+ interface CollectionTextFieldDef {
149
+ type: "text";
150
+ searchable?: boolean;
151
+ filterable?: boolean;
152
+ facet?: boolean | "range";
153
+ soft?: boolean;
154
+ path?: string;
155
+ weight?: number;
156
+ }
157
+ interface CollectionNumberFieldDef {
158
+ type: "number";
159
+ filterable?: boolean;
160
+ facet?: boolean | "range";
161
+ soft?: boolean;
162
+ path?: string;
163
+ /** NLQ maps implied budget words ("cheap", "premium") to percentile filters on this field. */
164
+ budget?: boolean;
165
+ }
166
+ interface CollectionBooleanFieldDef {
167
+ type: "boolean";
168
+ filterable?: boolean;
169
+ facet?: boolean;
170
+ soft?: boolean;
171
+ path?: string;
172
+ }
173
+ interface CollectionEnumFieldDef {
174
+ type: "enum";
175
+ values: readonly string[];
176
+ filterable?: boolean;
177
+ facet?: boolean;
178
+ soft?: boolean;
179
+ path?: string;
180
+ alsoMatch?: readonly string[];
181
+ }
182
+ interface CollectionArrayFieldDef {
183
+ type: "array";
184
+ itemType: "text" | "enum";
185
+ values?: readonly string[];
186
+ filterable?: boolean;
187
+ facet?: boolean;
188
+ soft?: boolean;
189
+ path?: string;
190
+ }
191
+ type CollectionFieldDef = CollectionTextFieldDef | CollectionNumberFieldDef | CollectionBooleanFieldDef | CollectionEnumFieldDef | CollectionArrayFieldDef;
192
+ interface CollectionEmbeddingDef {
193
+ source: string;
194
+ model: string;
195
+ dim: number;
196
+ taskType?: string;
197
+ }
198
+ type FtsChannel<F extends string> = {
199
+ kind: "fts";
200
+ fields: readonly F[];
201
+ weight: number;
202
+ };
203
+ type CosineChannel<E extends string> = {
204
+ kind: "cosine";
205
+ embedding: E;
206
+ weight: number;
207
+ };
208
+ type RecencyChannel<F extends string> = {
209
+ kind: "recency";
210
+ field: F;
211
+ halfLifeDays: number;
212
+ weight: number;
213
+ };
214
+ type SpacesChannel = {
215
+ kind: "spaces";
216
+ weight: number;
217
+ };
218
+ type TypedSearchChannel<F extends string, E extends string> = FtsChannel<F> | CosineChannel<E> | RecencyChannel<F | "updated_at"> | SpacesChannel;
219
+ interface SearchChannelDef {
220
+ kind: "fts" | "cosine" | "recency" | "spaces";
221
+ weight: number;
222
+ fields?: string[];
223
+ embedding?: string;
224
+ field?: string;
225
+ halfLifeDays?: number;
226
+ }
227
+ interface TextSpaceDef {
228
+ kind: "text";
229
+ source: string;
230
+ model: string;
231
+ dim: number;
232
+ taskType?: string;
233
+ }
234
+ interface ImageSpaceDef {
235
+ kind: "image";
236
+ source: string;
237
+ model: string;
238
+ dim: number;
239
+ taskType?: string;
240
+ }
241
+ interface NumberSpaceDef {
242
+ kind: "number";
243
+ field: string;
244
+ mode: "closer" | "max" | "min";
245
+ dims: number;
246
+ min: number;
247
+ max: number;
248
+ scale?: "linear" | "log";
249
+ }
250
+ interface RecencySpaceDef {
251
+ kind: "recency";
252
+ field: string;
253
+ halfLifeDays: number;
254
+ dims: number;
255
+ staleAfterDays?: number;
256
+ }
257
+ interface CategoricalSpaceDef {
258
+ kind: "categorical";
259
+ field: string;
260
+ values?: readonly string[];
261
+ dims: number;
262
+ }
263
+ type SpaceDef = TextSpaceDef | ImageSpaceDef | NumberSpaceDef | RecencySpaceDef | CategoricalSpaceDef;
264
+ interface CollectionSearchDef {
265
+ channels: SearchChannelDef[];
266
+ combiner?: "rrf";
267
+ defaultSpaceWeights?: Record<string, number>;
268
+ nlq?: {
269
+ instructions?: string;
270
+ semanticRewrite?: boolean;
271
+ enable?: boolean;
272
+ schema?: Record<string, unknown>;
273
+ model?: string;
274
+ };
275
+ }
276
+ interface StageContext {
277
+ data: Record<string, unknown>;
278
+ enriched: Record<string, unknown>;
279
+ }
280
+ interface StageDef {
281
+ name: string;
282
+ model?: string;
283
+ condition?: (ctx: StageContext) => boolean;
284
+ prompt: (ctx: StageContext) => string;
285
+ images?: (ctx: StageContext) => string[];
286
+ schema: (ctx: StageContext) => Record<string, unknown>;
287
+ }
288
+ interface PipelineDef {
289
+ stages: StageDef[];
290
+ }
291
+ interface ConnectorDef {
292
+ name: string;
293
+ kind: "shopify" | "woocommerce" | "jsonl";
294
+ options: Record<string, unknown>;
295
+ }
296
+ interface CollectionDef {
297
+ name?: string;
298
+ fields: Record<string, CollectionFieldDef>;
299
+ enrich?: PipelineDef;
300
+ sources?: ConnectorDef[];
301
+ embeddings?: Record<string, CollectionEmbeddingDef>;
302
+ spaces?: Record<string, SpaceDef>;
303
+ search?: CollectionSearchDef;
304
+ }
305
+ type SearchWeightsInput<S extends string = string> = {
306
+ fts?: number;
307
+ cosine?: number;
308
+ recency?: number;
309
+ spaces?: number | Partial<Record<S, number>>;
310
+ };
311
+ interface ProjectConfig {
312
+ entities?: EntityDef[];
313
+ collections?: CollectionDef[];
314
+ }
315
+
316
+ export type { AliasHitScorer, BrandGateScorer, CategoricalSpaceDef, CollectionArrayFieldDef, CollectionBooleanFieldDef, CollectionDef, CollectionEmbeddingDef, CollectionEnumFieldDef, CollectionFieldDef, CollectionNumberFieldDef, CollectionSearchDef, CollectionTextFieldDef, ConnectorDef, CosineChannel, CosineScorer, EmbeddingDef, EntityDef, FieldDef, FtsChannel, ImageSpaceDef, InternalCodeExactScorer, NumberSpaceDef, ParseDef, PhoneExactScorer, PhoneticDef, PhoneticEqScorer, PipelineDef, ProjectConfig, RecencyChannel, RecencySpaceDef, ScorerDef, ScoringDef, SearchChannelDef, SearchWeightsInput, SizeUnitGateScorer, SpaceDef, SpacesChannel, StageContext, StageDef, TextSpaceDef, TrigramScorer, TypedScorer, TypedSearchChannel };
@@ -0,0 +1,316 @@
1
+ export { MatchCandidate, MatchComponents, MatchResult, ResolvedMatch } from './schemas.js';
2
+ import 'zod';
3
+
4
+ interface FieldDef {
5
+ type: "text" | "number";
6
+ required?: boolean;
7
+ optional?: boolean;
8
+ maxLength?: number;
9
+ }
10
+ /**
11
+ * `source` is either:
12
+ * - a field name on the entity data (e.g. "name")
13
+ * - a template expression with $-prefixed field refs (e.g. "$brand $item_canonical")
14
+ *
15
+ * Functions aren't supported — they can't survive HTTP transport.
16
+ *
17
+ * `model` is an opaque identifier (e.g. "gemini-embedding-001", "text-embedding-3-small",
18
+ * "nomic-embed-text"). @samesake/server passes it through to the consumer's `embed`
19
+ * function untouched; the consumer's embedder decides what to do with it. The matcher
20
+ * uses it to namespace the embedding cache.
21
+ *
22
+ * `dim` is the vector dimension. It IS load-bearing for samesake: the per-project
23
+ * entity_<kind>_match table is created with `vector(<dim>)` columns.
24
+ *
25
+ * `taskType` is opaque metadata that @samesake/server forwards to the consumer's
26
+ * embedder. Useful for provider-specific hints like Gemini's "SEMANTIC_SIMILARITY"
27
+ * vs "RETRIEVAL_QUERY"/"RETRIEVAL_DOCUMENT".
28
+ */
29
+ interface EmbeddingDef {
30
+ source: string;
31
+ model: string;
32
+ dim: number;
33
+ taskType?: string;
34
+ }
35
+ interface PhoneticDef {
36
+ source: string;
37
+ algorithm: "indic-soundex" | "soundex" | "metaphone";
38
+ }
39
+ /**
40
+ * Marks an entity as "parse-shape" — the matcher will call the consumer-provided
41
+ * `parse` function on createMatcher to extract structured product/asset fields
42
+ * (brand, item_canonical, size_value, size_unit, variant, internal_code, ...)
43
+ * from the entity's source text. Those parsed fields then drive gated matching:
44
+ * a brand mismatch downweights a candidate by 5x; a size mismatch drops it.
45
+ *
46
+ * The parse OUTPUT shape (ParsedProductSchema) is owned by @samesake/server
47
+ * because the SQL match function generation depends on its columns. Consumers
48
+ * can override `instructions` to tune the prompt for their domain (medication
49
+ * vs grocery vs hardware), and `model` to pick a model — both forwarded to the
50
+ * consumer's parse function untouched.
51
+ */
52
+ interface ParseDef {
53
+ /** Field on entity.data to extract from. Defaults to the "name" field. */
54
+ source?: string;
55
+ /**
56
+ * Opaque model identifier passed to the consumer's parse function (e.g.
57
+ * "gemini-2.5-flash-lite", "gpt-4o-mini"). Defaults are decided by the
58
+ * consumer's parse function.
59
+ */
60
+ model?: string;
61
+ /**
62
+ * Override the default product-parse system prompt. Use this when your domain
63
+ * has specific extraction rules — e.g. "Sinhala medication strengths must
64
+ * preserve units (mg/g/ml) verbatim."
65
+ */
66
+ instructions?: string;
67
+ /** Cache TTL hint, e.g. "30d". Currently advisory; the cache always uses 90d. */
68
+ cacheTtl?: string;
69
+ }
70
+ interface ScorerDef {
71
+ kind: "cosine" | "trigram" | "phoneticEq" | "phoneExact" | "aliasHit" | "internalCodeExact" | "sizeUnitGate" | "brandGate";
72
+ weight?: number;
73
+ field?: string;
74
+ embedding?: string;
75
+ phonetic?: string;
76
+ value?: string;
77
+ unit?: string;
78
+ shortCircuit?: boolean;
79
+ matchBoost?: number;
80
+ mismatchFactor?: number;
81
+ latinOnlyPartial?: boolean;
82
+ }
83
+ type CosineScorer<E extends string> = {
84
+ kind: "cosine";
85
+ embedding: E;
86
+ weight: number;
87
+ };
88
+ type TrigramScorer<F extends string> = {
89
+ kind: "trigram";
90
+ field: F;
91
+ weight: number;
92
+ latinOnlyPartial?: boolean;
93
+ };
94
+ type PhoneticEqScorer<P extends string> = {
95
+ kind: "phoneticEq";
96
+ phonetic: P;
97
+ weight: number;
98
+ };
99
+ type PhoneExactScorer<F extends string> = {
100
+ kind: "phoneExact";
101
+ field: F;
102
+ weight: number;
103
+ };
104
+ type AliasHitScorer = {
105
+ kind: "aliasHit";
106
+ weight: number;
107
+ };
108
+ type InternalCodeExactScorer = {
109
+ kind: "internalCodeExact";
110
+ field: string;
111
+ shortCircuit?: boolean;
112
+ };
113
+ type SizeUnitGateScorer = {
114
+ kind: "sizeUnitGate";
115
+ value: string;
116
+ unit: string;
117
+ };
118
+ type BrandGateScorer = {
119
+ kind: "brandGate";
120
+ field: string;
121
+ matchBoost?: number;
122
+ mismatchFactor?: number;
123
+ };
124
+ /**
125
+ * The discriminated union the `scoring.channels` array accepts at the
126
+ * entity() call site. Generic over the entity's own field/embedding/
127
+ * phonetic key sets so e.g. `Scorers.cosine({ embedding: "name_emb" })`
128
+ * only compiles when "name_emb" is a key of the entity's embeddings.
129
+ */
130
+ type TypedScorer<F extends string, E extends string, P extends string> = CosineScorer<E> | TrigramScorer<F> | PhoneticEqScorer<P> | PhoneExactScorer<F> | AliasHitScorer | InternalCodeExactScorer | SizeUnitGateScorer | BrandGateScorer;
131
+ interface ScoringDef {
132
+ channels: ScorerDef[];
133
+ combiner?: "probabilistic-or" | "rrf" | "fellegi-sunter";
134
+ thresholds?: {
135
+ autoLink?: number;
136
+ suggest?: number;
137
+ };
138
+ }
139
+ interface EntityDef {
140
+ name?: string;
141
+ fields: Record<string, FieldDef>;
142
+ scopes: string[];
143
+ embeddings?: Record<string, EmbeddingDef>;
144
+ phonetic?: Record<string, PhoneticDef>;
145
+ scoring?: ScoringDef;
146
+ parse?: ParseDef;
147
+ }
148
+ interface CollectionTextFieldDef {
149
+ type: "text";
150
+ searchable?: boolean;
151
+ filterable?: boolean;
152
+ facet?: boolean | "range";
153
+ soft?: boolean;
154
+ path?: string;
155
+ weight?: number;
156
+ }
157
+ interface CollectionNumberFieldDef {
158
+ type: "number";
159
+ filterable?: boolean;
160
+ facet?: boolean | "range";
161
+ soft?: boolean;
162
+ path?: string;
163
+ /** NLQ maps implied budget words ("cheap", "premium") to percentile filters on this field. */
164
+ budget?: boolean;
165
+ }
166
+ interface CollectionBooleanFieldDef {
167
+ type: "boolean";
168
+ filterable?: boolean;
169
+ facet?: boolean;
170
+ soft?: boolean;
171
+ path?: string;
172
+ }
173
+ interface CollectionEnumFieldDef {
174
+ type: "enum";
175
+ values: readonly string[];
176
+ filterable?: boolean;
177
+ facet?: boolean;
178
+ soft?: boolean;
179
+ path?: string;
180
+ alsoMatch?: readonly string[];
181
+ }
182
+ interface CollectionArrayFieldDef {
183
+ type: "array";
184
+ itemType: "text" | "enum";
185
+ values?: readonly string[];
186
+ filterable?: boolean;
187
+ facet?: boolean;
188
+ soft?: boolean;
189
+ path?: string;
190
+ }
191
+ type CollectionFieldDef = CollectionTextFieldDef | CollectionNumberFieldDef | CollectionBooleanFieldDef | CollectionEnumFieldDef | CollectionArrayFieldDef;
192
+ interface CollectionEmbeddingDef {
193
+ source: string;
194
+ model: string;
195
+ dim: number;
196
+ taskType?: string;
197
+ }
198
+ type FtsChannel<F extends string> = {
199
+ kind: "fts";
200
+ fields: readonly F[];
201
+ weight: number;
202
+ };
203
+ type CosineChannel<E extends string> = {
204
+ kind: "cosine";
205
+ embedding: E;
206
+ weight: number;
207
+ };
208
+ type RecencyChannel<F extends string> = {
209
+ kind: "recency";
210
+ field: F;
211
+ halfLifeDays: number;
212
+ weight: number;
213
+ };
214
+ type SpacesChannel = {
215
+ kind: "spaces";
216
+ weight: number;
217
+ };
218
+ type TypedSearchChannel<F extends string, E extends string> = FtsChannel<F> | CosineChannel<E> | RecencyChannel<F | "updated_at"> | SpacesChannel;
219
+ interface SearchChannelDef {
220
+ kind: "fts" | "cosine" | "recency" | "spaces";
221
+ weight: number;
222
+ fields?: string[];
223
+ embedding?: string;
224
+ field?: string;
225
+ halfLifeDays?: number;
226
+ }
227
+ interface TextSpaceDef {
228
+ kind: "text";
229
+ source: string;
230
+ model: string;
231
+ dim: number;
232
+ taskType?: string;
233
+ }
234
+ interface ImageSpaceDef {
235
+ kind: "image";
236
+ source: string;
237
+ model: string;
238
+ dim: number;
239
+ taskType?: string;
240
+ }
241
+ interface NumberSpaceDef {
242
+ kind: "number";
243
+ field: string;
244
+ mode: "closer" | "max" | "min";
245
+ dims: number;
246
+ min: number;
247
+ max: number;
248
+ scale?: "linear" | "log";
249
+ }
250
+ interface RecencySpaceDef {
251
+ kind: "recency";
252
+ field: string;
253
+ halfLifeDays: number;
254
+ dims: number;
255
+ staleAfterDays?: number;
256
+ }
257
+ interface CategoricalSpaceDef {
258
+ kind: "categorical";
259
+ field: string;
260
+ values?: readonly string[];
261
+ dims: number;
262
+ }
263
+ type SpaceDef = TextSpaceDef | ImageSpaceDef | NumberSpaceDef | RecencySpaceDef | CategoricalSpaceDef;
264
+ interface CollectionSearchDef {
265
+ channels: SearchChannelDef[];
266
+ combiner?: "rrf";
267
+ defaultSpaceWeights?: Record<string, number>;
268
+ nlq?: {
269
+ instructions?: string;
270
+ semanticRewrite?: boolean;
271
+ enable?: boolean;
272
+ schema?: Record<string, unknown>;
273
+ model?: string;
274
+ };
275
+ }
276
+ interface StageContext {
277
+ data: Record<string, unknown>;
278
+ enriched: Record<string, unknown>;
279
+ }
280
+ interface StageDef {
281
+ name: string;
282
+ model?: string;
283
+ condition?: (ctx: StageContext) => boolean;
284
+ prompt: (ctx: StageContext) => string;
285
+ images?: (ctx: StageContext) => string[];
286
+ schema: (ctx: StageContext) => Record<string, unknown>;
287
+ }
288
+ interface PipelineDef {
289
+ stages: StageDef[];
290
+ }
291
+ interface ConnectorDef {
292
+ name: string;
293
+ kind: "shopify" | "woocommerce" | "jsonl";
294
+ options: Record<string, unknown>;
295
+ }
296
+ interface CollectionDef {
297
+ name?: string;
298
+ fields: Record<string, CollectionFieldDef>;
299
+ enrich?: PipelineDef;
300
+ sources?: ConnectorDef[];
301
+ embeddings?: Record<string, CollectionEmbeddingDef>;
302
+ spaces?: Record<string, SpaceDef>;
303
+ search?: CollectionSearchDef;
304
+ }
305
+ type SearchWeightsInput<S extends string = string> = {
306
+ fts?: number;
307
+ cosine?: number;
308
+ recency?: number;
309
+ spaces?: number | Partial<Record<S, number>>;
310
+ };
311
+ interface ProjectConfig {
312
+ entities?: EntityDef[];
313
+ collections?: CollectionDef[];
314
+ }
315
+
316
+ export type { AliasHitScorer, BrandGateScorer, CategoricalSpaceDef, CollectionArrayFieldDef, CollectionBooleanFieldDef, CollectionDef, CollectionEmbeddingDef, CollectionEnumFieldDef, CollectionFieldDef, CollectionNumberFieldDef, CollectionSearchDef, CollectionTextFieldDef, ConnectorDef, CosineChannel, CosineScorer, EmbeddingDef, EntityDef, FieldDef, FtsChannel, ImageSpaceDef, InternalCodeExactScorer, NumberSpaceDef, ParseDef, PhoneExactScorer, PhoneticDef, PhoneticEqScorer, PipelineDef, ProjectConfig, RecencyChannel, RecencySpaceDef, ScorerDef, ScoringDef, SearchChannelDef, SearchWeightsInput, SizeUnitGateScorer, SpaceDef, SpacesChannel, StageContext, StageDef, TextSpaceDef, TrigramScorer, TypedScorer, TypedSearchChannel };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ import "./chunk-6F4PWJZI.js";
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@samesake/core",
3
+ "version": "1.0.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/asyncdotengineering/samesake"
7
+ },
8
+ "description": "Config-as-code DSL for commerce search and entity resolution. Declare collection() and entity() with compile-time validation; @samesake/server runs hybrid search and multi-channel matching on PostgreSQL + pgvector.",
9
+ "type": "module",
10
+ "license": "MIT",
11
+ "main": "./dist/index.cjs",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.cts",
22
+ "default": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "./types": {
26
+ "import": {
27
+ "types": "./dist/types.d.ts",
28
+ "default": "./dist/types.js"
29
+ },
30
+ "require": {
31
+ "types": "./dist/types.d.cts",
32
+ "default": "./dist/types.cjs"
33
+ }
34
+ },
35
+ "./schemas": {
36
+ "import": {
37
+ "types": "./dist/schemas.d.ts",
38
+ "default": "./dist/schemas.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/schemas.d.cts",
42
+ "default": "./dist/schemas.cjs"
43
+ }
44
+ }
45
+ },
46
+ "files": ["dist", "README.md", "LICENSE"],
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "scripts": {
51
+ "build": "tsup"
52
+ },
53
+ "keywords": [
54
+ "entity-resolution",
55
+ "record-linkage",
56
+ "fuzzy-matching",
57
+ "deduplication",
58
+ "pgvector",
59
+ "drizzle",
60
+ "typescript"
61
+ ],
62
+ "dependencies": {
63
+ "zod": "^4.4.3"
64
+ },
65
+ "devDependencies": {
66
+ "tsup": "^8.5.1"
67
+ }
68
+ }