@hraness/oh 0.2.7 → 0.3.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.
Files changed (55) hide show
  1. package/README.md +116 -12
  2. package/dist/canonical.d.ts.map +1 -1
  3. package/dist/cli.d.ts +1 -1
  4. package/dist/cli.js +91 -19
  5. package/dist/cloudflare-embedding.d.ts +104 -0
  6. package/dist/cloudflare-embedding.d.ts.map +1 -0
  7. package/dist/graph.d.ts.map +1 -1
  8. package/dist/index.js +90 -18
  9. package/dist/libsql-semantic.d.ts +111 -0
  10. package/dist/libsql-semantic.d.ts.map +1 -0
  11. package/dist/libsql.js +105 -18
  12. package/dist/memory-page.d.ts +2 -0
  13. package/dist/memory-page.d.ts.map +1 -0
  14. package/dist/memory-page.js +725 -0
  15. package/dist/memory-pages.d.ts +76 -0
  16. package/dist/memory-pages.d.ts.map +1 -0
  17. package/dist/memory.d.ts +1 -0
  18. package/dist/memory.d.ts.map +1 -1
  19. package/dist/memory.js +478 -18
  20. package/dist/projection-public.js +105 -18
  21. package/dist/projection-suss.js +105 -18
  22. package/dist/sdk.js +90 -18
  23. package/dist/semantic-cloud.d.ts +3 -0
  24. package/dist/semantic-cloud.d.ts.map +1 -0
  25. package/dist/semantic-cloud.js +1843 -0
  26. package/dist/semantic.d.ts.map +1 -1
  27. package/dist/semantic.js +104 -21
  28. package/dist/sqlite/index.js +90 -18
  29. package/dist/store.js +105 -18
  30. package/dist/sync.js +90 -18
  31. package/package.json +10 -2
  32. package/skills/oh/SKILL.md +28 -2
  33. package/spec/README.md +11 -3
  34. package/spec/manifest.json +9 -1
  35. package/spec/v1/cloudflare-embedding-profile.json +13 -0
  36. package/spec/v1/cloudflare-embedding-renderer.json +8 -0
  37. package/spec/v1/memory-page.md +153 -0
  38. package/spec/v1/memory-page.schema.json +154 -0
  39. package/spec/v1/memory.md +18 -0
  40. package/spec/v1/migration.md +13 -0
  41. package/spec/v1/semantic-cloud.md +87 -0
  42. package/src/canonical.ts +28 -13
  43. package/src/cli.ts +1 -1
  44. package/src/cloudflare-embedding.test.ts +306 -0
  45. package/src/cloudflare-embedding.ts +385 -0
  46. package/src/contracts.test.ts +20 -0
  47. package/src/graph.ts +63 -6
  48. package/src/libsql-semantic.test.ts +478 -0
  49. package/src/libsql-semantic.ts +1117 -0
  50. package/src/memory-page.ts +1 -0
  51. package/src/memory-pages.test.ts +277 -0
  52. package/src/memory-pages.ts +440 -0
  53. package/src/memory.ts +2 -0
  54. package/src/semantic-cloud.ts +2 -0
  55. package/src/semantic.ts +14 -3
