mirror of
https://github.com/hanzoai/insights.git
synced 2026-11-03 00:52:32 +00:00
Every first-party Python caller and test now names the mount the API actually answers on. Mechanical: URL literals only, and only where the /api/ was ours -- a preceding word character means it was a module path like insights/api/ or a third-party host like slack.com/api/, and those are untouched. Left saying /api/, each for a reason rather than for safety: - products/warehouse_sources/.../sources/** is a catalogue of vendor endpoints - services/llm-gateway deploys separately and is under a code freeze, so moving its two calls would break it during the skew - the mcp_store and Slack/Teams redirect_uris are registered with third parties and must byte-match what was registered - the Wizard and Raycast client-metadata paths are OAuth client_ids - /api/surveys and /api/feature_flag/local_evaluation are SDK aliases the ingress routes to the Rust fleets, held by released SDK versions Test URLconfs moved with the requests that call them, and the Datastore user-selection fixtures now carry the leading slash that request.path has.
53 lines
2.0 KiB
TypeScript
53 lines
2.0 KiB
TypeScript
import { parseAiBlobPointer, resolveAiBlobUrl, resolveDataUri } from './aiBlob'
|
|
|
|
const HASH = 'a'.repeat(64)
|
|
const POINTER = `phaiblob://v1/sha256/${HASH}?mime=image%2Fpng&size=131072`
|
|
|
|
describe('aiBlob', () => {
|
|
it('parses a pointer', () => {
|
|
expect(parseAiBlobPointer(POINTER)).toEqual({
|
|
version: 'v1',
|
|
algo: 'sha256',
|
|
hash: HASH,
|
|
mime: 'image/png',
|
|
size: 131072,
|
|
})
|
|
})
|
|
|
|
it('resolves a pointer to the environment endpoint', () => {
|
|
expect(resolveAiBlobUrl(POINTER, 1)).toBe(`/v1/projects/1/ai_blob/v1/sha256/${HASH}`)
|
|
})
|
|
|
|
it.each([
|
|
['http url', 'https://example.com/a.png'],
|
|
['data uri', 'data:image/png;base64,AAAA'],
|
|
['plain text', 'hello'],
|
|
['bad hash', 'phaiblob://v1/sha256/xyz?mime=a&size=1'],
|
|
['unknown algo', `phaiblob://v1/md5/${HASH}?mime=a&size=1`],
|
|
['old scheme', `phblob://v1/sha256/${HASH}?mime=a&size=1`],
|
|
])('passes through unchanged: %s', (_name, value) => {
|
|
expect(parseAiBlobPointer(value)).toBeNull()
|
|
expect(resolveAiBlobUrl(value, 1)).toBe(value)
|
|
})
|
|
|
|
it('passes through when teamId is missing', () => {
|
|
expect(resolveAiBlobUrl(POINTER, null)).toBe(POINTER)
|
|
})
|
|
|
|
it.each([
|
|
['image/png', `data:image/png;base64,${POINTER}`],
|
|
['application/pdf', `data:application/pdf;base64,${POINTER}`],
|
|
])('resolves a pointer that a recipe wrapped in a %s data uri', (_mime, wrapped) => {
|
|
expect(parseAiBlobPointer(wrapped)).toMatchObject({ hash: HASH })
|
|
expect(resolveAiBlobUrl(wrapped, 1)).toBe(`/v1/projects/1/ai_blob/v1/sha256/${HASH}`)
|
|
})
|
|
|
|
it('resolves a pointer data field to the blob endpoint, ignoring the passed mime type', () => {
|
|
expect(resolveDataUri(POINTER, 'image/png', 1)).toBe(`/v1/projects/1/ai_blob/v1/sha256/${HASH}`)
|
|
})
|
|
|
|
it('builds a data: URI from raw base64 when the data field is not a pointer', () => {
|
|
expect(resolveDataUri('AAAA', 'image/png', 1)).toBe('data:image/png;base64,AAAA')
|
|
})
|
|
})
|