@fayz-ai/sdk 0.9.0-next.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +2 -2
  2. package/dist/ai-builder.js +1 -1
  3. package/dist/{chunk-2YJXKDHO.js → chunk-6UZOXHGJ.js} +11 -6
  4. package/dist/chunk-6UZOXHGJ.js.map +1 -0
  5. package/dist/{chunk-V4GWI7WH.js → chunk-7UXTYT6I.js} +65 -4
  6. package/dist/chunk-7UXTYT6I.js.map +1 -0
  7. package/dist/{chunk-7XM4LONE.js → chunk-BJFMBVMP.js} +2 -2
  8. package/dist/chunk-BJFMBVMP.js.map +1 -0
  9. package/dist/chunk-HA5O3CW7.js +181 -0
  10. package/dist/chunk-HA5O3CW7.js.map +1 -0
  11. package/dist/chunk-VRUPJGFZ.js +135 -0
  12. package/dist/chunk-VRUPJGFZ.js.map +1 -0
  13. package/dist/deprecations.d.ts +98 -0
  14. package/dist/deprecations.d.ts.map +1 -0
  15. package/dist/deprecations.js +3 -0
  16. package/dist/deprecations.js.map +1 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +5 -4
  20. package/dist/release-channels.js +1 -1
  21. package/dist/shop.d.ts +32 -0
  22. package/dist/shop.d.ts.map +1 -1
  23. package/dist/shop.js +2 -1
  24. package/dist/supported-surface.d.ts +8 -1
  25. package/dist/supported-surface.d.ts.map +1 -1
  26. package/dist/supported-surface.js +1 -1
  27. package/dist/vite.d.ts +30 -1
  28. package/dist/vite.d.ts.map +1 -1
  29. package/dist/vite.js +10 -2
  30. package/dist/vite.js.map +1 -1
  31. package/package.json +7 -14
  32. package/dist/chunk-2YJXKDHO.js.map +0 -1
  33. package/dist/chunk-7XM4LONE.js.map +0 -1
  34. package/dist/chunk-V4GWI7WH.js.map +0 -1
  35. package/dist/chunk-YZQW3BJA.js +0 -135
  36. package/dist/chunk-YZQW3BJA.js.map +0 -1
  37. package/src/agent.test.ts +0 -114
  38. package/src/agent.ts +0 -335
  39. package/src/ai-builder.ts +0 -115
  40. package/src/app-params.ts +0 -69
  41. package/src/client.test.ts +0 -176
  42. package/src/client.ts +0 -229
  43. package/src/index.ts +0 -94
  44. package/src/release-channels.json +0 -103
  45. package/src/release-channels.test.ts +0 -41
  46. package/src/release-channels.ts +0 -41
  47. package/src/runtime.test.ts +0 -123
  48. package/src/runtime.ts +0 -211
  49. package/src/shop.test.ts +0 -114
  50. package/src/shop.ts +0 -1118
  51. package/src/supported-surface.json +0 -40
  52. package/src/supported-surface.ts +0 -33
  53. package/src/types.ts +0 -67
  54. package/src/vite.ts +0 -121
