@bagelink/vue 1.17.2 → 1.17.6

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 (95) hide show
  1. package/dist/assetTransport.d.ts +9 -31
  2. package/dist/assetTransport.d.ts.map +1 -1
  3. package/dist/assets.d.ts +39 -20
  4. package/dist/assets.d.ts.map +1 -1
  5. package/dist/components/AddressSearch.vue.d.ts +40 -36
  6. package/dist/components/AddressSearch.vue.d.ts.map +1 -1
  7. package/dist/components/ContextMenu.vue.d.ts +518 -0
  8. package/dist/components/ContextMenu.vue.d.ts.map +1 -0
  9. package/dist/components/Dropdown.types.d.ts +25 -0
  10. package/dist/components/Dropdown.types.d.ts.map +1 -0
  11. package/dist/components/Dropdown.vue.d.ts +20 -15
  12. package/dist/components/Dropdown.vue.d.ts.map +1 -1
  13. package/dist/components/FilterQuery.vue.d.ts +1 -1
  14. package/dist/components/FilterQuery.vue.d.ts.map +1 -1
  15. package/dist/components/Icon/Icon.vue.d.ts +0 -1
  16. package/dist/components/Icon/Icon.vue.d.ts.map +1 -1
  17. package/dist/components/Icon/constants.d.ts +0 -1
  18. package/dist/components/Icon/constants.d.ts.map +1 -1
  19. package/dist/components/Icon/types.d.ts +2 -3
  20. package/dist/components/Icon/types.d.ts.map +1 -1
  21. package/dist/components/Swiper.vue.d.ts +1 -1
  22. package/dist/components/draggable/useDraggable.d.ts.map +1 -1
  23. package/dist/components/form/inputs/IconPickerInput.vue.d.ts +48 -37
  24. package/dist/components/form/inputs/IconPickerInput.vue.d.ts.map +1 -1
  25. package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
  26. package/dist/components/form/inputs/RichText/composables/useCommands.d.ts.map +1 -1
  27. package/dist/components/form/inputs/RichText/composables/useEditor.d.ts +3 -0
  28. package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -1
  29. package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts +1 -1
  30. package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -1
  31. package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
  32. package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
  33. package/dist/components/form/inputs/RichText/utils/selection.d.ts +2 -0
  34. package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -1
  35. package/dist/components/form/inputs/RichText/utils/table.d.ts +34 -8
  36. package/dist/components/form/inputs/RichText/utils/table.d.ts.map +1 -1
  37. package/dist/components/form/inputs/SelectInput.vue.d.ts +71 -63
  38. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  39. package/dist/components/form/inputs/TelInput.vue.d.ts +2 -2
  40. package/dist/components/index.d.ts +3 -1
  41. package/dist/components/index.d.ts.map +1 -1
  42. package/dist/composables/index.d.ts +1 -1
  43. package/dist/composables/index.d.ts.map +1 -1
  44. package/dist/composables/useBoundedRectDrag.d.ts.map +1 -1
  45. package/dist/composables/usePointerSession.d.ts +14 -3
  46. package/dist/composables/usePointerSession.d.ts.map +1 -1
  47. package/dist/core.css +3 -3
  48. package/dist/directives/vResize.d.ts.map +1 -1
  49. package/dist/form-flow/form-flow.d.ts +4 -2
  50. package/dist/form-flow/form-flow.d.ts.map +1 -1
  51. package/dist/form-flow/schema-fields.d.ts +4 -1
  52. package/dist/form-flow/schema-fields.d.ts.map +1 -1
  53. package/dist/index.cjs +240 -153
  54. package/dist/index.css +1 -1
  55. package/dist/index.mjs +18459 -18281
  56. package/dist/style.css +3 -3
  57. package/dist/types/BagelForm.d.ts +2 -0
  58. package/dist/types/BagelForm.d.ts.map +1 -1
  59. package/package.json +1 -1
  60. package/src/assetTransport.test.ts +33 -83
  61. package/src/assetTransport.ts +24 -90
  62. package/src/assets.test.ts +58 -99
  63. package/src/assets.ts +78 -161
  64. package/src/components/ContextMenu.vue +113 -0
  65. package/src/components/Dropdown.types.ts +27 -0
  66. package/src/components/Dropdown.vue +129 -64
  67. package/src/components/FilterQuery.vue +1 -1
  68. package/src/components/Icon/Icon.vue +8 -30
  69. package/src/components/Icon/constants.ts +0 -166
  70. package/src/components/Icon/types.ts +2 -3
  71. package/src/components/draggable/useDraggable.ts +67 -100
  72. package/src/components/form/inputs/IconPickerInput.vue +14 -9
  73. package/src/components/form/inputs/RichText/components/EditorToolbar.vue +43 -111
  74. package/src/components/form/inputs/RichText/composables/useCommands.ts +32 -54
  75. package/src/components/form/inputs/RichText/composables/useEditor.ts +45 -171
  76. package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +90 -14
  77. package/src/components/form/inputs/RichText/index.vue +1195 -1210
  78. package/src/components/form/inputs/RichText/utils/commands.ts +689 -1028
  79. package/src/components/form/inputs/RichText/utils/selection.ts +66 -41
  80. package/src/components/form/inputs/RichText/utils/table.ts +798 -136
  81. package/src/components/form/inputs/SelectInput.vue +1 -1
  82. package/src/components/form/inputs/Upload/AssetUploadInput.vue +2 -2
  83. package/src/components/index.ts +3 -1
  84. package/src/composables/index.ts +1 -1
  85. package/src/composables/useBoundedRectDrag.ts +9 -12
  86. package/src/composables/usePointerSession.ts +57 -12
  87. package/src/directives/vResize.ts +6 -7
  88. package/src/form-flow/form-flow.ts +8 -3
  89. package/src/form-flow/schema-fields.ts +9 -4
  90. package/src/styles/core.css +1 -18
  91. package/src/types/BagelForm.ts +2 -0
  92. package/dist/components/form/inputs/RichText/utils/formatting.d.ts +0 -10
  93. package/dist/components/form/inputs/RichText/utils/formatting.d.ts.map +0 -1
  94. package/src/components/form/inputs/RichText/components/gridBox.vue +0 -58
  95. package/src/components/form/inputs/RichText/utils/formatting.ts +0 -331
