@fayz-ai/sdk 0.9.0 → 0.10.1

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 (56) 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-KVMRRT3O.js +135 -0
  12. package/dist/chunk-KVMRRT3O.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/deprecations.json +119 -0
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +5 -4
  21. package/dist/release-channels.js +1 -1
  22. package/dist/release-channels.json +103 -0
  23. package/dist/shop.d.ts +32 -0
  24. package/dist/shop.d.ts.map +1 -1
  25. package/dist/shop.js +2 -1
  26. package/dist/supported-surface.d.ts +8 -1
  27. package/dist/supported-surface.d.ts.map +1 -1
  28. package/dist/supported-surface.js +1 -1
  29. package/{src → dist}/supported-surface.json +5 -3
  30. package/dist/vite.d.ts +30 -1
  31. package/dist/vite.d.ts.map +1 -1
  32. package/dist/vite.js +10 -2
  33. package/dist/vite.js.map +1 -1
  34. package/package.json +10 -17
  35. package/dist/chunk-2YJXKDHO.js.map +0 -1
  36. package/dist/chunk-7XM4LONE.js.map +0 -1
  37. package/dist/chunk-GQPVDQEB.js +0 -135
  38. package/dist/chunk-GQPVDQEB.js.map +0 -1
  39. package/dist/chunk-V4GWI7WH.js.map +0 -1
  40. package/src/agent.test.ts +0 -114
  41. package/src/agent.ts +0 -335
  42. package/src/ai-builder.ts +0 -115
  43. package/src/app-params.ts +0 -69
  44. package/src/client.test.ts +0 -176
  45. package/src/client.ts +0 -229
  46. package/src/index.ts +0 -94
  47. package/src/release-channels.json +0 -103
  48. package/src/release-channels.test.ts +0 -41
  49. package/src/release-channels.ts +0 -41
  50. package/src/runtime.test.ts +0 -123
  51. package/src/runtime.ts +0 -211
  52. package/src/shop.test.ts +0 -114
  53. package/src/shop.ts +0 -1118
  54. package/src/supported-surface.ts +0 -33
  55. package/src/types.ts +0 -67
  56. package/src/vite.ts +0 -121
