@aura3d/asset-index 1.0.5
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/dist/CanonicalAsset.d.ts +79 -0
- package/dist/CanonicalAsset.d.ts.map +1 -0
- package/dist/CanonicalAsset.js +50 -0
- package/dist/CanonicalAsset.js.map +1 -0
- package/dist/IndexStore.d.ts +67 -0
- package/dist/IndexStore.d.ts.map +1 -0
- package/dist/IndexStore.js +112 -0
- package/dist/IndexStore.js.map +1 -0
- package/dist/SourceAdapter.d.ts +54 -0
- package/dist/SourceAdapter.d.ts.map +1 -0
- package/dist/SourceAdapter.js +9 -0
- package/dist/SourceAdapter.js.map +1 -0
- package/dist/adapters/aura-index.d.ts +11 -0
- package/dist/adapters/aura-index.d.ts.map +1 -0
- package/dist/adapters/aura-index.js +64 -0
- package/dist/adapters/aura-index.js.map +1 -0
- package/dist/adapters/jsdelivr-mirror.d.ts +7 -0
- package/dist/adapters/jsdelivr-mirror.d.ts.map +1 -0
- package/dist/adapters/jsdelivr-mirror.js +80 -0
- package/dist/adapters/jsdelivr-mirror.js.map +1 -0
- package/dist/adapters/khronos.d.ts +3 -0
- package/dist/adapters/khronos.d.ts.map +1 -0
- package/dist/adapters/khronos.js +78 -0
- package/dist/adapters/khronos.js.map +1 -0
- package/dist/adapters/marketplace.d.ts +3 -0
- package/dist/adapters/marketplace.d.ts.map +1 -0
- package/dist/adapters/marketplace.js +70 -0
- package/dist/adapters/marketplace.js.map +1 -0
- package/dist/adapters/os3a.d.ts +3 -0
- package/dist/adapters/os3a.d.ts.map +1 -0
- package/dist/adapters/os3a.js +110 -0
- package/dist/adapters/os3a.js.map +1 -0
- package/dist/adapters/poly-haven.d.ts +3 -0
- package/dist/adapters/poly-haven.d.ts.map +1 -0
- package/dist/adapters/poly-haven.js +110 -0
- package/dist/adapters/poly-haven.js.map +1 -0
- package/dist/adapters/poly-pizza.d.ts +35 -0
- package/dist/adapters/poly-pizza.d.ts.map +1 -0
- package/dist/adapters/poly-pizza.js +109 -0
- package/dist/adapters/poly-pizza.js.map +1 -0
- package/dist/adapters/sketchfab.d.ts +20 -0
- package/dist/adapters/sketchfab.d.ts.map +1 -0
- package/dist/adapters/sketchfab.js +183 -0
- package/dist/adapters/sketchfab.js.map +1 -0
- package/dist/embedding.d.ts +56 -0
- package/dist/embedding.d.ts.map +1 -0
- package/dist/embedding.js +121 -0
- package/dist/embedding.js.map +1 -0
- package/dist/federate.d.ts +56 -0
- package/dist/federate.d.ts.map +1 -0
- package/dist/federate.js +80 -0
- package/dist/federate.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/ranking.d.ts +6 -0
- package/dist/ranking.d.ts.map +1 -0
- package/dist/ranking.js +71 -0
- package/dist/ranking.js.map +1 -0
- package/dist/refresh.d.ts +54 -0
- package/dist/refresh.d.ts.map +1 -0
- package/dist/refresh.js +48 -0
- package/dist/refresh.js.map +1 -0
- package/package.json +19 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { normalizeLicense } from "../CanonicalAsset.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sketchfab Data API v3 adapter.
|
|
4
|
+
*
|
|
5
|
+
* Verified live (https://api.sketchfab.com/v3):
|
|
6
|
+
*
|
|
7
|
+
* GET /v3/search?type=models&downloadable=true[&license=<slug>][&q=<text>]
|
|
8
|
+
* -> { results: [{
|
|
9
|
+
* uid, name, viewerUrl, isDownloadable,
|
|
10
|
+
* faceCount, vertexCount,
|
|
11
|
+
* license: { uid, label }, // e.g. label "CC0 Public Domain", "CC Attribution"
|
|
12
|
+
* thumbnails: { images: [{ uid, size, width, height, url }] },
|
|
13
|
+
* tags: [{ name, slug, uri }],
|
|
14
|
+
* archives: { glb?: {...}, gltf?: {...}, ... }
|
|
15
|
+
* }, ...], next, previous, cursors }
|
|
16
|
+
*
|
|
17
|
+
* GET /v3/models/{uid}/download (Authorization: Token <token>)
|
|
18
|
+
* -> { gltf?: { url, size, expires }, usdz?: { url, size, expires }, ... }
|
|
19
|
+
* where `url` is a SHORT-LIVED (expires ~300s) archive link. It cannot be
|
|
20
|
+
* embedded in the index; it must be exchanged at PULL time.
|
|
21
|
+
*
|
|
22
|
+
* License model: Sketchfab's search `license` object only exposes `{ uid, label }`
|
|
23
|
+
* (no SPDX/slug), so we map the human label onto a license slug and normalize it
|
|
24
|
+
* via `normalizeLicense`. Only CC0 / CC-BY families become verified +
|
|
25
|
+
* redistributable; everything else (and any model with no/unknown license)
|
|
26
|
+
* resolves to UNVERIFIED and is never auto-pulled.
|
|
27
|
+
*
|
|
28
|
+
* Because the file URL is a token exchange resolved at pull time, the canonical
|
|
29
|
+
* `url` points at the per-model download-resolve API endpoint
|
|
30
|
+
* (`/v3/models/{uid}/download`). The CLI pull bridge must perform the
|
|
31
|
+
* `Authorization: Token <SKETCHFAB_API_TOKEN>` exchange and follow the returned
|
|
32
|
+
* temporary `gltf.url` (see integrationNotes). We mark `access:'direct-download'`
|
|
33
|
+
* ONLY when a token is present AND the license is verified/redistributable;
|
|
34
|
+
* otherwise `access:'deep-link-only'` with the Sketchfab model page as sourcePage.
|
|
35
|
+
*/
|
|
36
|
+
const API_BASE = "https://api.sketchfab.com/v3";
|
|
37
|
+
/** Default page size for a search fan-out. */
|
|
38
|
+
const SEARCH_COUNT = 24;
|
|
39
|
+
/**
|
|
40
|
+
* Map a Sketchfab license LABEL (the only stable text the search API exposes)
|
|
41
|
+
* onto a string `normalizeLicense` recognizes. Anything outside the CC0 / CC-BY
|
|
42
|
+
* families is left as the raw label so it normalizes to UNVERIFIED.
|
|
43
|
+
*/
|
|
44
|
+
function licenseKeyFromLabel(label) {
|
|
45
|
+
if (!label)
|
|
46
|
+
return undefined;
|
|
47
|
+
const l = label.toLowerCase();
|
|
48
|
+
if (l.includes("cc0") || l.includes("public domain"))
|
|
49
|
+
return "CC0";
|
|
50
|
+
// "CC Attribution" (and only Attribution) maps to plain CC-BY; the
|
|
51
|
+
// ShareAlike / NoDerivs / NonCommercial variants intentionally fall through
|
|
52
|
+
// to their raw label and become UNVERIFIED (not freely redistributable here).
|
|
53
|
+
if (l === "cc attribution" || l === "cc-by" || l === "cc by")
|
|
54
|
+
return "CC-BY";
|
|
55
|
+
return label;
|
|
56
|
+
}
|
|
57
|
+
function tokenize(text) {
|
|
58
|
+
return text
|
|
59
|
+
.replace(/[_-]+/g, " ")
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.split(/[^a-z0-9]+/)
|
|
62
|
+
.filter((t) => t.length > 1);
|
|
63
|
+
}
|
|
64
|
+
/** Map our constraint license families to Sketchfab `license` query slugs. */
|
|
65
|
+
function licenseSlugs(constraints) {
|
|
66
|
+
const fams = constraints?.license;
|
|
67
|
+
if (!fams || fams.length === 0)
|
|
68
|
+
return [];
|
|
69
|
+
const slugs = [];
|
|
70
|
+
for (const fam of fams) {
|
|
71
|
+
if (fam === "CC0")
|
|
72
|
+
slugs.push("cc0");
|
|
73
|
+
else if (fam === "CC-BY")
|
|
74
|
+
slugs.push("by");
|
|
75
|
+
}
|
|
76
|
+
return slugs;
|
|
77
|
+
}
|
|
78
|
+
function buildSearchUrl(query) {
|
|
79
|
+
const params = new URLSearchParams();
|
|
80
|
+
params.set("type", "models");
|
|
81
|
+
params.set("downloadable", "true");
|
|
82
|
+
params.set("count", String(SEARCH_COUNT));
|
|
83
|
+
const text = query.text.trim();
|
|
84
|
+
if (text)
|
|
85
|
+
params.set("q", text);
|
|
86
|
+
// Sketchfab accepts repeated `license` params; restrict server-side when the
|
|
87
|
+
// caller already constrained to specific redistributable families.
|
|
88
|
+
for (const slug of licenseSlugs(query.constraints)) {
|
|
89
|
+
params.append("license", slug);
|
|
90
|
+
}
|
|
91
|
+
return `${API_BASE}/search?${params.toString()}`;
|
|
92
|
+
}
|
|
93
|
+
function bestThumbnail(thumbs) {
|
|
94
|
+
const images = thumbs?.images;
|
|
95
|
+
if (!images || images.length === 0)
|
|
96
|
+
return undefined;
|
|
97
|
+
let best;
|
|
98
|
+
for (const img of images) {
|
|
99
|
+
if (!img?.url)
|
|
100
|
+
continue;
|
|
101
|
+
if (!best || (img.size ?? 0) > (best.size ?? 0))
|
|
102
|
+
best = img;
|
|
103
|
+
}
|
|
104
|
+
return best?.url;
|
|
105
|
+
}
|
|
106
|
+
function toCanonical(model, hasToken) {
|
|
107
|
+
if (!model.uid || model.isDownloadable === false)
|
|
108
|
+
return null;
|
|
109
|
+
const sourcePage = model.viewerUrl ?? `https://sketchfab.com/3d-models/${model.uid}`;
|
|
110
|
+
const license = normalizeLicense(licenseKeyFromLabel(model.license?.label), sourcePage);
|
|
111
|
+
// The file URL is a short-lived token exchange resolved at PULL time, so the
|
|
112
|
+
// canonical url is the download-resolve API endpoint. It is only a real
|
|
113
|
+
// "direct-download" when we actually hold a token AND the license permits it.
|
|
114
|
+
const canResolve = hasToken && license.verified && license.redistributable;
|
|
115
|
+
const access = canResolve ? "direct-download" : "deep-link-only";
|
|
116
|
+
const url = canResolve
|
|
117
|
+
? `${API_BASE}/models/${model.uid}/download`
|
|
118
|
+
: sourcePage;
|
|
119
|
+
const title = model.name ?? model.uid;
|
|
120
|
+
const tagNames = (model.tags ?? [])
|
|
121
|
+
.map((t) => t?.name)
|
|
122
|
+
.filter((n) => typeof n === "string" && n.length > 0)
|
|
123
|
+
.flatMap((n) => tokenize(n));
|
|
124
|
+
const tags = Array.from(new Set([...tokenize(title), ...tagNames]));
|
|
125
|
+
return {
|
|
126
|
+
id: `sketchfab:${model.uid}`,
|
|
127
|
+
source: "sketchfab",
|
|
128
|
+
title,
|
|
129
|
+
description: model.description,
|
|
130
|
+
url,
|
|
131
|
+
access,
|
|
132
|
+
// glTF-archive downloads default to .glb when resolved by the bridge.
|
|
133
|
+
format: "glb",
|
|
134
|
+
license,
|
|
135
|
+
thumbnailUrl: bestThumbnail(model.thumbnails),
|
|
136
|
+
likeCount: typeof model.likeCount === "number" ? model.likeCount : undefined,
|
|
137
|
+
viewCount: typeof model.viewCount === "number" ? model.viewCount : undefined,
|
|
138
|
+
triangles: typeof model.faceCount === "number" ? model.faceCount : undefined,
|
|
139
|
+
tags,
|
|
140
|
+
sourcePage,
|
|
141
|
+
attribution: model.user?.displayName ?? model.user?.username,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export function createSketchfabAdapter(options = {}) {
|
|
145
|
+
// Resolve token presence once at construction. Absent token => degrade
|
|
146
|
+
// gracefully: search() returns [] without throwing. Present token only
|
|
147
|
+
// upgrades redistributable models to direct-download (the actual exchange
|
|
148
|
+
// happens later in the CLI pull bridge). An explicit option lets the Cloudflare
|
|
149
|
+
// Worker pass its secret binding without depending on `process.env`.
|
|
150
|
+
const envToken = typeof process !== "undefined" ? process.env?.SKETCHFAB_API_TOKEN : undefined;
|
|
151
|
+
const token = (options.token ?? envToken)?.trim();
|
|
152
|
+
const hasToken = typeof token === "string" && token.length > 0;
|
|
153
|
+
const maxPages = Math.max(1, options.maxPages ?? 1);
|
|
154
|
+
const throttleMs = Math.max(0, options.throttleMs ?? 0);
|
|
155
|
+
return {
|
|
156
|
+
id: "sketchfab",
|
|
157
|
+
label: "Sketchfab (downloadable, CC-licensed)",
|
|
158
|
+
async search(query, ctx) {
|
|
159
|
+
if (!hasToken) {
|
|
160
|
+
// No API token: cannot resolve downloads, so contribute nothing rather
|
|
161
|
+
// than surfacing deep-links we can never auto-pull.
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
const assets = [];
|
|
165
|
+
let url = buildSearchUrl(query);
|
|
166
|
+
for (let page = 0; page < maxPages && url; page++) {
|
|
167
|
+
if (page > 0 && throttleMs)
|
|
168
|
+
await new Promise((r) => setTimeout(r, throttleMs));
|
|
169
|
+
const raw = (await ctx.fetchJson(url));
|
|
170
|
+
for (const model of raw?.results ?? []) {
|
|
171
|
+
if (model && typeof model.uid === "string") {
|
|
172
|
+
const canonical = toCanonical(model, hasToken);
|
|
173
|
+
if (canonical)
|
|
174
|
+
assets.push(canonical);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
url = raw?.next; // cursor to the next page
|
|
178
|
+
}
|
|
179
|
+
return assets;
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=sketchfab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sketchfab.js","sourceRoot":"","sources":["../../../../../packages/asset-index/src/adapters/sketchfab.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { AuraCanonicalAsset } from "./CanonicalAsset.js";
|
|
2
|
+
/**
|
|
3
|
+
* Semantic-search upgrade seam over the keyword baseline in `ranking.ts`.
|
|
4
|
+
*
|
|
5
|
+
* The federation layer scores assets through a single seam (`scoreAsset`); this
|
|
6
|
+
* module provides the vector-embedding alternative the comment there promises.
|
|
7
|
+
* Everything here is dependency-free and fully deterministic: the default
|
|
8
|
+
* provider hashes tokens into a fixed-size vector, so the same text always
|
|
9
|
+
* yields the same embedding with no network, keys, randomness, or wall-clock
|
|
10
|
+
* time involved.
|
|
11
|
+
*/
|
|
12
|
+
/** Pluggable text embedder. Implementations must be deterministic per input. */
|
|
13
|
+
export interface EmbeddingProvider {
|
|
14
|
+
/** Embed each input string into a numeric vector of uniform dimension. */
|
|
15
|
+
embed(texts: readonly string[]): Promise<number[][]>;
|
|
16
|
+
}
|
|
17
|
+
/** Default embedding dimensionality for {@link LocalHashEmbedding}. */
|
|
18
|
+
export declare const DEFAULT_EMBEDDING_DIMS = 256;
|
|
19
|
+
/**
|
|
20
|
+
* Deterministic, dependency-free bag-of-words embedding.
|
|
21
|
+
*
|
|
22
|
+
* Each token is hashed into one of `dims` buckets and summed (sign derived from
|
|
23
|
+
* a second hash bit so unrelated tokens do not all push in the same direction),
|
|
24
|
+
* then the vector is L2-normalized. Identical text -> identical vector; cosine
|
|
25
|
+
* similarity of identical text is exactly 1.
|
|
26
|
+
*/
|
|
27
|
+
export declare class LocalHashEmbedding implements EmbeddingProvider {
|
|
28
|
+
readonly dims: number;
|
|
29
|
+
constructor(dims?: number);
|
|
30
|
+
private embedOne;
|
|
31
|
+
embed(texts: readonly string[]): Promise<number[][]>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Cosine similarity of two equal-length vectors. Returns 0 when either vector
|
|
35
|
+
* is all zeros or lengths differ. For L2-normalized vectors this equals the dot
|
|
36
|
+
* product, but we recompute norms so it is correct for any input.
|
|
37
|
+
*/
|
|
38
|
+
export declare function cosineSimilarity(a: readonly number[], b: readonly number[]): number;
|
|
39
|
+
/**
|
|
40
|
+
* Canonical text used to embed an asset: title, tags, then description. This is
|
|
41
|
+
* the same field set the ranking baseline scores against, concatenated so a
|
|
42
|
+
* bag-of-words embedding can capture all of them.
|
|
43
|
+
*/
|
|
44
|
+
export declare function assetEmbeddingText(asset: AuraCanonicalAsset): string;
|
|
45
|
+
/**
|
|
46
|
+
* Rank assets against a query by cosine similarity of their embeddings.
|
|
47
|
+
*
|
|
48
|
+
* Embeds the query and every asset's {@link assetEmbeddingText} in one batched
|
|
49
|
+
* call to the provider, then sorts descending by score. Ties break by asset id
|
|
50
|
+
* so the ordering is stable and deterministic.
|
|
51
|
+
*/
|
|
52
|
+
export declare function embeddingRanker(provider: EmbeddingProvider, query: string, assets: readonly AuraCanonicalAsset[]): Promise<{
|
|
53
|
+
asset: AuraCanonicalAsset;
|
|
54
|
+
score: number;
|
|
55
|
+
}[]>;
|
|
56
|
+
//# sourceMappingURL=embedding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../../../packages/asset-index/src/embedding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;;;;;;;;GASG;AAEH,gFAAgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,KAAK,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;CACtD;AAED,uEAAuE;AACvE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AA4B1C;;;;;;;GAOG;AACH,qBAAa,kBAAmB,YAAW,iBAAiB;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,GAAE,MAA+B;IAIjD,OAAO,CAAC,QAAQ;IAYV,KAAK,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;CAG3D;AAWD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAanF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAIpE;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,kBAAkB,EAAE,GACpC,OAAO,CAAC;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAiBzD"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/** Default embedding dimensionality for {@link LocalHashEmbedding}. */
|
|
2
|
+
export const DEFAULT_EMBEDDING_DIMS = 256;
|
|
3
|
+
/**
|
|
4
|
+
* Lowercase a string and split it into alphanumeric tokens, dropping single
|
|
5
|
+
* characters (matching the keyword baseline's `queryTerms`).
|
|
6
|
+
*/
|
|
7
|
+
function tokenize(text) {
|
|
8
|
+
return text
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.split(/[^a-z0-9]+/)
|
|
11
|
+
.filter((t) => t.length > 1);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Deterministic 32-bit FNV-1a hash of a string. Pure function of its input;
|
|
15
|
+
* no randomness or platform-dependent behavior.
|
|
16
|
+
*/
|
|
17
|
+
function fnv1a(token) {
|
|
18
|
+
let hash = 0x811c9dc5;
|
|
19
|
+
for (let i = 0; i < token.length; i++) {
|
|
20
|
+
hash ^= token.charCodeAt(i);
|
|
21
|
+
// FNV prime multiply via shifts to stay in 32-bit unsigned range.
|
|
22
|
+
hash = Math.imul(hash, 0x01000193);
|
|
23
|
+
}
|
|
24
|
+
// Coerce to unsigned 32-bit.
|
|
25
|
+
return hash >>> 0;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Deterministic, dependency-free bag-of-words embedding.
|
|
29
|
+
*
|
|
30
|
+
* Each token is hashed into one of `dims` buckets and summed (sign derived from
|
|
31
|
+
* a second hash bit so unrelated tokens do not all push in the same direction),
|
|
32
|
+
* then the vector is L2-normalized. Identical text -> identical vector; cosine
|
|
33
|
+
* similarity of identical text is exactly 1.
|
|
34
|
+
*/
|
|
35
|
+
export class LocalHashEmbedding {
|
|
36
|
+
dims;
|
|
37
|
+
constructor(dims = DEFAULT_EMBEDDING_DIMS) {
|
|
38
|
+
this.dims = dims > 0 ? Math.floor(dims) : DEFAULT_EMBEDDING_DIMS;
|
|
39
|
+
}
|
|
40
|
+
embedOne(text) {
|
|
41
|
+
const vec = new Array(this.dims).fill(0);
|
|
42
|
+
for (const token of tokenize(text)) {
|
|
43
|
+
const h = fnv1a(token);
|
|
44
|
+
const bucket = h % this.dims;
|
|
45
|
+
// Use a high bit as a stable sign so collisions are less likely to align.
|
|
46
|
+
const sign = (h & 0x80000000) !== 0 ? -1 : 1;
|
|
47
|
+
vec[bucket] += sign;
|
|
48
|
+
}
|
|
49
|
+
return l2Normalize(vec);
|
|
50
|
+
}
|
|
51
|
+
async embed(texts) {
|
|
52
|
+
return texts.map((t) => this.embedOne(t));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** L2-normalize a vector in place-safe fashion; zero vectors stay zero. */
|
|
56
|
+
function l2Normalize(vec) {
|
|
57
|
+
let sumSq = 0;
|
|
58
|
+
for (const v of vec)
|
|
59
|
+
sumSq += v * v;
|
|
60
|
+
const norm = Math.sqrt(sumSq);
|
|
61
|
+
if (norm === 0)
|
|
62
|
+
return vec;
|
|
63
|
+
return vec.map((v) => v / norm);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Cosine similarity of two equal-length vectors. Returns 0 when either vector
|
|
67
|
+
* is all zeros or lengths differ. For L2-normalized vectors this equals the dot
|
|
68
|
+
* product, but we recompute norms so it is correct for any input.
|
|
69
|
+
*/
|
|
70
|
+
export function cosineSimilarity(a, b) {
|
|
71
|
+
if (a.length !== b.length || a.length === 0)
|
|
72
|
+
return 0;
|
|
73
|
+
let dot = 0;
|
|
74
|
+
let normA = 0;
|
|
75
|
+
let normB = 0;
|
|
76
|
+
for (let i = 0; i < a.length; i++) {
|
|
77
|
+
dot += a[i] * b[i];
|
|
78
|
+
normA += a[i] * a[i];
|
|
79
|
+
normB += b[i] * b[i];
|
|
80
|
+
}
|
|
81
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
82
|
+
if (denom === 0)
|
|
83
|
+
return 0;
|
|
84
|
+
return dot / denom;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Canonical text used to embed an asset: title, tags, then description. This is
|
|
88
|
+
* the same field set the ranking baseline scores against, concatenated so a
|
|
89
|
+
* bag-of-words embedding can capture all of them.
|
|
90
|
+
*/
|
|
91
|
+
export function assetEmbeddingText(asset) {
|
|
92
|
+
const parts = [asset.title, asset.tags.join(" ")];
|
|
93
|
+
if (asset.description)
|
|
94
|
+
parts.push(asset.description);
|
|
95
|
+
return parts.join(" ");
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Rank assets against a query by cosine similarity of their embeddings.
|
|
99
|
+
*
|
|
100
|
+
* Embeds the query and every asset's {@link assetEmbeddingText} in one batched
|
|
101
|
+
* call to the provider, then sorts descending by score. Ties break by asset id
|
|
102
|
+
* so the ordering is stable and deterministic.
|
|
103
|
+
*/
|
|
104
|
+
export async function embeddingRanker(provider, query, assets) {
|
|
105
|
+
if (assets.length === 0)
|
|
106
|
+
return [];
|
|
107
|
+
const texts = [query, ...assets.map((a) => assetEmbeddingText(a))];
|
|
108
|
+
const vectors = await provider.embed(texts);
|
|
109
|
+
const queryVec = vectors[0];
|
|
110
|
+
const scored = assets.map((asset, i) => ({
|
|
111
|
+
asset,
|
|
112
|
+
score: cosineSimilarity(queryVec, vectors[i + 1]),
|
|
113
|
+
}));
|
|
114
|
+
scored.sort((x, y) => {
|
|
115
|
+
if (y.score !== x.score)
|
|
116
|
+
return y.score - x.score;
|
|
117
|
+
return x.asset.id < y.asset.id ? -1 : x.asset.id > y.asset.id ? 1 : 0;
|
|
118
|
+
});
|
|
119
|
+
return scored;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=embedding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../../../packages/asset-index/src/embedding.ts"],"names":[],"mappings":"AAmBA,uEAAuE;AACvE,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C;;;GAGG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI;SACR,WAAW,EAAE;SACb,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,SAAS,KAAK,CAAC,KAAa;IAC1B,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC5B,kEAAkE;QAClE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC;IACD,6BAA6B;IAC7B,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,kBAAkB;IACpB,IAAI,CAAS;IAEtB,YAAY,OAAe,sBAAsB;QAC/C,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC;IACnE,CAAC;IAEO,QAAQ,CAAC,IAAY;QAC3B,MAAM,GAAG,GAAG,IAAI,KAAK,CAAS,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;YACvB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;YAC7B,0EAA0E;YAC1E,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7C,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;QACtB,CAAC;QACD,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAwB;QAClC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;CACF;AAED,2EAA2E;AAC3E,SAAS,WAAW,CAAC,GAAa;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,GAAG;QAAE,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAC3B,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAoB,EAAE,CAAoB;IACzE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtD,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1B,OAAO,GAAG,GAAG,KAAK,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,IAAI,KAAK,CAAC,WAAW;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAA2B,EAC3B,KAAa,EACb,MAAqC;IAErC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE5B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACvC,KAAK;QACL,KAAK,EAAE,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;KAClD,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnB,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QAClD,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { AuraCanonicalAsset } from "./CanonicalAsset.js";
|
|
2
|
+
import type { FetchJson, ResolveQuery, SourceAdapter } from "./SourceAdapter.js";
|
|
3
|
+
export interface ResolveCandidate {
|
|
4
|
+
readonly asset: AuraCanonicalAsset;
|
|
5
|
+
readonly score: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ResolveResult {
|
|
8
|
+
readonly query: ResolveQuery;
|
|
9
|
+
readonly candidates: readonly ResolveCandidate[];
|
|
10
|
+
/** Non-fatal per-source failures, so a dead source is visible, not silent. */
|
|
11
|
+
readonly warnings: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Optional ranking seam. When provided, it replaces the default keyword
|
|
15
|
+
* `scoreAsset` ordering with a custom (e.g. semantic-embedding) ranker. It
|
|
16
|
+
* receives the constraint-filtered candidate pool and returns each asset paired
|
|
17
|
+
* with a score, already ordered best-first. The resolver consumes that order
|
|
18
|
+
* directly. See `embeddingRanker` in `embedding.ts` for the default semantic
|
|
19
|
+
* implementation (partially apply its `provider` to match this signature).
|
|
20
|
+
*/
|
|
21
|
+
export type Ranker = (query: string, assets: readonly AuraCanonicalAsset[]) => Promise<{
|
|
22
|
+
asset: AuraCanonicalAsset;
|
|
23
|
+
score: number;
|
|
24
|
+
}[]>;
|
|
25
|
+
export interface FederatedResolverOptions {
|
|
26
|
+
readonly adapters: readonly SourceAdapter[];
|
|
27
|
+
readonly fetchJson?: FetchJson;
|
|
28
|
+
/** Max candidates returned after ranking. Default 10. */
|
|
29
|
+
readonly limit?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Optional ranking override. Defaults to the keyword `scoreAsset` path when
|
|
32
|
+
* undefined, preserving existing behavior exactly.
|
|
33
|
+
*/
|
|
34
|
+
readonly ranker?: Ranker;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Federates a query across every configured source adapter in parallel,
|
|
38
|
+
* normalizes + constraint-filters + ranks the merged pool, and returns the top
|
|
39
|
+
* candidates. A source that throws contributes a warning instead of failing the
|
|
40
|
+
* whole resolve — federation degrades, it does not collapse.
|
|
41
|
+
*/
|
|
42
|
+
export declare class FederatedResolver {
|
|
43
|
+
private readonly adapters;
|
|
44
|
+
private readonly ctx;
|
|
45
|
+
private readonly limit;
|
|
46
|
+
private readonly ranker?;
|
|
47
|
+
constructor(options: FederatedResolverOptions);
|
|
48
|
+
resolve(query: ResolveQuery): Promise<ResolveResult>;
|
|
49
|
+
/**
|
|
50
|
+
* Rank the filtered pool through an injected ranker, consuming its returned
|
|
51
|
+
* order directly. Ties are re-broken by id so the ordering stays stable and
|
|
52
|
+
* deterministic even if the ranker leaves equal scores unordered.
|
|
53
|
+
*/
|
|
54
|
+
private rankWith;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=federate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federate.d.ts","sourceRoot":"","sources":["../../../../packages/asset-index/src/federate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAEV,SAAS,EACT,YAAY,EACZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACjD,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG,CACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,kBAAkB,EAAE,KAClC,OAAO,CAAC;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAAC;AAE7D,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IACpD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAiB;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;gBAErB,OAAO,EAAE,wBAAwB;IAOvC,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAoC1D;;;;OAIG;YACW,QAAQ;CAYvB"}
|
package/dist/federate.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { defaultFetchJson } from "./SourceAdapter.js";
|
|
2
|
+
import { matchesConstraints, scoreAsset } from "./ranking.js";
|
|
3
|
+
/**
|
|
4
|
+
* Federates a query across every configured source adapter in parallel,
|
|
5
|
+
* normalizes + constraint-filters + ranks the merged pool, and returns the top
|
|
6
|
+
* candidates. A source that throws contributes a warning instead of failing the
|
|
7
|
+
* whole resolve — federation degrades, it does not collapse.
|
|
8
|
+
*/
|
|
9
|
+
export class FederatedResolver {
|
|
10
|
+
adapters;
|
|
11
|
+
ctx;
|
|
12
|
+
limit;
|
|
13
|
+
ranker;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.adapters = options.adapters;
|
|
16
|
+
this.ctx = { fetchJson: options.fetchJson ?? defaultFetchJson };
|
|
17
|
+
this.limit = options.limit ?? 10;
|
|
18
|
+
this.ranker = options.ranker;
|
|
19
|
+
}
|
|
20
|
+
async resolve(query) {
|
|
21
|
+
const warnings = [];
|
|
22
|
+
const perAdapter = await Promise.all(this.adapters.map(async (adapter) => {
|
|
23
|
+
try {
|
|
24
|
+
return await adapter.search(query, this.ctx);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
warnings.push(`${adapter.id}: ${err.message}`);
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
// Dedupe by id and apply constraint filtering once; both the keyword and the
|
|
32
|
+
// injected-ranker paths rank over this same filtered pool.
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
const pool = [];
|
|
35
|
+
for (const asset of perAdapter.flat()) {
|
|
36
|
+
if (seen.has(asset.id))
|
|
37
|
+
continue;
|
|
38
|
+
seen.add(asset.id);
|
|
39
|
+
if (!matchesConstraints(asset, query.constraints))
|
|
40
|
+
continue;
|
|
41
|
+
pool.push(asset);
|
|
42
|
+
}
|
|
43
|
+
const candidates = this.ranker
|
|
44
|
+
? await this.rankWith(this.ranker, query.text, pool)
|
|
45
|
+
: rankByKeyword(query.text, pool);
|
|
46
|
+
return {
|
|
47
|
+
query,
|
|
48
|
+
candidates: candidates.slice(0, this.limit),
|
|
49
|
+
warnings,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Rank the filtered pool through an injected ranker, consuming its returned
|
|
54
|
+
* order directly. Ties are re-broken by id so the ordering stays stable and
|
|
55
|
+
* deterministic even if the ranker leaves equal scores unordered.
|
|
56
|
+
*/
|
|
57
|
+
async rankWith(ranker, text, pool) {
|
|
58
|
+
const ranked = await ranker(text, pool);
|
|
59
|
+
const candidates = ranked.map(({ asset, score }) => ({ asset, score }));
|
|
60
|
+
candidates.sort((a, b) => b.score - a.score || a.asset.id.localeCompare(b.asset.id));
|
|
61
|
+
return candidates;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Default keyword ranking: score via `scoreAsset`, drop zero-score assets, and
|
|
66
|
+
* order by score descending with an id tie-break for determinism. This preserves
|
|
67
|
+
* the resolver's pre-seam behavior exactly.
|
|
68
|
+
*/
|
|
69
|
+
function rankByKeyword(text, pool) {
|
|
70
|
+
const candidates = [];
|
|
71
|
+
for (const asset of pool) {
|
|
72
|
+
const score = scoreAsset(asset, text);
|
|
73
|
+
if (score <= 0)
|
|
74
|
+
continue;
|
|
75
|
+
candidates.push({ asset, score });
|
|
76
|
+
}
|
|
77
|
+
candidates.sort((a, b) => b.score - a.score || a.asset.id.localeCompare(b.asset.id));
|
|
78
|
+
return candidates;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=federate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federate.js","sourceRoot":"","sources":["../../../../packages/asset-index/src/federate.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aura3d/asset-index
|
|
3
|
+
*
|
|
4
|
+
* Live federated search over the free GLB/glTF universe. Source adapters
|
|
5
|
+
* normalize each library's native catalog into one {@link AuraCanonicalAsset}
|
|
6
|
+
* shape; the {@link FederatedResolver} fans a natural-language query across them,
|
|
7
|
+
* constraint-filters, ranks, and returns auto-pullable candidates.
|
|
8
|
+
*
|
|
9
|
+
* This package is the catalog. It is intentionally separate from `@aura3d/engine`
|
|
10
|
+
* (which stays a pipeline): the engine's prompt-plan `subject.intent` seam calls
|
|
11
|
+
* a resolver from here, and the CLI pulls a chosen candidate through the normal
|
|
12
|
+
* `assets add` flow.
|
|
13
|
+
*/
|
|
14
|
+
export type { AuraCanonicalAsset, AuraAssetLicense, AuraAssetLicenseSpdx, AuraAssetFormat, AuraAssetAccess, AuraAssetBounds, } from "./CanonicalAsset.js";
|
|
15
|
+
export { isAutoPullable, normalizeLicense } from "./CanonicalAsset.js";
|
|
16
|
+
export type { SourceAdapter, AdapterContext, AdapterRefreshResult, FetchJson, ResolveQuery, ResolveConstraints, } from "./SourceAdapter.js";
|
|
17
|
+
export { defaultFetchJson } from "./SourceAdapter.js";
|
|
18
|
+
export { scoreAsset, matchesConstraints } from "./ranking.js";
|
|
19
|
+
export type { ResolveCandidate, ResolveResult, FederatedResolverOptions, } from "./federate.js";
|
|
20
|
+
export { FederatedResolver } from "./federate.js";
|
|
21
|
+
export { createKhronosAdapter } from "./adapters/khronos.js";
|
|
22
|
+
export { createOS3AAdapter } from "./adapters/os3a.js";
|
|
23
|
+
export { createPolyHavenAdapter } from "./adapters/poly-haven.js";
|
|
24
|
+
export { createPolyPizzaAdapter } from "./adapters/poly-pizza.js";
|
|
25
|
+
export type { PolyPizzaAdapterOptions } from "./adapters/poly-pizza.js";
|
|
26
|
+
export { createSketchfabAdapter } from "./adapters/sketchfab.js";
|
|
27
|
+
export type { SketchfabAdapterOptions } from "./adapters/sketchfab.js";
|
|
28
|
+
export { createMarketplaceDeepLinkAdapter } from "./adapters/marketplace.js";
|
|
29
|
+
export { createJsDelivrMirrorAdapter } from "./adapters/jsdelivr-mirror.js";
|
|
30
|
+
export type { JsDelivrMirrorOptions } from "./adapters/jsdelivr-mirror.js";
|
|
31
|
+
export { createAuraIndexAdapter } from "./adapters/aura-index.js";
|
|
32
|
+
export type { AuraIndexAdapterOptions } from "./adapters/aura-index.js";
|
|
33
|
+
export { IndexStore, INDEX_STORE_SCHEMA } from "./IndexStore.js";
|
|
34
|
+
export type { IndexStoreFile } from "./IndexStore.js";
|
|
35
|
+
export { refreshIndex } from "./refresh.js";
|
|
36
|
+
export type { RefreshResult, RefreshOptions, WritableAssetIndex } from "./refresh.js";
|
|
37
|
+
export { LocalHashEmbedding, cosineSimilarity, assetEmbeddingText, embeddingRanker, DEFAULT_EMBEDDING_DIMS, } from "./embedding.js";
|
|
38
|
+
export type { EmbeddingProvider } from "./embedding.js";
|
|
39
|
+
import type { SourceAdapter } from "./SourceAdapter.js";
|
|
40
|
+
/**
|
|
41
|
+
* The zero-auth, verified source adapters available today.
|
|
42
|
+
*
|
|
43
|
+
* These are the no-key, redistributable-by-default sources safe to run in the
|
|
44
|
+
* auto-pull federation pass. Key-gated sources (Sketchfab, Poly Pizza) and the
|
|
45
|
+
* discovery-only marketplace deep-link adapter are intentionally excluded — they
|
|
46
|
+
* are opt-in, not auto-pull sources.
|
|
47
|
+
*
|
|
48
|
+
* `createJsDelivrMirrorAdapter` surfaces CC0 GLBs that the extraction pipeline
|
|
49
|
+
* mirrored from ZIP-pack sources (Kenney, Quaternius, curated OpenGameArt) into
|
|
50
|
+
* the public mirror repo, served free via jsDelivr.
|
|
51
|
+
*/
|
|
52
|
+
export declare function defaultAdapters(): SourceAdapter[];
|
|
53
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/asset-index/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvE,YAAY,EACV,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,SAAS,EACT,YAAY,EACZ,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE9D,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,YAAY,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,YAAY,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEtF,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMxD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,IAAI,aAAa,EAAE,CAOjD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aura3d/asset-index
|
|
3
|
+
*
|
|
4
|
+
* Live federated search over the free GLB/glTF universe. Source adapters
|
|
5
|
+
* normalize each library's native catalog into one {@link AuraCanonicalAsset}
|
|
6
|
+
* shape; the {@link FederatedResolver} fans a natural-language query across them,
|
|
7
|
+
* constraint-filters, ranks, and returns auto-pullable candidates.
|
|
8
|
+
*
|
|
9
|
+
* This package is the catalog. It is intentionally separate from `@aura3d/engine`
|
|
10
|
+
* (which stays a pipeline): the engine's prompt-plan `subject.intent` seam calls
|
|
11
|
+
* a resolver from here, and the CLI pulls a chosen candidate through the normal
|
|
12
|
+
* `assets add` flow.
|
|
13
|
+
*/
|
|
14
|
+
export { isAutoPullable, normalizeLicense } from "./CanonicalAsset.js";
|
|
15
|
+
export { defaultFetchJson } from "./SourceAdapter.js";
|
|
16
|
+
export { scoreAsset, matchesConstraints } from "./ranking.js";
|
|
17
|
+
export { FederatedResolver } from "./federate.js";
|
|
18
|
+
export { createKhronosAdapter } from "./adapters/khronos.js";
|
|
19
|
+
export { createOS3AAdapter } from "./adapters/os3a.js";
|
|
20
|
+
export { createPolyHavenAdapter } from "./adapters/poly-haven.js";
|
|
21
|
+
export { createPolyPizzaAdapter } from "./adapters/poly-pizza.js";
|
|
22
|
+
export { createSketchfabAdapter } from "./adapters/sketchfab.js";
|
|
23
|
+
export { createMarketplaceDeepLinkAdapter } from "./adapters/marketplace.js";
|
|
24
|
+
export { createJsDelivrMirrorAdapter } from "./adapters/jsdelivr-mirror.js";
|
|
25
|
+
export { createAuraIndexAdapter } from "./adapters/aura-index.js";
|
|
26
|
+
export { IndexStore, INDEX_STORE_SCHEMA } from "./IndexStore.js";
|
|
27
|
+
export { refreshIndex } from "./refresh.js";
|
|
28
|
+
export { LocalHashEmbedding, cosineSimilarity, assetEmbeddingText, embeddingRanker, DEFAULT_EMBEDDING_DIMS, } from "./embedding.js";
|
|
29
|
+
import { createKhronosAdapter } from "./adapters/khronos.js";
|
|
30
|
+
import { createOS3AAdapter } from "./adapters/os3a.js";
|
|
31
|
+
import { createPolyHavenAdapter } from "./adapters/poly-haven.js";
|
|
32
|
+
import { createJsDelivrMirrorAdapter } from "./adapters/jsdelivr-mirror.js";
|
|
33
|
+
/**
|
|
34
|
+
* The zero-auth, verified source adapters available today.
|
|
35
|
+
*
|
|
36
|
+
* These are the no-key, redistributable-by-default sources safe to run in the
|
|
37
|
+
* auto-pull federation pass. Key-gated sources (Sketchfab, Poly Pizza) and the
|
|
38
|
+
* discovery-only marketplace deep-link adapter are intentionally excluded — they
|
|
39
|
+
* are opt-in, not auto-pull sources.
|
|
40
|
+
*
|
|
41
|
+
* `createJsDelivrMirrorAdapter` surfaces CC0 GLBs that the extraction pipeline
|
|
42
|
+
* mirrored from ZIP-pack sources (Kenney, Quaternius, curated OpenGameArt) into
|
|
43
|
+
* the public mirror repo, served free via jsDelivr.
|
|
44
|
+
*/
|
|
45
|
+
export function defaultAdapters() {
|
|
46
|
+
return [
|
|
47
|
+
createKhronosAdapter(),
|
|
48
|
+
createOS3AAdapter(),
|
|
49
|
+
createPolyHavenAdapter(),
|
|
50
|
+
createJsDelivrMirrorAdapter(),
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/asset-index/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAUvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAO9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,oBAAoB,EAAE;QACtB,iBAAiB,EAAE;QACnB,sBAAsB,EAAE;QACxB,2BAA2B,EAAE;KAC9B,CAAC;AACJ,CAAC"}
|