@@ -100,6 +100,8 @@ export interface UploadInputValueObject {
100
100
  export interface UploadInputProps extends BagelInputShellProps {
101
101
  /** Opt-in stable reference output; defaults to legacy path-key behavior. */
102
102
  assetMode?: boolean;
103
+ /** Asset delivery policy. Defaults to protected; website/media fields use public. */
104
+ assetVisibility?: import('../assets').AssetVisibility;
103
105
  id?: string;
104
106
  name?: string;
105
107
  label?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"BagelForm.d.ts","sourceRoot":"","sources":["../../src/types/BagelForm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BagelForm.d.ts","sourceRoot":"","sources":["../../src/types/BagelForm.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "1.17.2",
4
+ "version": "1.17.6",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -4,56 +4,16 @@ import { createAssetClient } from './assets'
4
4
  import type { ApiTransport } from '@bagelink/sdk'
5
5
  import { createApp, ref } from 'vue'
6
6
 
7
- const session = { asset_id: 'a', version_id: 'v', upload_id: 'u', status: 'ready' }
7
+ const session = { asset_id: 'a', upload_id: 'u', status: 'ready' }
8
8
  const json = (value: unknown, status = 200) => new Response(JSON.stringify(value), { status })
9
9
  const signal = () => new AbortController().signal
10
10
 
11
11
  describe('asset REST transport', () => {
12
- it('reuses authenticated transport and synchronously invalidates on tenant changes', async () => {
13
- const request = vi.fn().mockImplementation(() => new Promise(() => {}))
14
- const transport = { axios: { defaults: { baseURL: 'https://api.example/api' }, request } } as unknown as ApiTransport
15
- const sessionKey = ref('account:tenant-a')
16
- const assets = configureAssetClient({ transport, sessionKey })
17
- createApp({}).use(assets)
18
- const result = assets.client.resolve({ asset_id: 'a', representation: 'website' })
19
- const rejected = expect(result).rejects.toMatchObject({ name: 'AbortError' })
20
- await Promise.resolve()
21
- expect(request.mock.calls[0]![0].url).toBe('assets/resolve')
22
- expect(JSON.parse(request.mock.calls[0]![0].data).references[0].representation).toBe('website')
23
- sessionKey.value = 'account:tenant-b'
24
- await rejected
25
- expect(request.mock.calls[0]![0].signal.aborted).toBe(true)
26
- })
27
-
28
- it('publishes only explicit image purposes with stable version-pinned URLs', async () => {
29
- const fetcher = vi.fn<AssetFetch>().mockResolvedValue(json({
30
- asset_id: 'a', version_id: 'v', published: true, name: 'photo',
31
- representations: ['website', 'social'].map(representation => ({
32
- representation, url: `/assets/a/public/v/${representation}`, media_type: 'image/jpeg', size: 42,
33
- })),
34
- }))
35
- const transport = createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
36
- const result = await transport.publish({ asset_id: 'a', version_id: 'v' })
37
- expect(JSON.parse(String(fetcher.mock.calls[0]![1]?.body))).toEqual({
38
- published: true, version_id: 'v', representations: ['website', 'social'],
39
- })
40
- expect(result.representations[1]?.url).toBe('https://api.example/assets/a/public/v/social')
41
- })
42
-
43
- it('rejects private grant URLs returned by publication', async () => {
44
- const fetcher = vi.fn<AssetFetch>().mockResolvedValue(json({
45
- asset_id: 'a', version_id: 'v', published: true,
46
- representations: [{ representation: 'website', url: '/assets/a/content?token=secret' }],
47
- }))
48
- await expect(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
49
- .publish({ asset_id: 'a', version_id: 'v' })).rejects.toThrow('Invalid public')
50
- })
51
-
52
- it('starts a session and sends unchanged raw bytes, returning pinned references', async () => {
12
+ it('starts a session and sends unchanged raw bytes, returning the public id', async () => {
53
13
  const fetcher = vi.fn<AssetFetch>().mockResolvedValueOnce(json(session)).mockResolvedValueOnce(json(session))
54
14
  const transport = createAssetHttpTransport({ baseURL: 'https://api.example/api', fetch: fetcher })
55
15
  const file = new File(['original'], 'test.heic')
56
- expect(await transport.upload(file, signal())).toEqual({ asset_id: 'a', version_id: 'v' })
16
+ expect(await transport.upload(file, signal())).toEqual({ asset_id: 'a' })
57
17
  expect(String(fetcher.mock.calls[0]![0])).toBe('https://api.example/api/assets/uploads')
58
18
  expect(fetcher.mock.calls[0]![1]?.body).toBe('{"name":"test.heic"}')
59
19
  expect(fetcher.mock.calls[1]![1]?.body).toBe(file)
@@ -65,30 +25,7 @@ describe('asset REST transport', () => {
65
25
  .mockResolvedValueOnce(json({ ...session, status: 'rejected' })).mockResolvedValueOnce(json({}, 403))
66
26
  const transport = createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
67
27
  await expect(transport.upload(new File(['x'], 'x'), signal())).rejects.toThrow('not ready')
68
- await expect(transport.resolve([{ asset_id: 'a' }], signal())).rejects.toThrow('(403)')
69
- })
70
-
71
- it('chunks 101 references and resolves relative URLs against the API origin', async () => {
72
- const fetcher = vi.fn<AssetFetch>(async (_url, init) => {
73
- const { references } = JSON.parse(String(init?.body)) as { references: { asset_id: string }[] }
74
- return json({ items: references.map(reference => ({
75
- ...reference, version_id: 'v', representation: 'original',
76
- url: '/assets/content?token=secret', expires_at: new Date(Date.now() + 60000).toISOString(),
77
- })) })
78
- })
79
- const transport = createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
80
- const items = await transport.resolve(Array.from({ length: 101 }, (_, i) => ({ asset_id: String(i) })), signal())
81
- expect(fetcher.mock.calls.map(call => JSON.parse(String(call[1]?.body)).references.length)).toEqual([50, 50, 1])
82
- expect(items).toHaveLength(101)
83
- expect(items[0]?.url).toBe('https://api.example/assets/content?token=secret')
84
- })
85
-
86
- it('rejects untrusted delivery origins', async () => {
87
- const fetcher = vi.fn<AssetFetch>().mockResolvedValue(json({ items: [{
88
- asset_id: 'a', version_id: 'v', representation: 'original', url: '//evil.example/file',
89
- }] }))
90
- await expect(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
91
- .resolve([{ asset_id: 'a' }], signal())).rejects.toThrow('Untrusted')
28
+ await expect(transport.upload(new File(['x'], 'x'), signal())).rejects.toThrow('(403)')
92
29
  })
93
30
 
94
31
  it('does not PUT if session creation fails', async () => {
@@ -98,28 +35,41 @@ describe('asset REST transport', () => {
98
35
  expect(fetcher).toHaveBeenCalledTimes(1)
99
36
  })
100
37
 
101
- it('does not complete an upload after session cancellation', async () => {
38
+ it('configureAssetClient provides a client that builds public URLs', () => {
39
+ const transport = { axios: { defaults: { baseURL: 'https://api.example/api' }, request: vi.fn() } } as unknown as ApiTransport
40
+ const assets = configureAssetClient({ transport, deliveryBaseUrl: 'https://cdn.bgl.dev/auctentic' })
41
+ expect(assets.client.assetUrl({ asset_id: 'a' })).toBe('https://cdn.bgl.dev/auctentic/a')
42
+ expect(assets.client.assetUrl({ asset_id: 'a' }, 'website')).toBe('https://cdn.bgl.dev/auctentic/a?fmt=webp')
43
+ expect(assets.client.assetUrl({ asset_id: 'a' }, 'social')).toBe('https://cdn.bgl.dev/auctentic/a?w=1200&h=630&fmt=jpeg&fit=cover')
44
+ })
45
+
46
+ it('clears in-flight uploads on session change', async () => {
47
+ let requestSignal: AbortSignal | null | undefined
48
+ const fetcher = vi.fn<AssetFetch>((config: any) => {
49
+ requestSignal = config?.signal
50
+ return new Promise((_resolve, reject) => requestSignal?.addEventListener('abort', () => reject(requestSignal?.reason))
51
+ )
52
+ })
53
+ const transport = { axios: { defaults: { baseURL: 'https://api.example' }, request: fetcher } } as unknown as ApiTransport
54
+ const sessionKey = ref('a')
55
+ const assets = configureAssetClient({ transport, deliveryBaseUrl: 'https://cdn.bgl.dev/auctentic', sessionKey })
56
+ createApp({}).use(assets)
57
+ const promise = assets.client.upload(new File(['x'], 'x'))
58
+ sessionKey.value = 'b'
59
+ await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
60
+ expect(requestSignal?.aborted).toBe(true)
61
+ })
62
+ })
63
+
64
+ describe('asset client upload cancellation', () => {
65
+ it('does not complete after clearSession', async () => {
102
66
  let finish!: (response: Response) => void
103
67
  const fetcher = vi.fn<AssetFetch>().mockImplementationOnce(() => new Promise(resolve => { finish = resolve }))
104
- const client = createAssetClient(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher }))
68
+ const client = createAssetClient(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher }), 'https://cdn.bgl.dev/auctentic')
105
69
  const promise = client.upload(new File(['x'], 'x'))
106
70
  client.clearSession()
107
71
  finish(json(session))
108
72
  await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
109
73
  expect(fetcher).toHaveBeenCalledTimes(1)
110
74
  })
111
-
112
- it('session cleanup aborts the HTTP request', async () => {
113
- let requestSignal: AbortSignal | null | undefined
114
- const fetcher = vi.fn<AssetFetch>((_url, init) => {
115
- requestSignal = init?.signal
116
- return new Promise((_resolve, reject) => requestSignal?.addEventListener('abort', () => reject(requestSignal?.reason)))
117
- })
118
- const client = createAssetClient(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher }))
119
- const promise = client.resolve({ asset_id: 'a' })
120
- await Promise.resolve()
121
- client.clearSession()
122
- await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
123
- expect(requestSignal?.aborted).toBe(true)
124
- })
125
75
  })
@@ -1,4 +1,4 @@
1
- import { createAssetClient, ASSET_CLIENT_KEY, type AssetDelivery, type AssetTransport, type AssetReference, type AssetPurpose } from './assets'
1
+ import { createAssetClient, ASSET_CLIENT_KEY, type AssetTransport } from './assets'
2
2
  import type { ApiTransport } from '@bagelink/sdk'
3
3
  import { watch, toValue, type App, type MaybeRefOrGetter } from 'vue'
4
4
 
@@ -10,30 +10,20 @@ export interface AssetHttpOptions {
10
10
  headers?: () => HeadersInit
11
11
  fetch?: AssetFetch
12
12
  credentials?: RequestCredentials
13
- /** Explicitly trusted delivery origins besides the API origin. */
14
- deliveryOrigins?: string[]
15
13
  /** Reuse the app's authenticated axios instance, including tenant interceptors. */
16
14
  apiTransport?: ApiTransport
17
15
  }
18
16
 
19
17
  interface UploadResponse {
20
18
  asset_id: string
21
- version_id: string
22
19
  upload_id: string
23
20
  status: string
24
21
  }
25
- interface DeliveryResponse extends AssetDelivery {
26
- asset_id: string
27
- representation: string
28
- }
29
22
 
30
- /** Concrete REST adapter, separate from generated SDK namespaces. */
31
- export function createAssetHttpTransport(options: AssetHttpOptions): AssetTransport & {
32
- publish(reference: Required<AssetReference>, signal?: AbortSignal): Promise<AssetPublication>
33
- } {
23
+ /** Concrete REST adapter. Public-by-default: upload only; display is a client-built URL. */
24
+ export function createAssetHttpTransport(options: AssetHttpOptions): AssetTransport {
34
25
  const base = new URL(options.baseURL.endsWith('/') ? options.baseURL : `${options.baseURL}/`)
35
26
  if (!['http:', 'https:'].includes(base.protocol) || base.username || base.password) throw new Error('Invalid API base')
36
- const trusted = new Set([base.origin, ...(options.deliveryOrigins ?? []).map(origin => new URL(origin).origin)])
37
27
  const request = options.fetch ?? globalThis.fetch
38
28
  async function send<T>(path: string, init: RequestInit, signal: AbortSignal): Promise<T> {
39
29
  signal.throwIfAborted()
@@ -57,108 +47,52 @@ export function createAssetHttpTransport(options: AssetHttpOptions): AssetTransp
57
47
  return await response.json() as T
58
48
  }
59
49
  return {
60
- async publish(reference: Required<AssetReference>, signal = new AbortController().signal): Promise<AssetPublication> {
61
- const result = await send<AssetPublication>(`${encodeURIComponent(reference.asset_id)}/publication`, {
62
- method: 'PUT', headers: { 'Content-Type': 'application/json' },
63
- body: JSON.stringify({ published: true, version_id: reference.version_id, representations: ['website', 'social'] }),
64
- }, signal)
65
- if (result.asset_id !== reference.asset_id || result.version_id !== reference.version_id || !result.published) {
66
- throw new Error('Mismatched asset publication')
67
- }
68
- for (const purpose of ['website', 'social'] as const) {
69
- const item = result.representations.find(item => item.representation === purpose)
70
- if (!item) throw new Error('Incomplete asset publication')
71
- const url = new URL(item.url, base)
72
- const suffix = `/assets/${encodeURIComponent(reference.asset_id)}/public/${encodeURIComponent(reference.version_id)}/${purpose}`
73
- if (!trusted.has(url.origin) || !['http:', 'https:'].includes(url.protocol)
74
- || url.username || url.password || url.search || url.hash || !url.pathname.endsWith(suffix)) {
75
- throw new Error('Invalid public asset URL')
76
- }
77
- item.url = url.href
78
- }
79
- return result
80
- },
81
- async upload(file, signal) {
50
+ async upload(file, signal, uploadOptions) {
82
51
  const started = await send<UploadResponse>('uploads', {
83
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: file.name }),
52
+ method: 'POST',
53
+ headers: { 'Content-Type': 'application/json' },
54
+ body: JSON.stringify({
55
+ name: file.name,
56
+ visibility: uploadOptions?.visibility ?? 'protected',
57
+ }),
84
58
  }, signal)
85
- if (!started.upload_id || !started.asset_id || !started.version_id) throw new Error('Invalid upload session')
59
+ if (!started.upload_id || !started.asset_id) throw new Error('Invalid upload session')
86
60
  const completed = await send<UploadResponse>(`uploads/${encodeURIComponent(started.upload_id)}`, {
87
61
  method: 'PUT', headers: { 'Content-Type': 'application/octet-stream' }, body: file,
88
62
  }, signal)
89
- if (completed.status !== 'ready' || completed.asset_id !== started.asset_id
90
- || completed.version_id !== started.version_id || completed.upload_id !== started.upload_id) {
63
+ if (completed.status !== 'ready' || completed.asset_id !== started.asset_id) {
91
64
  throw new Error('Asset upload is not ready')
92
65
  }
93
- return { asset_id: completed.asset_id, version_id: completed.version_id }
94
- },
95
- async resolve(references, signal) {
96
- const result: AssetDelivery[] = []
97
- for (let offset = 0; offset < references.length; offset += 50) {
98
- const chunk = references.slice(offset, offset + 50)
99
- const response = await send<{ items: DeliveryResponse[] }>('resolve', {
100
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ references: chunk }),
101
- }, signal)
102
- if (!Array.isArray(response.items) || response.items.length !== chunk.length) throw new Error('Incomplete delivery response')
103
- for (const reference of chunk) {
104
- const item = response.items.find(candidate => candidate.asset_id === reference.asset_id
105
- && (!reference.version_id || candidate.version_id === reference.version_id)
106
- && candidate.representation === (reference.representation ?? 'original'))
107
- if (!item) throw new Error('Mismatched delivery response')
108
- const url = new URL(item.url, base)
109
- if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password
110
- || !trusted.has(url.origin)) throw new Error('Untrusted asset delivery URL')
111
- result.push({ url: url.href, version_id: item.version_id, expires_at: item.expires_at })
112
- }
113
- }
114
- return result
66
+ return { asset_id: completed.asset_id }
115
67
  },
116
68
  }
117
69
  }
118
70
 
119
- /** Public URLs are deliberately separate from expiring private deliveries. */
120
- export interface AssetPublication {
121
- asset_id: string
122
- name: string
123
- version_id: string
124
- published: boolean
125
- representations: { representation: AssetPurpose; url: string; media_type: string; size: number }[]
126
- }
127
-
128
71
  export interface ConfigureAssetClientOptions {
129
72
  transport: ApiTransport
130
- /** Existing reactive identity/session + tenant key. Never inferred from auth globals. */
131
- sessionKey: MaybeRefOrGetter<string | undefined>
132
- deliveryOrigins?: string[]
73
+ /** Public CDN base, e.g. `https://cdn.bgl.dev/auctentic`. Used to build asset URLs. */
74
+ deliveryBaseUrl: string
75
+ /** Identity + tenant key; must change on logout and account/tenant switch. */
76
+ sessionKey?: MaybeRefOrGetter<string | undefined>
133
77
  }
134
78
 
135
- /** Vue plugin; owns its session watcher and clears on app teardown. */
79
+ /** Vue plugin; provides the asset client and clears uploads on session change. */
136
80
  export function configureAssetClient(options: ConfigureAssetClientOptions) {
137
81
  const baseURL = options.transport.axios.defaults.baseURL
138
82
  if (!baseURL) throw new Error('Asset transport needs an API baseURL')
139
83
  const transport = createAssetHttpTransport({
140
84
  baseURL: new URL(baseURL, typeof location === 'undefined' ? undefined : location.origin).href,
141
- apiTransport: options.transport, deliveryOrigins: options.deliveryOrigins,
85
+ apiTransport: options.transport,
142
86
  })
143
- const client = createAssetClient(transport)
144
- const publications = new Set<AbortController>()
145
- const clearSession = () => {
146
- client.clearSession()
147
- for (const controller of publications) controller.abort()
148
- publications.clear()
149
- }
87
+ const client = createAssetClient(transport, options.deliveryBaseUrl)
150
88
  return {
151
89
  client,
152
- async publish(reference: Required<AssetReference>) {
153
- const controller = new AbortController()
154
- publications.add(controller)
155
- try { return await transport.publish(reference, controller.signal) }
156
- finally { publications.delete(controller) }
157
- },
158
90
  install(app: App) {
159
91
  app.provide(ASSET_CLIENT_KEY, client)
160
- const stop = watch(() => toValue(options.sessionKey), clearSession, { flush: 'sync' })
161
- app.onUnmount(() => { stop(); clearSession() })
92
+ const stop = options.sessionKey
93
+ ? watch(() => toValue(options.sessionKey), () => client.clearSession(), { flush: 'sync' })
94
+ : undefined
95
+ app.onUnmount(() => { stop?.(); client.clearSession() })
162
96
  },
163
97
  }
164
98
  }
@@ -1,123 +1,82 @@
1
1
  // @vitest-environment happy-dom
2
2
  import { describe, expect, it, vi } from 'vitest'
3
- import { createAssetClient, ASSET_CLIENT_KEY, useAssetDelivery, type AssetDelivery, type AssetTransport } from './assets'
3
+ import { createAssetClient, ASSET_CLIENT_KEY, useAssetDelivery, useAssetUpload, type AssetTransport } from './assets'
4
4
  import { mount } from '@vue/test-utils'
5
5
  import { defineComponent, nextTick } from 'vue'
6
6
 
7
- const delivery = (version_id = 'v1'): AssetDelivery => ({
8
- url: 'https://delivery.example/private',
9
- expires_at: new Date(Date.now() + 60_000).toISOString(),
10
- version_id,
11
- })
7
+ const BASE = 'https://cdn.bgl.dev/auctentic'
12
8
 
13
- function setup() {
14
- const resolve = vi.fn<AssetTransport['resolve']>(async references => references.map(() => delivery()))
15
- const upload = vi.fn<AssetTransport['upload']>(async () => ({ asset_id: 'a', version_id: 'v1' }))
16
- return { resolve, upload, client: createAssetClient({ resolve, upload }) }
9
+ function makeClient(upload?: AssetTransport['upload']) {
10
+ const transport = { upload: upload ?? (async () => ({ asset_id: 'a' })) }
11
+ return createAssetClient(transport, BASE)
17
12
  }
18
13
 
19
14
  describe('asset client', () => {
20
- it('keeps the displayed URL while refreshing, but clears immediately on session change', async () => {
21
- vi.useFakeTimers()
22
- const { client, resolve } = setup()
23
- let finish!: (value: AssetDelivery[]) => void
24
- let state!: ReturnType<typeof useAssetDelivery>
25
- const component = mount(defineComponent({
26
- setup() { state = useAssetDelivery(() => ({ asset_id: 'a' })); return () => null },
27
- }), { global: { provide: { [ASSET_CLIENT_KEY as symbol]: client } } })
28
- try {
29
- await vi.advanceTimersByTimeAsync(0)
30
- expect(state.url.value).toBe(delivery().url)
31
- resolve.mockImplementationOnce(() => new Promise(done => { finish = done }))
32
- await vi.advanceTimersByTimeAsync(48_000)
33
- expect(resolve).toHaveBeenCalledTimes(2)
34
- expect(state.url.value).toBe(delivery().url)
35
- client.clearSession()
36
- expect(state.url.value).toBeUndefined()
37
- finish([delivery()])
38
- await nextTick()
39
- expect(state.url.value).toBeUndefined()
40
- } finally {
41
- component.unmount()
42
- vi.useRealTimers()
43
- }
15
+ it('builds deterministic public URLs per purpose', () => {
16
+ const client = makeClient()
17
+ expect(client.assetUrl({ asset_id: 'a' })).toBe(`${BASE}/a`)
18
+ expect(client.assetUrl({ asset_id: 'a' }, 'original')).toBe(`${BASE}/a`)
19
+ expect(client.assetUrl({ asset_id: 'a' }, 'website')).toBe(`${BASE}/a?fmt=webp`)
20
+ expect(client.assetUrl({ asset_id: 'a' }, 'social')).toBe(`${BASE}/a?w=1200&h=630&fmt=jpeg&fit=cover`)
44
21
  })
45
22
 
46
- it('deduplicates in-flight requests without sharing subscriber cancellation', async () => {
47
- const { client, resolve } = setup()
48
- let finish!: (value: AssetDelivery[]) => void
49
- resolve.mockImplementationOnce(() => new Promise(done => { finish = done }))
50
- const controller = new AbortController()
51
- const first = client.resolve({ asset_id: 'a' }, controller.signal)
52
- const rejected = expect(first).rejects.toMatchObject({ name: 'AbortError' })
53
- await Promise.resolve()
54
- const second = client.resolve({ asset_id: 'a', representation: 'original' })
55
- controller.abort()
56
- await rejected
57
- expect(resolve.mock.calls[0]![1].aborted).toBe(false)
58
- finish([delivery()])
59
- await expect(second).resolves.toMatchObject({ version_id: 'v1' })
60
- expect(resolve).toHaveBeenCalledTimes(1)
23
+ it('upload returns only the public id (version is ignored)', async () => {
24
+ const upload = vi.fn<AssetTransport['upload']>(async () => ({ asset_id: 'a', version_id: 'v1' }))
25
+ const client = makeClient(upload)
26
+ await expect(client.upload(new File(['x'], 'x'))).resolves.toEqual({ asset_id: 'a' })
61
27
  })
62
28
 
63
- it('aborts unused requests and starts fresh after a session change', async () => {
64
- const { client, resolve } = setup()
65
- resolve.mockImplementationOnce(() => new Promise(() => {}))
66
- const first = client.resolve({ asset_id: 'a' })
67
- const rejected = expect(first).rejects.toMatchObject({ name: 'AbortError' })
68
- await Promise.resolve()
29
+ it('clearSession aborts in-flight uploads and bumps revision', async () => {
30
+ const upload = vi.fn<AssetTransport['upload']>((_f, signal) => new Promise((_resolve, reject) => {
31
+ signal.addEventListener('abort', () => reject(new DOMException('x', 'AbortError')))
32
+ }))
33
+ const client = makeClient(upload)
34
+ const before = client.revision
35
+ const promise = client.upload(new File(['x'], 'x'))
69
36
  client.clearSession()
70
- await rejected
71
- expect(resolve.mock.calls[0]![1].aborted).toBe(true)
72
- await expect(client.resolve({ asset_id: 'a' })).resolves.toMatchObject({ version_id: 'v1' })
73
- expect(resolve).toHaveBeenCalledTimes(2)
74
- })
75
-
76
- it('batches same-turn resolutions and preserves pins', async () => {
77
- const { client, resolve } = setup()
78
- await Promise.all([client.resolve({ asset_id: 'a', version_id: 'v1' }), client.resolve({ asset_id: 'b' })])
79
- expect(resolve).toHaveBeenCalledTimes(1)
80
- expect(resolve.mock.calls[0]![0][0]).toEqual({ asset_id: 'a', version_id: 'v1' })
81
- })
82
-
83
- it('does not cache grants between calls', async () => {
84
- const { client, resolve } = setup()
85
- await client.resolve({ asset_id: 'a' })
86
- await client.resolve({ asset_id: 'a' })
87
- expect(resolve).toHaveBeenCalledTimes(2)
37
+ await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
38
+ expect(client.revision).toBe(before + 1)
88
39
  })
40
+ })
89
41
 
90
- it('rejects expired grants and mismatched pinned versions', async () => {
91
- const { client, resolve } = setup()
92
- await expect(client.resolve({ asset_id: 'a', version_id: 'v2' })).rejects.toThrow('Invalid asset delivery')
93
- resolve.mockResolvedValueOnce([{ ...delivery(), expires_at: '2000-01-01T00:00:00Z' }])
94
- await expect(client.resolve({ asset_id: 'a' })).rejects.toThrow('Invalid asset delivery')
42
+ describe('useAssetDelivery (public URL resolution)', () => {
43
+ it('resolves an asset reference to its public URL without a network call', async () => {
44
+ const client = makeClient()
45
+ let state!: ReturnType<typeof useAssetDelivery>
46
+ mount(defineComponent({
47
+ setup() { state = useAssetDelivery(() => ({ asset_id: 'a', representation: 'preview' })); return () => null },
48
+ }), { global: { provide: { [ASSET_CLIENT_KEY as symbol]: client } } })
49
+ await nextTick()
50
+ expect(state.url.value).toBe(`${BASE}/a?fmt=webp`)
51
+ expect(state.error.value).toBe(false)
95
52
  })
96
53
 
97
- it('cancels queued requests on session change', async () => {
98
- const { client, resolve } = setup()
99
- const request = client.resolve({ asset_id: 'a' })
100
- client.clearSession()
101
- await expect(request).rejects.toMatchObject({ name: 'AbortError' })
102
- expect(resolve).not.toHaveBeenCalled()
54
+ it('sets error when no client is provided', async () => {
55
+ let state!: ReturnType<typeof useAssetDelivery>
56
+ mount(defineComponent({
57
+ setup() { state = useAssetDelivery(() => ({ asset_id: 'a' })); return () => null },
58
+ }))
59
+ await nextTick()
60
+ expect(state.url.value).toBeUndefined()
61
+ expect(state.error.value).toBe(true)
103
62
  })
63
+ })
104
64
 
105
- it('rejects stale in-flight results even if transport ignores abort', async () => {
106
- const { client, resolve } = setup()
107
- let finish!: (value: AssetDelivery[]) => void
108
- resolve.mockImplementationOnce(() => new Promise(done => { finish = done }))
109
- const request = client.resolve({ asset_id: 'a' })
110
- await Promise.resolve()
111
- client.clearSession()
112
- finish([delivery()])
113
- await expect(request).rejects.toMatchObject({ name: 'AbortError' })
65
+ describe('useAssetUpload', () => {
66
+ it('rejects when no client is injected', async () => {
67
+ let upload!: ReturnType<typeof useAssetUpload>['upload']
68
+ mount(defineComponent({
69
+ setup() { upload = useAssetUpload().upload; return () => null },
70
+ }))
71
+ await expect(upload(new File(['x'], 'x'))).rejects.toThrow('Asset client is not configured')
114
72
  })
115
73
 
116
- it('does not dispatch already-cancelled requests', async () => {
117
- const { client, resolve } = setup()
118
- const controller = new AbortController()
119
- controller.abort()
120
- await expect(client.resolve({ asset_id: 'a' }, controller.signal)).rejects.toMatchObject({ name: 'AbortError' })
121
- expect(resolve).not.toHaveBeenCalled()
74
+ it('uploads and returns the public reference', async () => {
75
+ const client = makeClient()
76
+ let upload!: ReturnType<typeof useAssetUpload>['upload']
77
+ mount(defineComponent({
78
+ setup() { upload = useAssetUpload().upload; return () => null },
79
+ }), { global: { provide: { [ASSET_CLIENT_KEY as symbol]: client } } })
80
+ await expect(upload(new File(['x'], 'x'))).resolves.toEqual({ asset_id: 'a' })
122
81
  })
123
82
  })