@@ -1,123 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest'
2
- import {
3
- createFayzRuntimeClient,
4
- FayzRuntimeError,
5
- } from './runtime'
6
-
7
- function jsonResponse(body: unknown, status = 200): Response {
8
- return new Response(JSON.stringify(body), {
9
- status,
10
- headers: { 'Content-Type': 'application/json' },
11
- })
12
- }
13
-
14
- describe('createFayzRuntimeClient', () => {
15
- it('exchanges runtime-data tokens for broker tokens without sending provider credentials', async () => {
16
- const fetcher = vi.fn<typeof fetch>().mockResolvedValue(jsonResponse({
17
- token: 'broker-token',
18
- tokenType: 'Bearer',
19
- expiresIn: 300,
20
- projectId: 'project-1',
21
- tenantKey: 'tenant-a',
22
- environment: 'preview',
23
- pluginId: '@fayz-ai/plugin-agenda',
24
- grants: [{ grantId: 'grant-1', provider: 'google-calendar', scopes: ['calendar.read'] }],
25
- }))
26
- const client = createFayzRuntimeClient({
27
- baseUrl: 'https://api.fayz.ai/',
28
- projectId: 'project-1',
29
- runtimeToken: 'runtime-token',
30
- fetcher,
31
- })
32
-
33
- const response = await client.exchangePluginOAuth({
34
- pluginId: '@fayz-ai/plugin-agenda',
35
- scopes: ['calendar.read'],
36
- })
37
-
38
- expect(response.token).toBe('broker-token')
39
- expect(fetcher).toHaveBeenCalledWith(
40
- 'https://api.fayz.ai/api/v1/runtime/projects/project-1/oauth/exchange',
41
- expect.objectContaining({
42
- method: 'POST',
43
- headers: expect.objectContaining({
44
- Authorization: 'Bearer runtime-token',
45
- 'Content-Type': 'application/json',
46
- }),
47
- body: JSON.stringify({
48
- pluginId: '@fayz-ai/plugin-agenda',
49
- environment: 'preview',
50
- scopes: ['calendar.read'],
51
- }),
52
- }),
53
- )
54
- expect(JSON.stringify(fetcher.mock.calls)).not.toContain('clientSecret')
55
- expect(JSON.stringify(fetcher.mock.calls)).not.toContain('refreshToken')
56
- expect(JSON.stringify(fetcher.mock.calls)).not.toContain('accessToken')
57
- })
58
-
59
- it('calls Google Calendar broker routes with the short-lived plugin OAuth token', async () => {
60
- const fetcher = vi.fn<typeof fetch>()
61
- .mockResolvedValueOnce(jsonResponse({ provider: 'google-calendar', calendarId: 'primary', events: [] }))
62
- .mockResolvedValueOnce(jsonResponse({ provider: 'google-calendar', calendarId: 'primary', event: { id: 'event-1' } }, 201))
63
- .mockResolvedValueOnce(jsonResponse({ provider: 'google-calendar', calendarId: 'primary', event: { id: 'event-1' } }))
64
- .mockResolvedValueOnce(new Response(null, { status: 204 }))
65
- const client = createFayzRuntimeClient({
66
- baseUrl: 'https://api.fayz.ai',
67
- projectId: 'project-1',
68
- runtimeToken: 'runtime-token',
69
- fetcher,
70
- })
71
- const calendar = client.googleCalendar('broker-token')
72
-
73
- await calendar.listEvents({
74
- calendarId: 'primary',
75
- timeMin: '2026-06-14T00:00:00.000Z',
76
- timeMax: '2026-06-15T00:00:00.000Z',
77
- maxResults: 25,
78
- })
79
- await calendar.createEvent('primary', {
80
- summary: 'Haircut',
81
- start: { dateTime: '2026-06-14T09:00:00.000Z' },
82
- end: { dateTime: '2026-06-14T09:30:00.000Z' },
83
- })
84
- await calendar.updateEvent('primary', 'event-1', { summary: 'Updated haircut' })
85
- await calendar.deleteEvent('primary', 'event-1')
86
-
87
- expect(fetcher.mock.calls[0][0]).toBe(
88
- 'https://api.fayz.ai/api/v1/runtime/projects/project-1/oauth/google-calendar/events?calendarId=primary&timeMin=2026-06-14T00%3A00%3A00.000Z&timeMax=2026-06-15T00%3A00%3A00.000Z&maxResults=25',
89
- )
90
- expect(fetcher.mock.calls[1][0]).toBe(
91
- 'https://api.fayz.ai/api/v1/runtime/projects/project-1/oauth/google-calendar/events?calendarId=primary',
92
- )
93
- expect(fetcher.mock.calls[2][0]).toBe(
94
- 'https://api.fayz.ai/api/v1/runtime/projects/project-1/oauth/google-calendar/events/event-1?calendarId=primary',
95
- )
96
- expect(fetcher.mock.calls[3][0]).toBe(
97
- 'https://api.fayz.ai/api/v1/runtime/projects/project-1/oauth/google-calendar/events/event-1?calendarId=primary',
98
- )
99
- expect(fetcher.mock.calls[0][1]).toEqual(expect.objectContaining({
100
- headers: expect.objectContaining({ Authorization: 'Bearer broker-token' }),
101
- }))
102
- expect(fetcher.mock.calls[1][1]).toEqual(expect.objectContaining({ method: 'POST' }))
103
- expect(fetcher.mock.calls[2][1]).toEqual(expect.objectContaining({ method: 'PATCH' }))
104
- expect(fetcher.mock.calls[3][1]).toEqual(expect.objectContaining({ method: 'DELETE' }))
105
- })
106
-
107
- it('keeps non-json upstream errors debuggable', async () => {
108
- const fetcher = vi.fn<typeof fetch>().mockResolvedValue(new Response('upstream unavailable', { status: 502 }))
109
- const client = createFayzRuntimeClient({
110
- baseUrl: 'https://api.fayz.ai',
111
- projectId: 'project-1',
112
- runtimeToken: 'runtime-token',
113
- fetcher,
114
- })
115
-
116
- await expect(client.exchangePluginOAuth({ pluginId: '@fayz-ai/plugin-agenda' }))
117
- .rejects.toMatchObject({
118
- name: 'FayzRuntimeError',
119
- status: 502,
120
- responseBody: 'upstream unavailable',
121
- } satisfies Partial<FayzRuntimeError>)
122
- })
123
- })
package/src/runtime.ts DELETED
@@ -1,211 +0,0 @@
1
- export interface FayzRuntimeClientOptions {
2
- baseUrl: string
3
- projectId: string
4
- runtimeToken: string
5
- fetcher?: typeof fetch
6
- }
7
-
8
- export type FayzRuntimeEnvironment = 'preview' | 'production'
9
-
10
- export interface PluginOAuthExchangeInput {
11
- pluginId: string
12
- environment?: FayzRuntimeEnvironment
13
- scopes?: string[]
14
- }
15
-
16
- export interface RuntimePluginOAuthGrant {
17
- grantId: string
18
- provider: string
19
- scopes: string[]
20
- }
21
-
22
- export interface PluginOAuthExchangeResponse {
23
- token: string
24
- tokenType: 'Bearer'
25
- expiresIn: number
26
- projectId: string
27
- tenantKey: string
28
- environment: FayzRuntimeEnvironment
29
- pluginId: string
30
- grants: RuntimePluginOAuthGrant[]
31
- }
32
-
33
- export interface GoogleCalendarEventTime {
34
- dateTime: string
35
- timeZone?: string
36
- }
37
-
38
- export interface GoogleCalendarEventInput {
39
- summary: string
40
- description?: string
41
- location?: string
42
- start: GoogleCalendarEventTime
43
- end: GoogleCalendarEventTime
44
- attendees?: Array<{ email: string }>
45
- }
46
-
47
- export interface GoogleCalendarEvent {
48
- id: string
49
- summary?: string
50
- description?: string
51
- location?: string
52
- start: { dateTime?: string; date?: string; timeZone?: string }
53
- end: { dateTime?: string; date?: string; timeZone?: string }
54
- status?: string
55
- htmlLink?: string
56
- [key: string]: unknown
57
- }
58
-
59
- export interface ListGoogleCalendarEventsInput {
60
- calendarId: string
61
- timeMin?: string
62
- timeMax?: string
63
- maxResults?: number
64
- q?: string
65
- }
66
-
67
- export class FayzRuntimeError extends Error {
68
- constructor(
69
- message: string,
70
- readonly status: number,
71
- readonly responseBody?: unknown,
72
- ) {
73
- super(message)
74
- this.name = 'FayzRuntimeError'
75
- }
76
- }
77
-
78
- function normalizeBaseUrl(baseUrl: string): string {
79
- return baseUrl.replace(/\/+$/, '')
80
- }
81
-
82
- function assertRequired(value: string, field: string): string {
83
- const normalized = value.trim()
84
- if (!normalized) throw new Error(`${field} is required`)
85
- return normalized
86
- }
87
-
88
- function runtimePath(projectId: string, suffix: string): string {
89
- return `/api/v1/runtime/projects/${encodeURIComponent(projectId)}${suffix}`
90
- }
91
-
92
- function queryString(params: Record<string, string | number | undefined>): string {
93
- const search = new URLSearchParams()
94
- for (const [key, value] of Object.entries(params)) {
95
- if (value !== undefined && value !== '') search.set(key, String(value))
96
- }
97
- const value = search.toString()
98
- return value ? `?${value}` : ''
99
- }
100
-
101
- async function parseResponse<T>(response: Response): Promise<T> {
102
- if (response.status === 204) return undefined as T
103
-
104
- const text = await response.text()
105
- let body: unknown
106
- try {
107
- body = text ? JSON.parse(text) : undefined
108
- } catch {
109
- body = text
110
- }
111
-
112
- if (!response.ok) {
113
- const message = typeof body === 'object' && body && 'message' in body
114
- ? String((body as { message: unknown }).message)
115
- : `Fayz runtime request failed with status ${response.status}`
116
- throw new FayzRuntimeError(message, response.status, body)
117
- }
118
-
119
- return body as T
120
- }
121
-
122
- export function createFayzRuntimeClient(options: FayzRuntimeClientOptions) {
123
- const baseUrl = normalizeBaseUrl(assertRequired(options.baseUrl, 'baseUrl'))
124
- const projectId = assertRequired(options.projectId, 'projectId')
125
- const runtimeToken = assertRequired(options.runtimeToken, 'runtimeToken')
126
- const fetcher = options.fetcher ?? fetch
127
-
128
- async function request<T>(
129
- path: string,
130
- token: string,
131
- init: Omit<RequestInit, 'headers'> & { headers?: Record<string, string> } = {},
132
- ): Promise<T> {
133
- const response = await fetcher(`${baseUrl}${path}`, {
134
- ...init,
135
- headers: {
136
- ...(init.body ? { 'Content-Type': 'application/json' } : {}),
137
- ...init.headers,
138
- Authorization: `Bearer ${token}`,
139
- },
140
- })
141
- return parseResponse<T>(response)
142
- }
143
-
144
- async function exchangePluginOAuth(input: PluginOAuthExchangeInput): Promise<PluginOAuthExchangeResponse> {
145
- return request<PluginOAuthExchangeResponse>(
146
- runtimePath(projectId, '/oauth/exchange'),
147
- runtimeToken,
148
- {
149
- method: 'POST',
150
- body: JSON.stringify({
151
- pluginId: input.pluginId,
152
- environment: input.environment ?? 'preview',
153
- ...(input.scopes ? { scopes: input.scopes } : {}),
154
- }),
155
- },
156
- )
157
- }
158
-
159
- function googleCalendar(pluginOAuthToken: string) {
160
- const brokerToken = assertRequired(pluginOAuthToken, 'pluginOAuthToken')
161
- const eventsPath = runtimePath(projectId, '/oauth/google-calendar/events')
162
-
163
- return {
164
- listEvents(input: ListGoogleCalendarEventsInput) {
165
- const calendarId = assertRequired(input.calendarId, 'calendarId')
166
- return request<{
167
- provider: 'google-calendar'
168
- calendarId: string
169
- timeMin: string
170
- timeMax: string
171
- events: GoogleCalendarEvent[]
172
- }>(
173
- `${eventsPath}${queryString({
174
- calendarId,
175
- timeMin: input.timeMin,
176
- timeMax: input.timeMax,
177
- maxResults: input.maxResults,
178
- q: input.q,
179
- })}`,
180
- brokerToken,
181
- )
182
- },
183
- createEvent(calendarId: string, event: GoogleCalendarEventInput) {
184
- return request<{ provider: 'google-calendar'; calendarId: string; event: GoogleCalendarEvent }>(
185
- `${eventsPath}${queryString({ calendarId: assertRequired(calendarId, 'calendarId') })}`,
186
- brokerToken,
187
- { method: 'POST', body: JSON.stringify(event) },
188
- )
189
- },
190
- updateEvent(calendarId: string, eventId: string, updates: Partial<GoogleCalendarEventInput>) {
191
- return request<{ provider: 'google-calendar'; calendarId: string; event: GoogleCalendarEvent }>(
192
- `${eventsPath}/${encodeURIComponent(assertRequired(eventId, 'eventId'))}${queryString({ calendarId: assertRequired(calendarId, 'calendarId') })}`,
193
- brokerToken,
194
- { method: 'PATCH', body: JSON.stringify(updates) },
195
- )
196
- },
197
- deleteEvent(calendarId: string, eventId: string) {
198
- return request<void>(
199
- `${eventsPath}/${encodeURIComponent(assertRequired(eventId, 'eventId'))}${queryString({ calendarId: assertRequired(calendarId, 'calendarId') })}`,
200
- brokerToken,
201
- { method: 'DELETE' },
202
- )
203
- },
204
- }
205
- }
206
-
207
- return {
208
- exchangePluginOAuth,
209
- googleCalendar,
210
- }
211
- }
package/src/shop.test.ts DELETED
@@ -1,114 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest'
2
-
3
- import { createFayzShopProvider } from './shop'
4
-
5
- function jsonResponse(body: unknown, status = 200): Response {
6
- return new Response(JSON.stringify(body), {
7
- status,
8
- headers: { 'Content-Type': 'application/json' },
9
- })
10
- }
11
-
12
- function productRow(overrides: Record<string, unknown> = {}) {
13
- return {
14
- id: '11111111-1111-4111-8111-000000000001',
15
- tenant_id: 'store-1',
16
- name: 'Runner Vortex Neon',
17
- slug: 'runner-vortex-neon',
18
- sku: 'SNK-001',
19
- price: 499.9,
20
- metadata: {},
21
- images: [],
22
- ...overrides,
23
- }
24
- }
25
-
26
- describe('createFayzShopProvider', () => {
27
- it('uses the Fayz broker without provider credentials when apiBaseUrl and projectId are provided', async () => {
28
- const fetcher = vi.fn<typeof fetch>().mockResolvedValue(jsonResponse({
29
- products: [{
30
- id: '11111111-1111-4111-8111-000000000001',
31
- tenantId: 'store-1',
32
- name: 'Aurora Tote',
33
- slug: 'aurora-tote',
34
- sku: 'BAG-001',
35
- price: 149.9,
36
- metadata: {},
37
- images: [],
38
- category: { id: 'cat-1', name: 'Bags' },
39
- }],
40
- }))
41
-
42
- const provider = createFayzShopProvider({
43
- apiBaseUrl: 'http://localhost:5173/api',
44
- projectId: 'project-1',
45
- fetcher,
46
- })
47
-
48
- const [product] = await provider.listProducts({ status: 'active', limit: 4 })
49
-
50
- expect(fetcher).toHaveBeenCalledWith(
51
- 'http://localhost:5173/api/public/projects/project-1/shop/products?status=active&limit=4',
52
- {},
53
- )
54
- expect(product?.categoryId).toBe('cat-1')
55
- expect(product?.categoryName).toBe('Bags')
56
- })
57
-
58
- it('merges app-owned product metadata overlays into listed products', async () => {
59
- const fetcher = vi.fn<typeof fetch>().mockResolvedValue(jsonResponse([
60
- productRow({
61
- metadata: {
62
- colorway: 'Backend wins',
63
- },
64
- }),
65
- ]))
66
-
67
- const provider = createFayzShopProvider({
68
- supabaseUrl: 'https://example.supabase.co',
69
- publishableKey: 'publishable-key',
70
- storeId: 'store-1',
71
- productMetadata: [
72
- {
73
- sku: 'SNK-001',
74
- slug: 'runner-vortex-neon',
75
- metadata: {
76
- colorway: 'Overlay loses',
77
- sizes: ['38', '39', '40'],
78
- },
79
- },
80
- ],
81
- fetcher,
82
- })
83
-
84
- const [product] = await provider.listProducts({ status: 'active' })
85
-
86
- expect(product?.metadata.sizes).toEqual(['38', '39', '40'])
87
- expect(product?.metadata.colorway).toBe('Backend wins')
88
- })
89
-
90
- it('uses slug overlays when fetching a single product', async () => {
91
- const fetcher = vi.fn<typeof fetch>().mockResolvedValue(jsonResponse([
92
- productRow({ sku: null }),
93
- ]))
94
-
95
- const provider = createFayzShopProvider({
96
- supabaseUrl: 'https://example.supabase.co',
97
- publishableKey: 'publishable-key',
98
- storeId: 'store-1',
99
- productMetadata: [
100
- {
101
- slug: 'runner-vortex-neon',
102
- metadata: {
103
- sizes: ['40', '41'],
104
- },
105
- },
106
- ],
107
- fetcher,
108
- })
109
-
110
- const product = await provider.getProduct('11111111-1111-4111-8111-000000000001')
111
-
112
- expect(product?.metadata.sizes).toEqual(['40', '41'])
113
- })
114
- })