@lunora/bindings 1.0.0-alpha.2 → 1.0.0-alpha.21

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 (57) hide show
  1. package/LICENSE.md +6 -0
  2. package/dist/analytics/index.d.mts +66 -87
  3. package/dist/analytics/index.d.ts +66 -87
  4. package/dist/analytics/index.mjs +1 -2
  5. package/dist/images/index.d.mts +148 -148
  6. package/dist/images/index.d.ts +148 -148
  7. package/dist/images/index.mjs +1 -3
  8. package/dist/kv/index.d.mts +130 -113
  9. package/dist/kv/index.d.ts +130 -113
  10. package/dist/kv/index.mjs +1 -1
  11. package/dist/packem_shared/AnalyticsSqlError-B-JcsUhX.mjs +1 -0
  12. package/dist/packem_shared/R2SqlError-Uaz0RJTR.mjs +1 -0
  13. package/dist/packem_shared/SelectBuilder-WMBQ2b4q.mjs +1 -0
  14. package/dist/packem_shared/SetOperation-BrzMB1Tb.mjs +1 -0
  15. package/dist/packem_shared/Sql-CwhZl1Q5.mjs +1 -0
  16. package/dist/packem_shared/WindowExpression-CxCuEy8V.mjs +1 -0
  17. package/dist/packem_shared/WindowFunction-rzl4CzYE.mjs +1 -0
  18. package/dist/packem_shared/asc-BsbdtIQU.mjs +1 -0
  19. package/dist/packem_shared/buildImageDeliveryUrl-CMUkVJfB.mjs +1 -0
  20. package/dist/packem_shared/buildSignedImageUrl-BzgCHIu6.mjs +4 -0
  21. package/dist/packem_shared/concurrent-DMFQCILU.mjs +1 -0
  22. package/dist/packem_shared/createAnalytics-HRPCzT1M.mjs +1 -0
  23. package/dist/packem_shared/createContextVectors-D-ae1wWO.mjs +6 -0
  24. package/dist/packem_shared/createImages-TW6ircG2.mjs +1 -0
  25. package/dist/packem_shared/createKv-CKeFDFuG.mjs +1 -0
  26. package/dist/packem_shared/createKvIntrospector-Bz0nqUjD.mjs +1 -0
  27. package/dist/packem_shared/createPipelines-n0Bf_p8Y.mjs +1 -0
  28. package/dist/packem_shared/createVectorAdminIntrospector-B9Yt09yj.mjs +1 -0
  29. package/dist/packem_shared/createVectors-jb8fAY6R.mjs +1 -0
  30. package/dist/pipelines/index.d.mts +24 -24
  31. package/dist/pipelines/index.d.ts +24 -24
  32. package/dist/pipelines/index.mjs +1 -1
  33. package/dist/r2sql/index.d.mts +124 -124
  34. package/dist/r2sql/index.d.ts +124 -124
  35. package/dist/r2sql/index.mjs +1 -7
  36. package/dist/vectors/index.d.mts +185 -134
  37. package/dist/vectors/index.d.ts +185 -134
  38. package/dist/vectors/index.mjs +1 -3
  39. package/package.json +5 -1
  40. package/dist/packem_shared/AnalyticsSqlError-CGTdsi4H.mjs +0 -42
  41. package/dist/packem_shared/R2SqlError-DlDd_SrE.mjs +0 -67
  42. package/dist/packem_shared/SelectBuilder-DHaXZwn_.mjs +0 -167
  43. package/dist/packem_shared/SetOperation-RDHcxccj.mjs +0 -80
  44. package/dist/packem_shared/Sql-DceGtcUd.mjs +0 -68
  45. package/dist/packem_shared/WindowExpression-Cg9s2xcr.mjs +0 -44
  46. package/dist/packem_shared/WindowFunction-DA3pGC3N.mjs +0 -82
  47. package/dist/packem_shared/asc-Cur-xO8v.mjs +0 -16
  48. package/dist/packem_shared/buildImageDeliveryUrl-D1sVfIOP.mjs +0 -30
  49. package/dist/packem_shared/buildSignedImageUrl-Otdgc_jO.mjs +0 -113
  50. package/dist/packem_shared/concurrent-Dj5sOibv.mjs +0 -23
  51. package/dist/packem_shared/createAnalytics-CEEI69o9.mjs +0 -57
  52. package/dist/packem_shared/createContextVectors-BSizpmu5.mjs +0 -140
  53. package/dist/packem_shared/createImages-CJrvqX0u.mjs +0 -80
  54. package/dist/packem_shared/createKv-DTiSt216.mjs +0 -141
  55. package/dist/packem_shared/createPipelines-CfyJ6VGu.mjs +0 -10
  56. package/dist/packem_shared/createVectorAdminIntrospector-BJUOM6VW.mjs +0 -51
  57. package/dist/packem_shared/createVectors-LSpGoKCd.mjs +0 -91
