@rudra-js/core 0.1.0 → 0.2.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.
- package/README.md +185 -3
- package/dist/component-generator.d.ts +11 -0
- package/dist/component-generator.d.ts.map +1 -1
- package/dist/component-generator.js +14 -6
- package/dist/component-generator.js.map +1 -1
- package/dist/component-spec.d.ts +7 -7
- package/dist/component-spec.js +7 -7
- package/dist/fit-to-shopper.js +1 -1
- package/dist/fit-to-shopper.js.map +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/reconciliation.d.ts.map +1 -1
- package/dist/reconciliation.js +20 -8
- package/dist/reconciliation.js.map +1 -1
- package/dist/signal-digest.d.ts.map +1 -1
- package/dist/signal-digest.js +10 -7
- package/dist/signal-digest.js.map +1 -1
- package/dist/spec-cache.d.ts +6 -5
- package/dist/spec-cache.d.ts.map +1 -1
- package/dist/spec-cache.js +7 -0
- package/dist/spec-cache.js.map +1 -1
- package/dist/tracking-input.d.ts +2 -0
- package/dist/tracking-input.d.ts.map +1 -1
- package/dist/tracking-input.js +10 -2
- package/dist/tracking-input.js.map +1 -1
- package/package.json +3 -3
- package/src/component-generator.ts +29 -12
- package/src/component-spec.ts +7 -7
- package/src/fit-to-shopper.ts +1 -1
- package/src/index.ts +2 -6
- package/src/reconciliation.ts +21 -8
- package/src/signal-digest.ts +10 -7
- package/src/spec-cache.ts +15 -5
- package/src/tracking-input.ts +10 -2
package/src/signal-digest.ts
CHANGED
|
@@ -230,14 +230,17 @@ function mergeViewsBySku(views: ViewSignal[]): MergedView[] {
|
|
|
230
230
|
|
|
231
231
|
/** The most-viewed few, as the digest reports them. */
|
|
232
232
|
function mostViewedProducts(views: ViewSignal[]): ViewedProduct[] {
|
|
233
|
-
|
|
233
|
+
const top = mergeViewsBySku(views)
|
|
234
234
|
.toSorted((left, right) => right.views - left.views)
|
|
235
|
-
.slice(0, DIGEST_LIMITS.viewed)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
235
|
+
.slice(0, DIGEST_LIMITS.viewed);
|
|
236
|
+
|
|
237
|
+
const products: ViewedProduct[] = [];
|
|
238
|
+
for (const merged of top) {
|
|
239
|
+
const product: ViewedProduct = { sku: merged.sku, views: merged.views };
|
|
240
|
+
if (merged.dwellMs !== undefined) product.dwellMs = merged.dwellMs;
|
|
241
|
+
products.push(product);
|
|
242
|
+
}
|
|
243
|
+
return products;
|
|
241
244
|
}
|
|
242
245
|
|
|
243
246
|
/** The open-vocabulary long tail, reduced to "which kinds, and how often". */
|
package/src/spec-cache.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { SPEC_VERSION, type GeneratedSpec } from './component-spec.js';
|
|
3
|
+
import { SYSTEM_PROMPT } from './model-prompt.js';
|
|
3
4
|
import type { SignalDigest } from './signal-digest.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -15,11 +16,6 @@ import type { SignalDigest } from './signal-digest.js';
|
|
|
15
16
|
* instance count.
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
|
-
/**
|
|
19
|
-
* Asynchronous on purpose. A synchronous `get` would look simpler and would
|
|
20
|
-
* make the shared store the docs recommend impossible to write, since no Redis
|
|
21
|
-
* or Memcached client can return a value without awaiting.
|
|
22
|
-
*/
|
|
23
19
|
/**
|
|
24
20
|
* A stored generation, with the moment it was produced.
|
|
25
21
|
*
|
|
@@ -33,9 +29,15 @@ export interface CachedSpec {
|
|
|
33
29
|
generatedAt: number;
|
|
34
30
|
}
|
|
35
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Asynchronous on purpose. A synchronous `get` would look simpler and would
|
|
34
|
+
* make the shared store the docs recommend impossible to write, since no Redis
|
|
35
|
+
* or Memcached client can return a value without awaiting.
|
|
36
|
+
*/
|
|
36
37
|
export interface SpecCache {
|
|
37
38
|
get(key: string): Promise<CachedSpec | undefined>;
|
|
38
39
|
set(key: string, cached: CachedSpec): Promise<void>;
|
|
40
|
+
delete?(key: string): Promise<void>;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
export interface MemorySpecCacheOptions {
|
|
@@ -115,6 +117,10 @@ export function createMemorySpecCache(options: MemorySpecCacheOptions = {}): Spe
|
|
|
115
117
|
entries.delete(oldest.value);
|
|
116
118
|
}
|
|
117
119
|
},
|
|
120
|
+
|
|
121
|
+
async delete(key) {
|
|
122
|
+
entries.delete(key);
|
|
123
|
+
},
|
|
118
124
|
};
|
|
119
125
|
}
|
|
120
126
|
|
|
@@ -148,6 +154,8 @@ function canonicalise(value: unknown): string {
|
|
|
148
154
|
return `{${entries.map(([name, fieldValue]) => `${JSON.stringify(name)}:${canonicalise(fieldValue)}`).join(',')}}`;
|
|
149
155
|
}
|
|
150
156
|
|
|
157
|
+
const PROMPT_FINGERPRINT = createHash('sha256').update(SYSTEM_PROMPT).digest('hex').slice(0, 16);
|
|
158
|
+
|
|
151
159
|
/**
|
|
152
160
|
* Derives the cache key.
|
|
153
161
|
*
|
|
@@ -182,6 +190,7 @@ export function specCacheKey(
|
|
|
182
190
|
// The spec's own version, so a shape change cannot read entries written by
|
|
183
191
|
// the previous shape out of a shared store that outlives a deploy.
|
|
184
192
|
specVersion: SPEC_VERSION,
|
|
193
|
+
prompt: PROMPT_FINGERPRINT,
|
|
185
194
|
provider: providerId,
|
|
186
195
|
digest,
|
|
187
196
|
candidates: candidateSkus.toSorted(),
|
|
@@ -201,6 +210,7 @@ export function cohortCacheKey(
|
|
|
201
210
|
): string {
|
|
202
211
|
const material = canonicalise({
|
|
203
212
|
specVersion: SPEC_VERSION,
|
|
213
|
+
prompt: PROMPT_FINGERPRINT,
|
|
204
214
|
provider: providerId,
|
|
205
215
|
segment: digest.segment ?? null,
|
|
206
216
|
surface: digest.surface,
|
package/src/tracking-input.ts
CHANGED
|
@@ -42,6 +42,8 @@ export const FIELD_LIMITS = {
|
|
|
42
42
|
candidates: 200,
|
|
43
43
|
productsPerBundle: 5,
|
|
44
44
|
bundles: 20,
|
|
45
|
+
localeTag: 35,
|
|
46
|
+
maxItems: 12,
|
|
45
47
|
} as const;
|
|
46
48
|
|
|
47
49
|
/** Assigning this as an object key mutates the prototype instead of the object. */
|
|
@@ -179,9 +181,15 @@ export const renderContextSchema = z.strictObject({
|
|
|
179
181
|
currentSku: optionalIdentifier(),
|
|
180
182
|
currentCategory: optionalIdentifier(),
|
|
181
183
|
searchQuery: z.string().max(FIELD_LIMITS.searchQuery).optional(),
|
|
182
|
-
|
|
184
|
+
// One language tag, not the Accept-Language header it is often copied from:
|
|
185
|
+
// the locale is part of the cohort cache key, so a list makes its own cohort.
|
|
186
|
+
locale: z
|
|
187
|
+
.string()
|
|
188
|
+
.max(FIELD_LIMITS.localeTag)
|
|
189
|
+
.regex(/^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*$/, 'expected one language tag, such as en-US')
|
|
190
|
+
.default('en-US'),
|
|
183
191
|
/** Upper bound on products across the whole generated component. */
|
|
184
|
-
maxItems: z.number().int().min(1).max(
|
|
192
|
+
maxItems: z.number().int().min(1).max(FIELD_LIMITS.maxItems).default(4),
|
|
185
193
|
});
|
|
186
194
|
export type RenderContext = z.infer<typeof renderContextSchema>;
|
|
187
195
|
|