@@ -1,103 +0,0 @@
1
- {
2
- "channels": {
3
- "stable": {
4
- "@fayz-ai/sdk": "^0.9.0",
5
- "@fayz-ai/core": "^0.9.0",
6
- "@fayz-ai/auth": "^0.9.0",
7
- "@fayz-ai/ui": "^0.9.0",
8
- "@fayz-ai/saas": "^0.9.0",
9
- "@fayz-ai/shop": "^0.9.0",
10
- "@fayz-ai/storefront": "^0.9.0",
11
- "@fayz-ai/portal": "^0.9.0",
12
- "@fayz-ai/courses": "^0.9.0",
13
- "@fayz-ai/db": "^0.9.0",
14
- "@fayz-ai/plugin-agenda": "^0.9.0",
15
- "@fayz-ai/plugin-auth": "^0.9.0",
16
- "@fayz-ai/plugin-automations": "^0.9.0",
17
- "@fayz-ai/plugin-blog": "^0.9.0",
18
- "@fayz-ai/plugin-conversations": "^0.9.0",
19
- "@fayz-ai/plugin-courses": "^0.9.0",
20
- "@fayz-ai/plugin-crm": "^0.9.0",
21
- "@fayz-ai/plugin-dashboard": "^0.9.0",
22
- "@fayz-ai/plugin-financial": "^0.9.0",
23
- "@fayz-ai/plugin-forms": "^0.9.0",
24
- "@fayz-ai/plugin-inventory": "^0.9.0",
25
- "@fayz-ai/plugin-marketing": "^0.9.0",
26
- "@fayz-ai/plugin-menu": "^0.9.0",
27
- "@fayz-ai/plugin-orders": "^0.9.0",
28
- "@fayz-ai/plugin-payments": "^0.9.0",
29
- "@fayz-ai/plugin-reports": "^0.9.0",
30
- "@fayz-ai/plugin-reputation": "^0.9.0",
31
- "@fayz-ai/plugin-shop": "^0.9.0",
32
- "@fayz-ai/plugin-sites": "^0.9.0",
33
- "@fayz-ai/plugin-tables": "^0.9.0",
34
- "@fayz-ai/plugin-tasks": "^0.9.0"
35
- },
36
- "latest": {
37
- "@fayz-ai/sdk": "^0.9.0",
38
- "@fayz-ai/core": "^0.9.0",
39
- "@fayz-ai/auth": "^0.9.0",
40
- "@fayz-ai/ui": "^0.9.0",
41
- "@fayz-ai/saas": "^0.9.0",
42
- "@fayz-ai/shop": "^0.9.0",
43
- "@fayz-ai/storefront": "^0.9.0",
44
- "@fayz-ai/portal": "^0.9.0",
45
- "@fayz-ai/courses": "^0.9.0",
46
- "@fayz-ai/db": "^0.9.0",
47
- "@fayz-ai/plugin-agenda": "^0.9.0",
48
- "@fayz-ai/plugin-auth": "^0.9.0",
49
- "@fayz-ai/plugin-automations": "^0.9.0",
50
- "@fayz-ai/plugin-blog": "^0.9.0",
51
- "@fayz-ai/plugin-conversations": "^0.9.0",
52
- "@fayz-ai/plugin-courses": "^0.9.0",
53
- "@fayz-ai/plugin-crm": "^0.9.0",
54
- "@fayz-ai/plugin-dashboard": "^0.9.0",
55
- "@fayz-ai/plugin-financial": "^0.9.0",
56
- "@fayz-ai/plugin-forms": "^0.9.0",
57
- "@fayz-ai/plugin-inventory": "^0.9.0",
58
- "@fayz-ai/plugin-marketing": "^0.9.0",
59
- "@fayz-ai/plugin-menu": "^0.9.0",
60
- "@fayz-ai/plugin-orders": "^0.9.0",
61
- "@fayz-ai/plugin-payments": "^0.9.0",
62
- "@fayz-ai/plugin-reports": "^0.9.0",
63
- "@fayz-ai/plugin-reputation": "^0.9.0",
64
- "@fayz-ai/plugin-shop": "^0.9.0",
65
- "@fayz-ai/plugin-sites": "^0.9.0",
66
- "@fayz-ai/plugin-tables": "^0.9.0",
67
- "@fayz-ai/plugin-tasks": "^0.9.0"
68
- },
69
- "preview": {
70
- "@fayz-ai/sdk": "^0.9.0",
71
- "@fayz-ai/core": "^0.9.0",
72
- "@fayz-ai/auth": "^0.9.0",
73
- "@fayz-ai/ui": "^0.9.0",
74
- "@fayz-ai/saas": "^0.9.0",
75
- "@fayz-ai/shop": "^0.9.0",
76
- "@fayz-ai/storefront": "^0.9.0",
77
- "@fayz-ai/portal": "^0.9.0",
78
- "@fayz-ai/courses": "^0.9.0",
79
- "@fayz-ai/db": "^0.9.0",
80
- "@fayz-ai/plugin-agenda": "^0.9.0",
81
- "@fayz-ai/plugin-auth": "^0.9.0",
82
- "@fayz-ai/plugin-automations": "^0.9.0",
83
- "@fayz-ai/plugin-blog": "^0.9.0",
84
- "@fayz-ai/plugin-conversations": "^0.9.0",
85
- "@fayz-ai/plugin-courses": "^0.9.0",
86
- "@fayz-ai/plugin-crm": "^0.9.0",
87
- "@fayz-ai/plugin-dashboard": "^0.9.0",
88
- "@fayz-ai/plugin-financial": "^0.9.0",
89
- "@fayz-ai/plugin-forms": "^0.9.0",
90
- "@fayz-ai/plugin-inventory": "^0.9.0",
91
- "@fayz-ai/plugin-marketing": "^0.9.0",
92
- "@fayz-ai/plugin-menu": "^0.9.0",
93
- "@fayz-ai/plugin-orders": "^0.9.0",
94
- "@fayz-ai/plugin-payments": "^0.9.0",
95
- "@fayz-ai/plugin-reports": "^0.9.0",
96
- "@fayz-ai/plugin-reputation": "^0.9.0",
97
- "@fayz-ai/plugin-shop": "^0.9.0",
98
- "@fayz-ai/plugin-sites": "^0.9.0",
99
- "@fayz-ai/plugin-tables": "^0.9.0",
100
- "@fayz-ai/plugin-tasks": "^0.9.0"
101
- }
102
- }
103
- }
@@ -1,41 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import releaseChannels from './release-channels.json' with { type: 'json' }
3
- import {
4
- resolveFayzPackageDependencies,
5
- fayzPackageVersionSets,
6
- resolveFayzPackageVersion,
7
- resolveFayzPackageVersions,
8
- } from './release-channels'
9
-
10
- describe('release channels', () => {
11
- it('keeps stable as the default channel', () => {
12
- expect(resolveFayzPackageVersions()).toEqual({
13
- channel: 'stable',
14
- packages: releaseChannels.channels.stable,
15
- })
16
- expect(resolveFayzPackageVersions().packages['@fayz-ai/sdk']).toBe(releaseChannels.channels.stable['@fayz-ai/sdk'])
17
- })
18
-
19
- it('returns a copy of package dependencies', () => {
20
- const dependencies = resolveFayzPackageDependencies()
21
- dependencies['@fayz-ai/sdk'] = 'tampered'
22
-
23
- expect(resolveFayzPackageDependencies()['@fayz-ai/sdk']).toBe(releaseChannels.channels.stable['@fayz-ai/sdk'])
24
- })
25
-
26
- it('throws when a package is not mapped for a channel', () => {
27
- expect(() => resolveFayzPackageVersion('@fayz-ai/app-runtime')).toThrow(
28
- 'No Fayz package version configured for @fayz-ai/app-runtime in stable channel',
29
- )
30
- })
31
-
32
- it('keeps the machine-readable release-channel manifest aligned with the typed export', () => {
33
- expect(releaseChannels).toEqual({
34
- channels: {
35
- stable: fayzPackageVersionSets.stable.packages,
36
- latest: fayzPackageVersionSets.latest.packages,
37
- preview: fayzPackageVersionSets.preview.packages,
38
- },
39
- })
40
- })
41
- })
@@ -1,41 +0,0 @@
1
- import releaseChannels from './release-channels.json'
2
-
3
- export type FayzPackageChannel = 'stable' | 'latest' | 'preview'
4
-
5
- export interface FayzPackageVersionSet {
6
- channel: FayzPackageChannel
7
- packages: Record<string, string>
8
- }
9
-
10
- const releaseChannelPackages = releaseChannels.channels as Record<FayzPackageChannel, Record<string, string>>
11
-
12
- function buildVersionSet(channel: FayzPackageChannel): FayzPackageVersionSet {
13
- return {
14
- channel,
15
- packages: { ...releaseChannelPackages[channel] },
16
- }
17
- }
18
-
19
- export const fayzPackageVersionSets: Record<FayzPackageChannel, FayzPackageVersionSet> = {
20
- stable: buildVersionSet('stable'),
21
- latest: buildVersionSet('latest'),
22
- preview: buildVersionSet('preview'),
23
- }
24
-
25
- export function resolveFayzPackageVersions(channel: FayzPackageChannel = 'stable'): FayzPackageVersionSet {
26
- return fayzPackageVersionSets[channel]
27
- }
28
-
29
- export function resolveFayzPackageDependencies(channel: FayzPackageChannel = 'stable'): Record<string, string> {
30
- return { ...resolveFayzPackageVersions(channel).packages }
31
- }
32
-
33
- export function resolveFayzPackageVersion(packageName: string, channel: FayzPackageChannel = 'stable'): string {
34
- const version = resolveFayzPackageVersions(channel).packages[packageName]
35
-
36
- if (!version) {
37
- throw new Error(`No Fayz package version configured for ${packageName} in ${channel} channel`)
38
- }
39
-
40
- return version
41
- }
@@ -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
- })