@@ -0,0 +1,440 @@
1
+ import {
2
+ boundedText,
3
+ canonicalJson,
4
+ isPlainRecord,
5
+ orderedUnique,
6
+ parseCanonicalInstantV1,
7
+ parseSha256Hex,
8
+ safeCode,
9
+ utf8ByteLength,
10
+ type JsonValue,
11
+ type Sha256Hex,
12
+ } from "./canonical";
13
+ import type { OhRecordCodec } from "./contract";
14
+ import {
15
+ createKnowledgeGraphRecordV1,
16
+ OH_GRAPH_LIMITS_V1,
17
+ parseKnowledgeGraphRecordV1,
18
+ type KnowledgeGraphRecordV1,
19
+ } from "./graph";
20
+
21
+ export const OH_MEMORY_PAGE_FORMAT_V1 = "oh.memory-page.v1" as const;
22
+ export const OH_MEMORY_PAGE_MARKDOWN_EXTENSION_V1 = ".oh.md" as const;
23
+
24
+ export const OH_MEMORY_PAGE_LIMITS_V1 = Object.freeze({
25
+ bodyBytes: 512 * 1024,
26
+ fileBytes: 1024 * 1024,
27
+ frontmatterLines: 18 + OH_GRAPH_LIMITS_V1.dependenciesPerRecord + 5 * 128,
28
+ languageBytes: 255,
29
+ sourceTitleBytes: 1024,
30
+ sourceUrlBytes: 4096,
31
+ sources: 128,
32
+ summaryBytes: 8192,
33
+ titleBytes: 512,
34
+ valueBytes: 768 * 1024,
35
+ });
36
+
37
+ export type OhMemoryPageSourceV1 = Readonly<{
38
+ contentSha256: Sha256Hex;
39
+ observedAt: string;
40
+ title: string;
41
+ url: string;
42
+ v: 1;
43
+ }>;
44
+
45
+ /**
46
+ * A pointer to a host-owned attestation receipt. Parsing confirms the receipt
47
+ * identity, not the receipt's existence, signature, or authorization.
48
+ */
49
+ export type OhMemoryPageProvenanceV1 = Readonly<{
50
+ actorId: string;
51
+ attestationSha256: Sha256Hex;
52
+ attestedAt: string;
53
+ kind: "host-attested";
54
+ v: 1;
55
+ }>;
56
+
57
+ export type OhMemoryPageValueV1 = Readonly<{
58
+ body: string;
59
+ createdAt: string;
60
+ format: typeof OH_MEMORY_PAGE_FORMAT_V1;
61
+ language: string | null;
62
+ provenance: OhMemoryPageProvenanceV1;
63
+ sources: readonly OhMemoryPageSourceV1[];
64
+ summary: string;
65
+ title: string;
66
+ updatedAt: string;
67
+ v: 1;
68
+ }>;
69
+
70
+ export type OhMemoryPageRecordV1 = Omit<KnowledgeGraphRecordV1, "kind" | "value"> & Readonly<{
71
+ kind: "edition";
72
+ value: OhMemoryPageValueV1;
73
+ }>;
74
+
75
+ export type OhMemoryPageRecordInputV1 = Readonly<{
76
+ dependencies: readonly string[];
77
+ key: string;
78
+ value: OhMemoryPageValueV1;
79
+ }>;
80
+
81
+ function singleLineText(value: unknown, maximumBytes: number): string | null {
82
+ const parsed = boundedText(value, maximumBytes);
83
+ return parsed !== null && !/[\r\n\u0085\u2028\u2029]/u.test(parsed) ? parsed : null;
84
+ }
85
+
86
+ function exactDataRecord(value: unknown, keys: readonly string[]): Record<string, unknown> | null {
87
+ try {
88
+ if (!isPlainRecord(value)) return null;
89
+ const ownKeys = Reflect.ownKeys(value);
90
+ if (ownKeys.length !== keys.length || ownKeys.some((key) => typeof key !== "string")
91
+ || keys.some((key) => !ownKeys.includes(key))) return null;
92
+ const detached: Record<string, unknown> = {};
93
+ for (const key of keys) {
94
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
95
+ if (descriptor === undefined || !descriptor.enumerable
96
+ || descriptor.get !== undefined || descriptor.set !== undefined) return null;
97
+ detached[key] = descriptor.value;
98
+ }
99
+ return detached;
100
+ } catch {
101
+ return null;
102
+ }
103
+ }
104
+
105
+ function exactDataArray(value: unknown, maximumLength: number): readonly unknown[] | null {
106
+ try {
107
+ if (!Array.isArray(value)) return null;
108
+ const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
109
+ const length = lengthDescriptor?.value;
110
+ if (typeof length !== "number" || !Number.isSafeInteger(length)
111
+ || length < 0 || length > maximumLength) return null;
112
+ const ownKeys = Reflect.ownKeys(value);
113
+ if (ownKeys.length !== length + 1 || ownKeys.some((key) => typeof key !== "string")
114
+ || !ownKeys.includes("length")) return null;
115
+ const detached: unknown[] = [];
116
+ for (let index = 0; index < length; index += 1) {
117
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
118
+ if (descriptor === undefined || !descriptor.enumerable
119
+ || descriptor.get !== undefined || descriptor.set !== undefined) return null;
120
+ detached.push(descriptor.value);
121
+ }
122
+ return detached;
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+
128
+ function parseLanguage(value: unknown): string | null | undefined {
129
+ if (value === null) return null;
130
+ return typeof value === "string" && utf8ByteLength(value) <= OH_MEMORY_PAGE_LIMITS_V1.languageBytes
131
+ && /^(?:und|[a-z]{2,3}(?:-[a-z0-9]{2,8})*)$/u.test(value)
132
+ ? value
133
+ : undefined;
134
+ }
135
+
136
+ function parseCanonicalSourceUrl(value: unknown): string | null {
137
+ if (typeof value !== "string" || value.normalize("NFC") !== value
138
+ || utf8ByteLength(value) > OH_MEMORY_PAGE_LIMITS_V1.sourceUrlBytes) return null;
139
+ try {
140
+ const url = new URL(value);
141
+ if ((url.protocol !== "https:" && url.protocol !== "http:")
142
+ || url.username !== "" || url.password !== "" || url.href !== value) return null;
143
+ for (let index = value.indexOf("%"); index >= 0; index = value.indexOf("%", index + 3)) {
144
+ const encoded = value.slice(index + 1, index + 3);
145
+ if (!/^[0-9A-F]{2}$/u.test(encoded)) return null;
146
+ const decoded = String.fromCharCode(Number.parseInt(encoded, 16));
147
+ if (/^[A-Za-z0-9._~-]$/u.test(decoded)) return null;
148
+ }
149
+ return value;
150
+ } catch {
151
+ return null;
152
+ }
153
+ }
154
+
155
+ function parseSource(value: unknown): OhMemoryPageSourceV1 | null {
156
+ const source = exactDataRecord(value, ["contentSha256", "observedAt", "title", "url", "v"]);
157
+ if (source === null || source.v !== 1) return null;
158
+ const contentSha256 = parseSha256Hex(source.contentSha256);
159
+ const observedAt = parseCanonicalInstantV1(source.observedAt);
160
+ const title = singleLineText(source.title, OH_MEMORY_PAGE_LIMITS_V1.sourceTitleBytes);
161
+ const url = parseCanonicalSourceUrl(source.url);
162
+ return contentSha256 !== null && observedAt !== null && title !== null && url !== null
163
+ ? { contentSha256, observedAt, title, url, v: 1 }
164
+ : null;
165
+ }
166
+
167
+ function parseProvenance(value: unknown): OhMemoryPageProvenanceV1 | null {
168
+ const provenance = exactDataRecord(value,
169
+ ["actorId", "attestationSha256", "attestedAt", "kind", "v"]);
170
+ if (provenance === null || provenance.kind !== "host-attested" || provenance.v !== 1) return null;
171
+ const actorId = safeCode(provenance.actorId);
172
+ const attestationSha256 = parseSha256Hex(provenance.attestationSha256);
173
+ const attestedAt = parseCanonicalInstantV1(provenance.attestedAt);
174
+ return actorId !== null && attestationSha256 !== null && attestedAt !== null
175
+ ? { actorId, attestationSha256, attestedAt, kind: "host-attested", v: 1 }
176
+ : null;
177
+ }
178
+
179
+ /** Parses only the exact, bounded, model-neutral V1 page value. */
180
+ export function parseOhMemoryPageValueV1(value: unknown): OhMemoryPageValueV1 | null {
181
+ const page = exactDataRecord(value,
182
+ ["body", "createdAt", "format", "language", "provenance", "sources", "summary", "title",
183
+ "updatedAt", "v"]);
184
+ if (page === null || page.format !== OH_MEMORY_PAGE_FORMAT_V1 || page.v !== 1) return null;
185
+ const sourceValues = exactDataArray(page.sources, OH_MEMORY_PAGE_LIMITS_V1.sources);
186
+ if (sourceValues === null) return null;
187
+
188
+ const body = boundedText(page.body, OH_MEMORY_PAGE_LIMITS_V1.bodyBytes);
189
+ const createdAt = parseCanonicalInstantV1(page.createdAt);
190
+ const language = parseLanguage(page.language);
191
+ const provenance = parseProvenance(page.provenance);
192
+ const sources = sourceValues.map(parseSource);
193
+ const summary = boundedText(page.summary, OH_MEMORY_PAGE_LIMITS_V1.summaryBytes);
194
+ const title = singleLineText(page.title, OH_MEMORY_PAGE_LIMITS_V1.titleBytes);
195
+ const updatedAt = parseCanonicalInstantV1(page.updatedAt);
196
+ if (body === null || createdAt === null || language === undefined || provenance === null
197
+ || sources.some((source) => source === null) || summary === null || title === null || updatedAt === null) {
198
+ return null;
199
+ }
200
+ const parsedSources = sources as OhMemoryPageSourceV1[];
201
+ if (!orderedUnique(parsedSources, (source) => source.url)
202
+ || Date.parse(createdAt) > Date.parse(updatedAt)
203
+ || Date.parse(updatedAt) > Date.parse(provenance.attestedAt)
204
+ || parsedSources.some((source) => Date.parse(source.observedAt) > Date.parse(updatedAt))) return null;
205
+
206
+ const parsed: OhMemoryPageValueV1 = {
207
+ body,
208
+ createdAt,
209
+ format: OH_MEMORY_PAGE_FORMAT_V1,
210
+ language,
211
+ provenance,
212
+ sources: parsedSources,
213
+ summary,
214
+ title,
215
+ updatedAt,
216
+ v: 1,
217
+ };
218
+ return utf8ByteLength(canonicalJson(parsed)) <= OH_MEMORY_PAGE_LIMITS_V1.valueBytes ? parsed : null;
219
+ }
220
+
221
+ export function createOhMemoryPageValueV1(value: OhMemoryPageValueV1): OhMemoryPageValueV1 {
222
+ const parsed = parseOhMemoryPageValueV1(value);
223
+ if (parsed === null) throw new TypeError("Invalid Oh memory page value.");
224
+ return parsed;
225
+ }
226
+
227
+ /** Creates an ordinary content-addressed Oh `edition` record. */
228
+ export function createOhMemoryPageRecordV1(input: OhMemoryPageRecordInputV1): OhMemoryPageRecordV1 {
229
+ const parsedInput = exactDataRecord(input, ["dependencies", "key", "value"]);
230
+ if (parsedInput === null) {
231
+ throw new TypeError("Invalid Oh memory page record input.");
232
+ }
233
+ const value = createOhMemoryPageValueV1(parsedInput.value as OhMemoryPageValueV1);
234
+ const record = createKnowledgeGraphRecordV1({
235
+ dependencies: parsedInput.dependencies as readonly string[],
236
+ key: parsedInput.key as string,
237
+ kind: "edition",
238
+ v: 1,
239
+ value: value as unknown as JsonValue,
240
+ });
241
+ return { ...record, kind: "edition", value };
242
+ }
243
+
244
+ export function parseOhMemoryPageRecordV1(value: unknown): OhMemoryPageRecordV1 | null {
245
+ const envelope = exactDataRecord(value, [
246
+ "dependencies", "key", "kind", "recordSha256", "v", "value",
247
+ ]);
248
+ if (envelope === null) return null;
249
+ const record = parseKnowledgeGraphRecordV1(envelope);
250
+ if (record === null || record.kind !== "edition") return null;
251
+ const page = parseOhMemoryPageValueV1(record.value);
252
+ return page === null ? null : { ...record, kind: "edition", value: page };
253
+ }
254
+
255
+ /** Register this only where `edition` is reserved for the memory-page profile. */
256
+ export const OH_MEMORY_PAGE_RECORD_CODEC_V1: OhRecordCodec = Object.freeze({
257
+ kind: "edition" as const,
258
+ parse(value: unknown): JsonValue | null {
259
+ return parseOhMemoryPageValueV1(value) as unknown as JsonValue | null;
260
+ },
261
+ });
262
+
263
+ type FrontmatterScalar = null | number | string;
264
+ type FrontmatterEntry = readonly [key: string, value: FrontmatterScalar];
265
+
266
+ function scalar(value: FrontmatterScalar): string {
267
+ return JSON.stringify(value).replaceAll("\u2028", "\\u2028").replaceAll("\u2029", "\\u2029");
268
+ }
269
+
270
+ function dependencyPrefix(index: number): string {
271
+ return `dependency-${index.toString().padStart(4, "0")}`;
272
+ }
273
+
274
+ function sourcePrefix(index: number): string {
275
+ return `source-${index.toString().padStart(3, "0")}`;
276
+ }
277
+
278
+ function markdownEntries(record: OhMemoryPageRecordV1): readonly FrontmatterEntry[] {
279
+ const page = record.value;
280
+ const entries: FrontmatterEntry[] = [
281
+ ["format", page.format],
282
+ ["record-v", record.v],
283
+ ["record-kind", record.kind],
284
+ ["record-key", record.key],
285
+ ["record-sha256", record.recordSha256],
286
+ ["dependency-count", record.dependencies.length],
287
+ ];
288
+ record.dependencies.forEach((dependency, index) => {
289
+ entries.push([`${dependencyPrefix(index)}-key`, dependency]);
290
+ });
291
+ entries.push(
292
+ ["page-v", page.v],
293
+ ["title", page.title],
294
+ ["summary", page.summary],
295
+ ["language", page.language],
296
+ ["created-at", page.createdAt],
297
+ ["updated-at", page.updatedAt],
298
+ ["provenance-kind", page.provenance.kind],
299
+ ["provenance-v", page.provenance.v],
300
+ ["provenance-actor-id", page.provenance.actorId],
301
+ ["provenance-attested-at", page.provenance.attestedAt],
302
+ ["provenance-attestation-sha256", page.provenance.attestationSha256],
303
+ ["source-count", page.sources.length],
304
+ );
305
+ page.sources.forEach((source, index) => {
306
+ const prefix = sourcePrefix(index);
307
+ entries.push(
308
+ [`${prefix}-v`, source.v],
309
+ [`${prefix}-url`, source.url],
310
+ [`${prefix}-title`, source.title],
311
+ [`${prefix}-observed-at`, source.observedAt],
312
+ [`${prefix}-content-sha256`, source.contentSha256],
313
+ );
314
+ });
315
+ return entries;
316
+ }
317
+
318
+ /**
319
+ * Renders a self-contained record transport. Oh bundles remain the
320
+ * authoritative multi-record and operation transport.
321
+ */
322
+ export function renderOhMemoryPageMarkdownV1(value: OhMemoryPageRecordV1): string {
323
+ const record = parseOhMemoryPageRecordV1(value);
324
+ if (record === null) throw new TypeError("Invalid Oh memory page record.");
325
+ const frontmatter = markdownEntries(record).map(([key, item]) => `${key}: ${scalar(item)}`).join("\n");
326
+ const rendered = `---\n${frontmatter}\n---\n${record.value.body}`;
327
+ if (utf8ByteLength(rendered) > OH_MEMORY_PAGE_LIMITS_V1.fileBytes) {
328
+ throw new RangeError("Oh memory page Markdown exceeds its byte limit.");
329
+ }
330
+ return rendered;
331
+ }
332
+
333
+ function parseFrontmatterLine(line: string): FrontmatterEntry | null {
334
+ const separator = line.indexOf(": ");
335
+ if (separator < 1 || !/^[a-z][a-z0-9-]*$/u.test(line.slice(0, separator))) return null;
336
+ const key = line.slice(0, separator);
337
+ const encoded = line.slice(separator + 2);
338
+ let value: unknown;
339
+ try {
340
+ value = JSON.parse(encoded);
341
+ } catch {
342
+ return null;
343
+ }
344
+ if ((value !== null && typeof value !== "string" && typeof value !== "number")
345
+ || (typeof value === "number" && !Number.isFinite(value))
346
+ || scalar(value as FrontmatterScalar) !== encoded) return null;
347
+ return [key, value as FrontmatterScalar];
348
+ }
349
+
350
+ /**
351
+ * Parses the exact `.oh.md` scalar subset and recomputes the graph record
352
+ * digest. Comments, aliases, tags, duplicate keys, alternate key order,
353
+ * alternate scalar spellings, and CRLF are rejected.
354
+ */
355
+ export function parseOhMemoryPageMarkdownV1(text: unknown): OhMemoryPageRecordV1 | null {
356
+ if (typeof text !== "string" || utf8ByteLength(text) > OH_MEMORY_PAGE_LIMITS_V1.fileBytes
357
+ || !text.startsWith("---\n")) return null;
358
+ const closing = text.indexOf("\n---\n", 4);
359
+ if (closing < 0) return null;
360
+ const frontmatter = text.slice(4, closing);
361
+ let frontmatterLines = 1;
362
+ for (let index = frontmatter.indexOf("\n"); index >= 0;
363
+ index = frontmatter.indexOf("\n", index + 1)) {
364
+ frontmatterLines += 1;
365
+ if (frontmatterLines > OH_MEMORY_PAGE_LIMITS_V1.frontmatterLines) return null;
366
+ }
367
+ const lines = frontmatter.split("\n");
368
+ const entries = lines.map(parseFrontmatterLine);
369
+ if (entries.some((entry) => entry === null) || entries.length < 18) return null;
370
+ const parsedEntries = entries as FrontmatterEntry[];
371
+ const dependencyCount = parsedEntries[5]?.[1];
372
+ if (!Number.isSafeInteger(dependencyCount) || (dependencyCount as number) < 0
373
+ || (dependencyCount as number) > OH_GRAPH_LIMITS_V1.dependenciesPerRecord) return null;
374
+ const pageOffset = 6 + (dependencyCount as number);
375
+ const sourceCount = parsedEntries[pageOffset + 11]?.[1];
376
+ if (!Number.isSafeInteger(sourceCount) || (sourceCount as number) < 0
377
+ || (sourceCount as number) > OH_MEMORY_PAGE_LIMITS_V1.sources) return null;
378
+ const expectedKeys = [
379
+ "format", "record-v", "record-kind", "record-key", "record-sha256", "dependency-count",
380
+ ...Array.from({ length: dependencyCount as number }, (_, index) => `${dependencyPrefix(index)}-key`),
381
+ "page-v", "title", "summary", "language", "created-at", "updated-at", "provenance-kind",
382
+ "provenance-v", "provenance-actor-id", "provenance-attested-at",
383
+ "provenance-attestation-sha256", "source-count",
384
+ ...Array.from({ length: sourceCount as number }, (_, index) => {
385
+ const prefix = sourcePrefix(index);
386
+ return [`${prefix}-v`, `${prefix}-url`, `${prefix}-title`,
387
+ `${prefix}-observed-at`, `${prefix}-content-sha256`];
388
+ }).flat(),
389
+ ];
390
+ if (parsedEntries.length !== expectedKeys.length
391
+ || parsedEntries.some(([key], index) => key !== expectedKeys[index])) return null;
392
+
393
+ const dependencies = Array.from({ length: dependencyCount as number },
394
+ (_, index) => parsedEntries[6 + index]?.[1]);
395
+ const sources: OhMemoryPageSourceV1[] = [];
396
+ for (let index = 0; index < (sourceCount as number); index += 1) {
397
+ const offset = pageOffset + 12 + index * 5;
398
+ sources.push({
399
+ v: parsedEntries[offset]?.[1] as 1,
400
+ url: parsedEntries[offset + 1]?.[1] as string,
401
+ title: parsedEntries[offset + 2]?.[1] as string,
402
+ observedAt: parsedEntries[offset + 3]?.[1] as string,
403
+ contentSha256: parsedEntries[offset + 4]?.[1] as Sha256Hex,
404
+ });
405
+ }
406
+ const page = parseOhMemoryPageValueV1({
407
+ body: text.slice(closing + 5),
408
+ createdAt: parsedEntries[pageOffset + 4]?.[1],
409
+ format: parsedEntries[0]?.[1],
410
+ language: parsedEntries[pageOffset + 3]?.[1],
411
+ provenance: {
412
+ actorId: parsedEntries[pageOffset + 8]?.[1],
413
+ attestationSha256: parsedEntries[pageOffset + 10]?.[1],
414
+ attestedAt: parsedEntries[pageOffset + 9]?.[1],
415
+ kind: parsedEntries[pageOffset + 6]?.[1],
416
+ v: parsedEntries[pageOffset + 7]?.[1],
417
+ },
418
+ sources,
419
+ summary: parsedEntries[pageOffset + 2]?.[1],
420
+ title: parsedEntries[pageOffset + 1]?.[1],
421
+ updatedAt: parsedEntries[pageOffset + 5]?.[1],
422
+ v: parsedEntries[pageOffset]?.[1],
423
+ });
424
+ if (page === null || parsedEntries[1]?.[1] !== 1 || parsedEntries[2]?.[1] !== "edition"
425
+ || typeof parsedEntries[3]?.[1] !== "string" || typeof parsedEntries[4]?.[1] !== "string"
426
+ || dependencies.some((dependency) => typeof dependency !== "string")) return null;
427
+ let record: OhMemoryPageRecordV1;
428
+ try {
429
+ record = createOhMemoryPageRecordV1({
430
+ dependencies: dependencies as string[],
431
+ key: parsedEntries[3][1] as string,
432
+ value: page,
433
+ });
434
+ } catch {
435
+ return null;
436
+ }
437
+ return record.recordSha256 === parsedEntries[4][1] && renderOhMemoryPageMarkdownV1(record) === text
438
+ ? record
439
+ : null;
440
+ }
package/src/memory.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
2
2
 
3
+ export * from "./memory-pages";
4
+
3
5
  import {
4
6
  canonicalJson,
5
7
  canonicalSha256,
@@ -0,0 +1,2 @@
1
+ export * from "./cloudflare-embedding";
2
+ export * from "./libsql-semantic";
package/src/semantic.ts CHANGED
@@ -33,9 +33,20 @@ export function normalizeOhEmbeddingV1(vector: readonly number[]): readonly numb
33
33
  || vector.some((component) => !Number.isFinite(component))) {
34
34
  throw new TypeError(`Embedding vectors must contain ${OH_EMBEDDING_PROFILE_V1.dimensions} finite values.`);
35
35
  }
36
- const magnitude = Math.sqrt(vector.reduce((sum, component) => sum + component * component, 0));
37
- if (magnitude === 0) throw new TypeError("Embedding vectors must have nonzero magnitude.");
38
- return vector.map((component) => component / magnitude);
36
+ const scale = vector.reduce((maximum, component) => Math.max(maximum, Math.abs(component)), 0);
37
+ if (scale === 0) throw new TypeError("Embedding vectors must have nonzero magnitude.");
38
+ const scaledMagnitude = Math.sqrt(vector.reduce((sum, component) => {
39
+ const scaled = component / scale;
40
+ return sum + scaled * scaled;
41
+ }, 0));
42
+ if (!Number.isFinite(scaledMagnitude) || scaledMagnitude === 0) {
43
+ throw new TypeError("Embedding vectors must have finite nonzero magnitude.");
44
+ }
45
+ const normalized = vector.map((component) => (component / scale) / scaledMagnitude);
46
+ if (normalized.some((component) => !Number.isFinite(component))) {
47
+ throw new TypeError("Embedding vectors must normalize to finite values.");
48
+ }
49
+ return normalized;
39
50
  }
40
51
 
41
52
  export function cosineSimilarityV1(left: readonly number[], right: readonly number[]): number {