@@ -1,140 +0,0 @@
1
- import { c as concurrentMap, U as UPSERT_EMBED_CONCURRENCY } from './concurrent-Dj5sOibv.mjs';
2
-
3
- const createContextVectors = (lunora) => {
4
- const upsert = async (indexName, input) => {
5
- await lunora.upsert(indexName, {
6
- embed: input.embed,
7
- id: input.id,
8
- input: input.input,
9
- metadata: input.metadata,
10
- namespace: input.namespace
11
- });
12
- };
13
- return {
14
- deleteByIds: async (indexName, ids) => {
15
- await lunora.deleteByIds(indexName, ids);
16
- },
17
- getByIds: async (indexName, ids) => {
18
- const records = await lunora.getByIds(indexName, ids);
19
- return records.map((record) => {
20
- return { id: record.id, metadata: record.metadata, values: record.values };
21
- });
22
- },
23
- query: async (indexName, input) => {
24
- const result = await lunora.query(indexName, {
25
- embed: input.embed,
26
- filter: input.filter,
27
- input: input.input,
28
- namespace: input.namespace,
29
- // Default to "indexed" rather than "all": returning every
30
- // metadata field by default leaks whatever was stored on the
31
- // vector (potentially cross-tenant if namespaces aren't wired).
32
- // Callers that need full metadata opt in explicitly via input.
33
- returnMetadata: input.returnMetadata ?? "indexed",
34
- topK: input.topK,
35
- vector: input.vector
36
- });
37
- return {
38
- count: result.count,
39
- matches: result.matches.map((match) => {
40
- return { id: match.id, metadata: match.metadata, score: match.score };
41
- })
42
- };
43
- },
44
- upsert,
45
- upsertNow: upsert
46
- };
47
- };
48
- const sharedNamespaceWarned = /* @__PURE__ */ new Set();
49
- const warnSharedNamespace = (indexName) => {
50
- if (sharedNamespaceWarned.has(indexName)) {
51
- return;
52
- }
53
- sharedNamespaceWarned.add(indexName);
54
- console.warn(
55
- `[@lunora/bindings/vectors] index "${indexName}" syncs vectors without a namespace — in a
56
- multi-tenant/sharded app this exposes one tenant's vectors (and any captured
57
- metadata) to every other tenant, since Vectorize indexes are account-global.
58
- Pass \`namespace\` (the shard/tenant key) on both write and query — query-side
59
- namespace filtering is mandatory for multi-tenant apps. Single-tenant apps that
60
- legitimately have no tenant key suppress this via { allowSharedNamespace: true }.`
61
- );
62
- };
63
- const pickMetadata = (row, fields) => {
64
- const result = {};
65
- for (const field of fields) {
66
- if (field in row) {
67
- result[field] = row[field];
68
- }
69
- }
70
- return result;
71
- };
72
- const createVectorSyncHook = (options) => {
73
- const { allowSharedNamespace, namespace, schema, vectors } = options;
74
- return async (event) => {
75
- const tableDefinition = schema.tables[event.table];
76
- const inlineIndexes = tableDefinition?.vectorIndexes ?? [];
77
- const standaloneIndexes = Object.entries(schema.vectorIndexes).filter(([, definition]) => definition.table === event.table);
78
- if (inlineIndexes.length === 0 && standaloneIndexes.length === 0) {
79
- return;
80
- }
81
- const allIndexNames = [...inlineIndexes.map((index) => index.name), ...standaloneIndexes.map(([name]) => name)];
82
- if (event.op === "delete") {
83
- await Promise.all(allIndexNames.map((name) => vectors.deleteByIds(name, [event.id])));
84
- return;
85
- }
86
- const row = event.doc;
87
- if (!row) {
88
- return;
89
- }
90
- const inlineWithValue = inlineIndexes.map((index) => {
91
- return { index, value: row[index.field] };
92
- });
93
- const inlineToUpsert = inlineWithValue.filter((entry) => entry.value !== void 0 && entry.value !== null);
94
- const inlineToClear = inlineWithValue.filter((entry) => entry.value === void 0 || entry.value === null);
95
- for (const { index, value } of inlineToUpsert) {
96
- if (typeof value !== "string") {
97
- throw new TypeError(
98
- `@lunora/bindings/vectors: inline index "${index.name}" expects a string source at "${index.field}" on table "${event.table}" (got ${typeof value}); use a standalone defineVectorIndex with a select() to derive text from non-string columns`
99
- );
100
- }
101
- }
102
- const operations = [
103
- ...inlineToClear.map((entry) => async () => {
104
- await vectors.deleteByIds(entry.index.name, [event.id]);
105
- }),
106
- ...inlineToUpsert.map((entry) => async () => {
107
- if (!allowSharedNamespace && namespace === void 0) {
108
- warnSharedNamespace(entry.index.name);
109
- }
110
- await vectors.upsert(entry.index.name, {
111
- embed: entry.index.embed,
112
- id: event.id,
113
- input: entry.value,
114
- metadata: entry.index.metadata ? pickMetadata(row, entry.index.metadata) : void 0,
115
- namespace
116
- });
117
- }),
118
- ...standaloneIndexes.map(([name, definition]) => async () => {
119
- if (!allowSharedNamespace && namespace === void 0) {
120
- warnSharedNamespace(name);
121
- }
122
- await vectors.upsert(name, {
123
- embed: definition.embed,
124
- id: event.id,
125
- input: definition.select(row),
126
- metadata: definition.metadata?.(row),
127
- namespace
128
- });
129
- })
130
- ];
131
- try {
132
- await concurrentMap(operations, UPSERT_EMBED_CONCURRENCY, async (operation) => operation());
133
- } catch (error) {
134
- await Promise.allSettled(allIndexNames.map((name) => vectors.deleteByIds(name, [event.id])));
135
- throw error;
136
- }
137
- };
138
- };
139
-
140
- export { createContextVectors, createVectorSyncHook };
@@ -1,80 +0,0 @@
1
- const ALLOWED_OUTPUT_FORMATS = /* @__PURE__ */ new Set(["image/avif", "image/gif", "image/jpeg", "image/png", "image/webp"]);
2
- const DEFAULT_MAX_DIMENSION = 1e4;
3
- const DEFAULT_OUTPUT_FORMAT = "image/webp";
4
- const isR2ObjectBody = (input) => {
5
- if (typeof input !== "object") {
6
- return false;
7
- }
8
- const object = input;
9
- return "body" in object && !(input instanceof ArrayBuffer) && !(input instanceof Uint8Array);
10
- };
11
- const toStream = (input) => {
12
- if (input instanceof ReadableStream) {
13
- return input;
14
- }
15
- if (isR2ObjectBody(input)) {
16
- if (input.body === null) {
17
- throw new Error("@lunora/bindings/images: R2 object body is null (object missing or already consumed)");
18
- }
19
- return input.body;
20
- }
21
- if (input instanceof Blob) {
22
- return input.stream();
23
- }
24
- const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
25
- return new ReadableStream({
26
- start(controller) {
27
- controller.enqueue(bytes);
28
- controller.close();
29
- }
30
- });
31
- };
32
- const sanitizeTransform = (transform, maxDimension) => {
33
- if (transform === void 0) {
34
- return {};
35
- }
36
- const clampDimension = (value) => {
37
- if (!Number.isFinite(value) || value <= 0) {
38
- throw new Error("@lunora/bindings/images: width/height must be a positive finite number");
39
- }
40
- return Math.min(Math.floor(value), maxDimension);
41
- };
42
- const rest = { ...transform };
43
- delete rest.draw;
44
- return {
45
- ...rest,
46
- ...transform.width === void 0 ? {} : { width: clampDimension(transform.width) },
47
- ...transform.height === void 0 ? {} : { height: clampDimension(transform.height) }
48
- };
49
- };
50
- const splitOverlay = (overlay) => {
51
- const { image, transform, ...drawOptions } = overlay;
52
- return { drawOptions, image, transform };
53
- };
54
- const resolveOutput = (output) => {
55
- const format = output?.format ?? DEFAULT_OUTPUT_FORMAT;
56
- if (!ALLOWED_OUTPUT_FORMATS.has(format)) {
57
- throw new Error(`@lunora/bindings/images: unsupported output format "${format}" (allowed: ${[...ALLOWED_OUTPUT_FORMATS].join(", ")})`);
58
- }
59
- return { ...output, format };
60
- };
61
- const createImages = (options) => {
62
- const { binding } = options;
63
- const maxDimension = options.maxDimension ?? DEFAULT_MAX_DIMENSION;
64
- return {
65
- info: async (input) => binding.info(toStream(input)),
66
- transform: async (input, transform, output, overlays) => {
67
- const safeTransform = sanitizeTransform(transform, maxDimension);
68
- const outputOptions = resolveOutput(output);
69
- let transformer = binding.input(toStream(input)).transform(safeTransform);
70
- for (const overlay of overlays ?? []) {
71
- const { drawOptions, image, transform: overlayTransform } = splitOverlay(overlay);
72
- const overlayImage = overlayTransform === void 0 ? toStream(image) : binding.input(toStream(image)).transform(sanitizeTransform(overlayTransform, maxDimension));
73
- transformer = transformer.draw(overlayImage, drawOptions);
74
- }
75
- return transformer.output(outputOptions);
76
- }
77
- };
78
- };
79
-
80
- export { createImages };
@@ -1,141 +0,0 @@
1
- const MAX_KEY_LENGTH = 512;
2
- const MAX_LIST_LIMIT = 1e3;
3
- const validateKey = (key) => {
4
- if (typeof key !== "string" || key.length === 0) {
5
- throw new Error("@lunora/bindings/kv: key must be a non-empty string");
6
- }
7
- if (key.length > MAX_KEY_LENGTH) {
8
- throw new Error(`@lunora/bindings/kv: key exceeds ${String(MAX_KEY_LENGTH)}-byte limit`);
9
- }
10
- if (key.includes("\0")) {
11
- throw new Error("@lunora/bindings/kv: key contains NUL byte");
12
- }
13
- const segments = key.split("/");
14
- for (const segment of segments) {
15
- if (segment === "." || segment === "..") {
16
- throw new Error("@lunora/bindings/kv: key contains a `.`/`..` path component");
17
- }
18
- }
19
- };
20
- const validatePrefix = (prefix) => {
21
- if (prefix.length === 0) {
22
- return;
23
- }
24
- if (prefix.length > MAX_KEY_LENGTH) {
25
- throw new Error(`@lunora/bindings/kv: prefix exceeds ${String(MAX_KEY_LENGTH)}-byte limit`);
26
- }
27
- if (prefix.includes("\0")) {
28
- throw new Error("@lunora/bindings/kv: prefix contains NUL byte");
29
- }
30
- const segments = prefix.split("/");
31
- for (const segment of segments) {
32
- if (segment === "." || segment === "..") {
33
- throw new Error("@lunora/bindings/kv: prefix contains a `.`/`..` path component");
34
- }
35
- }
36
- };
37
- const scopeKey = (prefix, key) => {
38
- validateKey(prefix);
39
- validateKey(key);
40
- const trimmedPrefix = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
41
- const composed = `${trimmedPrefix}/${key}`;
42
- if (composed.length > MAX_KEY_LENGTH) {
43
- throw new Error(`@lunora/bindings/kv: scoped key exceeds ${String(MAX_KEY_LENGTH)}-byte limit`);
44
- }
45
- return composed;
46
- };
47
- const toPutOptions = (options) => {
48
- const out = {};
49
- if (options.expiration !== void 0 && options.expirationTtl !== void 0) {
50
- throw new Error("@lunora/bindings/kv: `expiration` and `expirationTtl` are mutually exclusive");
51
- }
52
- if (options.expiration !== void 0) {
53
- out.expiration = options.expiration;
54
- }
55
- if (options.expirationTtl !== void 0) {
56
- out.expirationTtl = options.expirationTtl;
57
- }
58
- if (options.metadata !== void 0) {
59
- out.metadata = options.metadata;
60
- }
61
- return Object.keys(out).length > 0 ? out : void 0;
62
- };
63
- const createKv = (options) => {
64
- if (!options.namespace) {
65
- throw new Error("@lunora/bindings/kv: `namespace` is required");
66
- }
67
- const { keyPrefix, namespace } = options;
68
- if (keyPrefix !== void 0) {
69
- validateKey(keyPrefix);
70
- }
71
- const resolve = (key) => {
72
- if (keyPrefix === void 0) {
73
- validateKey(key);
74
- return key;
75
- }
76
- return scopeKey(keyPrefix, key);
77
- };
78
- const stripPrefix = (name) => {
79
- if (keyPrefix === void 0) {
80
- return name;
81
- }
82
- const trimmed = keyPrefix.endsWith("/") ? keyPrefix : `${keyPrefix}/`;
83
- return name.startsWith(trimmed) ? name.slice(trimmed.length) : name;
84
- };
85
- const get = async (key, getOptions = {}) => {
86
- const value = await namespace.get(resolve(key), { cacheTtl: getOptions.cacheTtl, type: "json" });
87
- return value ?? null;
88
- };
89
- const getRaw = async (key, getOptions = {}) => {
90
- const value = await namespace.get(resolve(key), { cacheTtl: getOptions.cacheTtl, type: getOptions.type ?? "text" });
91
- return value ?? null;
92
- };
93
- const getWithMetadata = async (key, getOptions = {}) => {
94
- const result = await namespace.getWithMetadata(resolve(key), { cacheTtl: getOptions.cacheTtl, type: "json" });
95
- return { metadata: result.metadata ?? null, value: result.value ?? null };
96
- };
97
- const put = async (key, value, putOptions = {}) => {
98
- const body = putOptions.raw ? value : JSON.stringify(value);
99
- await namespace.put(resolve(key), body, toPutOptions(putOptions));
100
- };
101
- const deleteKey = async (key) => {
102
- await namespace.delete(resolve(key));
103
- };
104
- const list = async (listOptions = {}) => {
105
- if (listOptions.limit !== void 0 && (!Number.isInteger(listOptions.limit) || listOptions.limit <= 0)) {
106
- throw new Error("@lunora/bindings/kv: `limit` must be a positive integer");
107
- }
108
- let { prefix } = listOptions;
109
- if (prefix !== void 0) {
110
- validatePrefix(prefix);
111
- }
112
- if (keyPrefix !== void 0) {
113
- const base = keyPrefix.endsWith("/") ? keyPrefix : `${keyPrefix}/`;
114
- prefix = listOptions.prefix === void 0 ? base : `${base}${listOptions.prefix}`;
115
- validatePrefix(prefix);
116
- }
117
- const limit = listOptions.limit === void 0 ? void 0 : Math.min(listOptions.limit, MAX_LIST_LIMIT);
118
- const result = await namespace.list({ cursor: listOptions.cursor, limit, prefix });
119
- const keys = result.keys.map((entry) => {
120
- return {
121
- ...entry,
122
- name: stripPrefix(entry.name)
123
- };
124
- });
125
- return {
126
- cursor: result.list_complete ? void 0 : result.cursor,
127
- keys,
128
- listComplete: result.list_complete
129
- };
130
- };
131
- return {
132
- delete: deleteKey,
133
- get,
134
- getRaw,
135
- getWithMetadata,
136
- list,
137
- put
138
- };
139
- };
140
-
141
- export { createKv, scopeKey };
@@ -1,10 +0,0 @@
1
- const createPipelines = (options) => {
2
- const { binding } = options;
3
- return {
4
- send: async (records) => {
5
- await binding.send(Array.isArray(records) ? records : [records]);
6
- }
7
- };
8
- };
9
-
10
- export { createPipelines };
@@ -1,51 +0,0 @@
1
- const MAX_TOP_K = 20;
2
- const DEFAULT_TOP_K = 10;
3
- const createVectorAdminIntrospector = (options) => {
4
- const { embedders, indexes, registry } = options;
5
- const listIndexes = async () => Promise.all(
6
- registry.map(async (entry) => {
7
- const binding = indexes[entry.name];
8
- if (binding?.describe === void 0) {
9
- return { ...entry };
10
- }
11
- try {
12
- const details = await binding.describe();
13
- return {
14
- ...entry,
15
- dimensions: entry.dimensions ?? details.dimensions,
16
- processedUpToMutation: details.processedUpToMutation,
17
- vectorsCount: details.vectorsCount
18
- };
19
- } catch {
20
- return { ...entry };
21
- }
22
- })
23
- );
24
- const hasEmbedders = embedders !== void 0 && Object.keys(embedders).length > 0;
25
- if (!hasEmbedders) {
26
- return { listIndexes };
27
- }
28
- const queryIndex = async ({ name, text, topK }) => {
29
- const binding = indexes[name];
30
- if (binding === void 0) {
31
- throw new Error(`@lunora/bindings/vectors: no Vectorize binding registered for index "${name}"`);
32
- }
33
- const embed = embedders[name];
34
- if (embed === void 0) {
35
- throw new Error(`@lunora/bindings/vectors: no embedder registered for index "${name}" — it lists read-only`);
36
- }
37
- const vector = await embed(text);
38
- const result = await binding.query(vector, {
39
- returnMetadata: "all",
40
- topK: Math.min(topK ?? DEFAULT_TOP_K, MAX_TOP_K)
41
- });
42
- return {
43
- matches: result.matches.map((match) => {
44
- return { id: match.id, metadata: match.metadata, score: match.score };
45
- })
46
- };
47
- };
48
- return { listIndexes, queryIndex };
49
- };
50
-
51
- export { createVectorAdminIntrospector };
@@ -1,91 +0,0 @@
1
- import { c as concurrentMap, U as UPSERT_EMBED_CONCURRENCY } from './concurrent-Dj5sOibv.mjs';
2
-
3
- const resolveIndex = (indexes, name) => {
4
- const index = indexes[name];
5
- if (!index) {
6
- throw new Error(`@lunora/bindings/vectors: no index registered for "${name}". Known indexes: ${Object.keys(indexes).join(", ") || "(none)"}`);
7
- }
8
- return index;
9
- };
10
- const toVector = async (input) => {
11
- const values = await input.embed(input.input);
12
- return {
13
- id: input.id,
14
- metadata: input.metadata,
15
- namespace: input.namespace,
16
- values
17
- };
18
- };
19
- const MAX_TOP_K = 100;
20
- const MAX_TOP_K_WITH_VALUES = 20;
21
- const MAX_ID_BATCH = 1e3;
22
- const MAX_UPSERT_BATCH = 1e3;
23
- const createVectors = (options) => {
24
- if (Object.keys(options.indexes).length === 0) {
25
- throw new Error("@lunora/bindings/vectors: at least one index binding is required");
26
- }
27
- const upsert = async (indexName, input) => {
28
- const index = resolveIndex(options.indexes, indexName);
29
- const vector = await toVector(input);
30
- return index.upsert([vector]);
31
- };
32
- const upsertMany = async (indexName, inputs) => {
33
- const index = resolveIndex(options.indexes, indexName);
34
- if (inputs.length > MAX_UPSERT_BATCH) {
35
- throw new RangeError(
36
- `@lunora/bindings/vectors: upsertMany batch exceeds ${String(MAX_UPSERT_BATCH)} (got ${String(inputs.length)}) — split across calls`
37
- );
38
- }
39
- const vectors = await concurrentMap(inputs, UPSERT_EMBED_CONCURRENCY, toVector);
40
- return index.upsert(vectors);
41
- };
42
- const query = async (indexName, input) => {
43
- const index = resolveIndex(options.indexes, indexName);
44
- const wantsHeavyPayload = input.returnValues === true || input.returnMetadata === "all";
45
- const topKCeiling = wantsHeavyPayload ? MAX_TOP_K_WITH_VALUES : MAX_TOP_K;
46
- if (input.topK !== void 0 && (!Number.isInteger(input.topK) || input.topK < 1 || input.topK > topKCeiling)) {
47
- const reason = wantsHeavyPayload ? ' (lowered to 20 because returnValues/returnMetadata:"all" is set)' : "";
48
- throw new RangeError(`@lunora/bindings/vectors: topK must be an integer in [1, ${String(topKCeiling)}]${reason} (got ${String(input.topK)})`);
49
- }
50
- let values;
51
- if (input.vector && input.vector.length > 0) {
52
- values = input.vector;
53
- } else {
54
- if (!input.embed || input.input === void 0) {
55
- throw new Error("@lunora/bindings/vectors: query requires either `vector` or both `input` and `embed`");
56
- }
57
- values = await input.embed(input.input);
58
- }
59
- return index.query(values, {
60
- filter: input.filter,
61
- namespace: input.namespace,
62
- returnMetadata: input.returnMetadata,
63
- returnValues: input.returnValues,
64
- topK: input.topK
65
- });
66
- };
67
- const getByIds = async (indexName, ids) => {
68
- const index = resolveIndex(options.indexes, indexName);
69
- if (ids.length > MAX_ID_BATCH) {
70
- throw new RangeError(`@lunora/bindings/vectors: getByIds accepts at most ${String(MAX_ID_BATCH)} ids (got ${String(ids.length)})`);
71
- }
72
- return index.getByIds(ids);
73
- };
74
- const deleteByIds = async (indexName, ids) => {
75
- const index = resolveIndex(options.indexes, indexName);
76
- if (ids.length > MAX_ID_BATCH) {
77
- throw new RangeError(`@lunora/bindings/vectors: deleteByIds accepts at most ${String(MAX_ID_BATCH)} ids (got ${String(ids.length)})`);
78
- }
79
- return index.deleteByIds(ids);
80
- };
81
- const describe = async (indexName) => {
82
- const index = resolveIndex(options.indexes, indexName);
83
- if (!index.describe) {
84
- throw new Error(`@lunora/bindings/vectors: binding for "${indexName}" does not implement describe()`);
85
- }
86
- return index.describe();
87
- };
88
- return { deleteByIds, describe, getByIds, query, upsert, upsertMany };
89
- };
90
-
91
- export { createVectors as default };