@fiction/sdk 1.0.67 → 1.0.69
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/README.md +525 -5
- package/dist/{SelfProvider.vue_vue_type_script_setup_true_lang-BqMkZtWQ.js → SelfProvider.vue_vue_type_script_setup_true_lang-BbEo445n.js} +2 -2
- package/dist/{SelfProvider.vue_vue_type_script_setup_true_lang-BqMkZtWQ.js.map → SelfProvider.vue_vue_type_script_setup_true_lang-BbEo445n.js.map} +1 -1
- package/dist/{SelfWidgetInline-Crm-TMBK.js → SelfWidgetInline-DcJoMxUE.js} +2 -2
- package/dist/{SelfWidgetInline-Crm-TMBK.js.map → SelfWidgetInline-DcJoMxUE.js.map} +1 -1
- package/dist/{SelfWidgetModal-CN2sw2ra.js → SelfWidgetModal-B-FWtiDd.js} +2 -2
- package/dist/{SelfWidgetModal-CN2sw2ra.js.map → SelfWidgetModal-B-FWtiDd.js.map} +1 -1
- package/dist/{SelfWidgetPopup-C9iSKR2D.js → SelfWidgetPopup-BbrEUvSC.js} +2 -2
- package/dist/{SelfWidgetPopup-C9iSKR2D.js.map → SelfWidgetPopup-BbrEUvSC.js.map} +1 -1
- package/dist/{SelfWrap.vue_vue_type_script_setup_true_lang-BQS3okin.js → SelfWrap.vue_vue_type_script_setup_true_lang-DcjZRnSG.js} +3 -3
- package/dist/SelfWrap.vue_vue_type_script_setup_true_lang-DcjZRnSG.js.map +1 -0
- package/dist/constants/socialPlatforms.d.ts +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/sdk.css +1 -1
- package/dist/sdk.js +6 -4
- package/dist/sdk.js.map +1 -1
- package/dist/self/schema.d.ts +1 -1
- package/dist/self.js +3 -3
- package/dist/socialPlatforms-CuH51wxS.js +75 -0
- package/dist/socialPlatforms-CuH51wxS.js.map +1 -0
- package/dist/widget.js +23 -23
- package/dist/widget.js.map +1 -1
- package/package.json +6 -2
- package/dist/SelfWrap.vue_vue_type_script_setup_true_lang-BQS3okin.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,19 +1,539 @@
|
|
|
1
1
|
# Fiction SDK
|
|
2
2
|
|
|
3
|
-
Lightweight client library for Fiction-owned
|
|
3
|
+
Lightweight client library for Fiction digital self integration. Built for Fiction-owned properties (app, www, widget).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
npm install @fiction/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { FictionSDK } from '@fiction/sdk'
|
|
15
|
+
|
|
16
|
+
// Singleton pattern - shares state across your app
|
|
17
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
18
|
+
|
|
19
|
+
// Get public digital self
|
|
20
|
+
const self = await sdk.getPublicSelf({ handle: 'andrew' })
|
|
21
|
+
|
|
22
|
+
// Authenticate user
|
|
23
|
+
await sdk.requestAuthCode({ email: 'user@example.com' })
|
|
24
|
+
await sdk.loginWithCode({ email: 'user@example.com', code: '123456' })
|
|
25
|
+
|
|
26
|
+
// Access reactive state
|
|
27
|
+
console.log(sdk.activeUser.value)
|
|
28
|
+
console.log(sdk.currentSelf.value)
|
|
29
|
+
console.log(sdk.currentOrg.value)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Core Philosophy
|
|
33
|
+
|
|
34
|
+
**Minimal API Surface**: Clean wrapper methods hide internal complexity. No direct `apiClient` exposure prevents type generation issues.
|
|
35
|
+
|
|
36
|
+
**Self-First Architecture**: Digital selves are primary entities. Organization context derived from self, not passed redundantly.
|
|
37
|
+
|
|
38
|
+
**Singleton by Default**: Browser-only singleton prevents duplicate API calls and separate reactive state. Multiple `getInstance()` calls return same instance.
|
|
39
|
+
|
|
40
|
+
**SSR-Safe**: No singleton in Node.js—each request gets new instance to prevent request bleeding.
|
|
41
|
+
|
|
42
|
+
## Public API
|
|
43
|
+
|
|
44
|
+
### Authentication
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// Request email verification code
|
|
48
|
+
await sdk.requestAuthCode({ email: 'user@example.com' })
|
|
49
|
+
|
|
50
|
+
// Login with code
|
|
51
|
+
await sdk.loginWithCode({
|
|
52
|
+
email: 'user@example.com',
|
|
53
|
+
code: '123456'
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// Get current user
|
|
57
|
+
const user = await sdk.getCurrentUser()
|
|
58
|
+
|
|
59
|
+
// Logout
|
|
60
|
+
await sdk.logout()
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Digital Self Access
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Public self by handle (no auth)
|
|
67
|
+
const self = await sdk.getPublicSelf({ handle: 'andrew' })
|
|
68
|
+
|
|
69
|
+
// Public self by email (no auth)
|
|
70
|
+
const self = await sdk.getSelfByEmail({ email: 'andrew@fiction.com' })
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Usage Tracking
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Unified tracking method
|
|
77
|
+
await sdk.trackUsage({
|
|
78
|
+
selfId: 'slf_456', // Self contains orgId
|
|
79
|
+
type: 'voice', // 'voice' | 'chat'
|
|
80
|
+
quantity: 45, // Seconds for voice, characters for chat
|
|
81
|
+
participantId: 'usr_123' // Optional: conversation participant
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Reactive State
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// Core state
|
|
89
|
+
sdk.activeUser.value // EnrichedUser | undefined
|
|
90
|
+
sdk.token.value // string | null
|
|
91
|
+
sdk.loading.value // boolean
|
|
92
|
+
sdk.error.value // string | null
|
|
93
|
+
|
|
94
|
+
// Computed properties (auto-derived from activeUser)
|
|
95
|
+
sdk.currentSelf.value // Self | undefined
|
|
96
|
+
sdk.currentOrg.value // OrgInfo | undefined
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Singleton Pattern
|
|
100
|
+
|
|
101
|
+
**Why Singleton**: Prevents duplicate API requests and maintains shared reactive state across your application.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Both return same instance
|
|
105
|
+
const sdk1 = FictionSDK.getInstance({ isDev: true })
|
|
106
|
+
const sdk2 = FictionSDK.getInstance({ isDev: true })
|
|
107
|
+
|
|
108
|
+
console.log(sdk1 === sdk2) // true
|
|
109
|
+
|
|
110
|
+
// Reactive state shared
|
|
111
|
+
sdk1.token.value = 'test-token'
|
|
112
|
+
console.log(sdk2.token.value) // 'test-token'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Cross-Bundle Singleton**: Uses `globalThis` to share instance between separate bundles (www + widget).
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Global SDK (www.fiction.com)
|
|
119
|
+
window.fictionSDK = FictionSDK.getInstance({ isDev: true })
|
|
120
|
+
|
|
121
|
+
// Widget automatically uses singleton
|
|
122
|
+
const widget = new FictionWidget({ handle: 'andrew' })
|
|
123
|
+
console.log(window.fictionSDK === widget.sdk) // true
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Testing Pattern**: Use `clear()` to reset singleton between tests.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { afterEach, it, expect } from 'vitest'
|
|
130
|
+
|
|
131
|
+
afterEach(() => {
|
|
132
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
133
|
+
sdk.clear() // Clears session + state + destroys singleton
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('should test singleton behavior', () => {
|
|
137
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
138
|
+
// Test runs with clean state
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Environment Detection**: `apiBase` auto-detected from environment. Only override for testing.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// ✅ Normal usage (95%+ cases) - apiBase omitted
|
|
146
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
147
|
+
// Dev: http://localhost:5555 (auto)
|
|
148
|
+
// Prod: https://app.fiction.com (auto)
|
|
149
|
+
|
|
150
|
+
// ✅ Testing only - custom apiBase
|
|
151
|
+
const testSDK = FictionSDK.getInstance({
|
|
152
|
+
isDev: true,
|
|
153
|
+
apiBase: 'http://localhost:9999'
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Usage Patterns
|
|
158
|
+
|
|
159
|
+
### Blog Author Attribution
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Astro component (www.fiction.com)
|
|
163
|
+
import { FictionSDK } from '@fiction/sdk'
|
|
164
|
+
|
|
165
|
+
const sdk = FictionSDK.getInstance({ isDev: import.meta.env.DEV })
|
|
166
|
+
const authorSelf = await sdk.getSelfByEmail({ email: 'andrew@fiction.com' })
|
|
167
|
+
|
|
168
|
+
// Use digital self data instead of static strings
|
|
169
|
+
const authorAvatar = authorSelf?.avatar?.url
|
|
170
|
+
const authorName = authorSelf?.name
|
|
171
|
+
const authorBio = authorSelf?.summary
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Widget Integration
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { FictionWidget } from '@fiction/sdk/widget'
|
|
178
|
+
|
|
179
|
+
const widget = new FictionWidget({
|
|
180
|
+
mode: 'modal', // 'inline' | 'popup' | 'modal'
|
|
181
|
+
handle: 'andrew', // Or provide self object directly
|
|
182
|
+
context: 'support', // Optional: agent context override
|
|
183
|
+
firstMessage: 'Hi!' // Optional: custom greeting
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
// Update without re-mount
|
|
187
|
+
widget.update({
|
|
188
|
+
self: newSelf,
|
|
189
|
+
context: 'sales'
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// Cleanup
|
|
193
|
+
widget.destroy()
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Profile Page
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { SelfAgent } from '@fiction/sdk/self'
|
|
200
|
+
|
|
201
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
202
|
+
const self = await sdk.getPublicSelf({ handle: 'andrew' })
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```vue
|
|
206
|
+
<template>
|
|
207
|
+
<SelfAgent
|
|
208
|
+
:sdk="sdk"
|
|
209
|
+
:self="self"
|
|
210
|
+
theme-color="#3b82f6"
|
|
211
|
+
/>
|
|
212
|
+
</template>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Error Handling
|
|
216
|
+
|
|
217
|
+
All wrapper methods return `undefined` on error (no exceptions thrown). Check reactive error state for details.
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
const self = await sdk.getPublicSelf({ handle: 'nonexistent' })
|
|
221
|
+
|
|
222
|
+
if (!self) {
|
|
223
|
+
console.error(sdk.error.value) // 'Self not found'
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Build Strategy
|
|
228
|
+
|
|
229
|
+
**SDK Build**: ES modules, tree-shakeable, externals (Vue, ElevenLabs)
|
|
230
|
+
- Format: ES modules
|
|
231
|
+
- Bundle size: < 256KB
|
|
232
|
+
- Build time: 5 seconds
|
|
233
|
+
|
|
234
|
+
**Widget Build**: IIFE, single-file CDN bundle
|
|
235
|
+
- Format: IIFE (global `window.FictionWidget`)
|
|
236
|
+
- Bundle size: < 1MB
|
|
237
|
+
- Includes all dependencies
|
|
238
|
+
|
|
239
|
+
## Import Patterns
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// ✅ Correct - Use bundled entry points
|
|
243
|
+
import { FictionSDK } from '@fiction/sdk'
|
|
244
|
+
import { SelfAgent, SelfProvider } from '@fiction/sdk/self'
|
|
245
|
+
import { FictionWidget } from '@fiction/sdk/widget'
|
|
246
|
+
import { getDemoSelves } from '@fiction/sdk/demo'
|
|
247
|
+
|
|
248
|
+
// ❌ Wrong - Deep imports don't work
|
|
249
|
+
import { FictionSDK } from '@fiction/sdk/FictionSDK'
|
|
250
|
+
import SelfAgent from '@fiction/sdk/self/ui/SelfAgent.vue'
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Package Exports
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"exports": {
|
|
258
|
+
".": {
|
|
259
|
+
"import": "./dist/sdk.js",
|
|
260
|
+
"types": "./dist/sdk.d.ts"
|
|
261
|
+
},
|
|
262
|
+
"./self": {
|
|
263
|
+
"import": "./dist/self.js",
|
|
264
|
+
"types": "./dist/self.d.ts"
|
|
265
|
+
},
|
|
266
|
+
"./widget": {
|
|
267
|
+
"import": "./dist/widget.js",
|
|
268
|
+
"types": "./dist/widget.d.ts"
|
|
269
|
+
},
|
|
270
|
+
"./demo": {
|
|
271
|
+
"import": "./dist/demo.js",
|
|
272
|
+
"types": "./dist/demo/index.d.ts"
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
10
276
|
```
|
|
11
277
|
|
|
12
|
-
##
|
|
278
|
+
## Self-First Architecture
|
|
279
|
+
|
|
280
|
+
Digital selves are primary entities that determine organizational context.
|
|
13
281
|
|
|
14
282
|
```typescript
|
|
283
|
+
// ✅ Self contains all context
|
|
284
|
+
await sdk.trackUsage({
|
|
285
|
+
selfId: 'slf_456', // Includes orgId internally
|
|
286
|
+
type: 'voice',
|
|
287
|
+
quantity: 45
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
// ❌ Don't pass redundant orgId
|
|
291
|
+
await sdk.trackUsage({
|
|
292
|
+
orgId: 'org_123', // Redundant - derived from selfId
|
|
293
|
+
selfId: 'slf_456',
|
|
294
|
+
type: 'voice',
|
|
295
|
+
quantity: 45
|
|
296
|
+
})
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Benefits**:
|
|
300
|
+
- Simpler APIs (fewer parameters)
|
|
301
|
+
- Single source of truth (self determines org)
|
|
302
|
+
- Automatic context resolution
|
|
303
|
+
- Consistent across all SDK methods
|
|
304
|
+
|
|
305
|
+
## Reactive State Pattern
|
|
306
|
+
|
|
307
|
+
SDK maintains reactive state that auto-updates components.
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
311
|
+
|
|
312
|
+
// Core refs (direct state)
|
|
313
|
+
sdk.activeUser.value // Updated by auth operations
|
|
314
|
+
sdk.token.value // Updated by login/logout
|
|
315
|
+
sdk.loading.value // Updated during API calls
|
|
316
|
+
sdk.error.value // Updated on errors
|
|
317
|
+
|
|
318
|
+
// Computed properties (auto-derived)
|
|
319
|
+
sdk.currentSelf.value = computed(() => {
|
|
320
|
+
const user = sdk.activeUser.value
|
|
321
|
+
if (!user?.selves) return undefined
|
|
322
|
+
|
|
323
|
+
const selfId = user.primarySelfId || user.selves[0]?.selfId
|
|
324
|
+
return user.selves.find(s => s.selfId === selfId)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
sdk.currentOrg.value = computed(() => {
|
|
328
|
+
const self = sdk.currentSelf.value
|
|
329
|
+
if (!self?.orgId) return undefined
|
|
330
|
+
|
|
331
|
+
return sdk.activeUser.value?.orgs.find(org =>
|
|
332
|
+
org.orgId === self.orgId
|
|
333
|
+
)
|
|
334
|
+
})
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Benefits**:
|
|
338
|
+
- Components auto-update when user changes
|
|
339
|
+
- No manual state management needed
|
|
340
|
+
- Consistent with Fiction app patterns
|
|
341
|
+
- Self-first architecture (org derived from self)
|
|
342
|
+
|
|
343
|
+
## Component Integration
|
|
344
|
+
|
|
345
|
+
### Prop-Based Dependency Injection
|
|
346
|
+
|
|
347
|
+
SDK components accept `sdk` prop instead of using global services.
|
|
348
|
+
|
|
349
|
+
```vue
|
|
350
|
+
<script setup>
|
|
15
351
|
import { FictionSDK } from '@fiction/sdk'
|
|
16
352
|
import { SelfAgent } from '@fiction/sdk/self'
|
|
353
|
+
|
|
354
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
355
|
+
const self = await sdk.getPublicSelf({ handle: 'andrew' })
|
|
356
|
+
</script>
|
|
357
|
+
|
|
358
|
+
<template>
|
|
359
|
+
<SelfAgent
|
|
360
|
+
:sdk="sdk"
|
|
361
|
+
:self="self"
|
|
362
|
+
theme-color="#3b82f6"
|
|
363
|
+
/>
|
|
364
|
+
</template>
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Available Components
|
|
368
|
+
|
|
369
|
+
**SelfAgent** - Main agent interface (chat/voice)
|
|
370
|
+
**SelfProvider** - Handle → self resolver wrapper
|
|
371
|
+
**SelfAbout** - Profile information display
|
|
372
|
+
**SelfChat** - Text chat interface
|
|
373
|
+
**SelfVoice** - Voice call interface
|
|
374
|
+
**SelfSidebar** - Navigation sidebar
|
|
375
|
+
|
|
376
|
+
## Demo Data
|
|
377
|
+
|
|
378
|
+
Static demo selves for marketing/showcase.
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { getDemoSelves, getDemoSelfByHandle } from '@fiction/sdk/demo'
|
|
382
|
+
|
|
383
|
+
// All demo selves
|
|
384
|
+
const demoSelves = getDemoSelves()
|
|
385
|
+
|
|
386
|
+
// Specific demo self
|
|
387
|
+
const andrew = getDemoSelfByHandle('andrew')
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Single Source of Truth**: Demo data maintained in Fiction app at `src/modules/self/static/data.ts`, bundled into SDK at build time.
|
|
391
|
+
|
|
392
|
+
## Security Model
|
|
393
|
+
|
|
394
|
+
**Public-Only Access**: `getPublicSelf()` and `getSelfByEmail()` only return selves with `visibility: 'public'`.
|
|
395
|
+
|
|
396
|
+
**Authentication Required**: User operations require valid JWT token in `sdk.token.value`.
|
|
397
|
+
|
|
398
|
+
**Rate Limiting**: Widget includes 10 comments/hour per self, 100 likes/hour (future).
|
|
399
|
+
|
|
400
|
+
## Performance Optimization
|
|
401
|
+
|
|
402
|
+
**Single Query Pattern**: Public endpoints use single SQL query with LEFT JOINs for media.
|
|
403
|
+
|
|
404
|
+
**Voice Recordings Excluded**: Public endpoints exclude voice recordings (performance).
|
|
405
|
+
|
|
406
|
+
**Build Time Bundling**: App dependencies (`@/` imports) bundled during SDK build.
|
|
407
|
+
|
|
408
|
+
**Ultra-Fast Builds**: 5-second builds via custom tsconfig + esbuild optimization.
|
|
409
|
+
|
|
410
|
+
## Type Safety
|
|
411
|
+
|
|
412
|
+
**Full TypeScript Inference**: From API routes to SDK methods to component props.
|
|
413
|
+
|
|
414
|
+
**Wrapper Method Pattern**: Clean function signatures serialize perfectly to `.d.ts` files.
|
|
415
|
+
|
|
416
|
+
**No Complex Types**: Simple `Promise<Self | undefined>` instead of Hono RPC types.
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
// Clean wrapper method
|
|
420
|
+
async getPublicSelf(args: {
|
|
421
|
+
handle: string
|
|
422
|
+
}): Promise<Self | undefined>
|
|
423
|
+
|
|
424
|
+
// Internal complexity hidden
|
|
425
|
+
const response = await this.api.self.public[':handle'].$get({
|
|
426
|
+
param: { handle: args.handle }
|
|
427
|
+
})
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Best Practices
|
|
431
|
+
|
|
432
|
+
**1. Use Singleton**: Always use `getInstance()` instead of `new FictionSDK()`.
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
// ✅ Recommended
|
|
436
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
437
|
+
|
|
438
|
+
// ⚠️ Works but creates singleton anyway
|
|
439
|
+
const sdk = new FictionSDK({ isDev: true })
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**2. Don't Override apiBase**: Let SDK auto-detect environment.
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
// ✅ Normal usage
|
|
446
|
+
const sdk = FictionSDK.getInstance({ isDev: true })
|
|
447
|
+
|
|
448
|
+
// ❌ Only for testing
|
|
449
|
+
const sdk = FictionSDK.getInstance({
|
|
450
|
+
isDev: true,
|
|
451
|
+
apiBase: 'http://localhost:9999'
|
|
452
|
+
})
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**3. Clear Between Tests**: Use `clear()` for test isolation.
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
afterEach(() => {
|
|
459
|
+
FictionSDK.getInstance({ isDev: true }).clear()
|
|
460
|
+
})
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**4. Check Error State**: Methods return `undefined` on error.
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
const self = await sdk.getPublicSelf({ handle: 'test' })
|
|
467
|
+
if (!self) {
|
|
468
|
+
console.error(sdk.error.value)
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**5. Self-First APIs**: Pass `selfId`, let SDK resolve `orgId`.
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
// ✅ Minimal args
|
|
476
|
+
await sdk.trackUsage({ selfId, type, quantity })
|
|
477
|
+
|
|
478
|
+
// ❌ Redundant args
|
|
479
|
+
await sdk.trackUsage({ orgId, selfId, type, quantity })
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Architecture Principles
|
|
483
|
+
|
|
484
|
+
**Minimal Case First**: Start with simplest implementation, add complexity only when needed.
|
|
485
|
+
|
|
486
|
+
**No Globals**: All state via dependency injection (SDK prop pattern).
|
|
487
|
+
|
|
488
|
+
**Bundle Safety**: Server code never reaches client (strict separation).
|
|
489
|
+
|
|
490
|
+
**Validated Environment**: Auto-detected `apiBase` based on environment.
|
|
491
|
+
|
|
492
|
+
**Static Chaining**: Preserves Hono type inference for internal operations.
|
|
493
|
+
|
|
494
|
+
## Browser Compatibility
|
|
495
|
+
|
|
496
|
+
**Singleton Scope**: `globalThis` for cross-bundle state sharing.
|
|
497
|
+
|
|
498
|
+
**SSR Detection**: `typeof window === 'undefined'` prevents Node.js singleton.
|
|
499
|
+
|
|
500
|
+
**Storage**: localStorage for user data, cookies for auth tokens.
|
|
501
|
+
|
|
502
|
+
**Vue 3.6+**: Required for reactive refs and computed properties.
|
|
503
|
+
|
|
504
|
+
## Development
|
|
505
|
+
|
|
506
|
+
```bash
|
|
507
|
+
# Watch mode - rebuilds on change
|
|
508
|
+
pnpm dev
|
|
509
|
+
|
|
510
|
+
# Production build (ES modules + types)
|
|
511
|
+
pnpm build
|
|
512
|
+
|
|
513
|
+
# Run tests
|
|
514
|
+
pnpm test
|
|
515
|
+
|
|
516
|
+
# Typecheck
|
|
517
|
+
pnpm typecheck
|
|
17
518
|
```
|
|
18
519
|
|
|
19
520
|
**Build required before typecheck** - Widget/www import from `dist/`, not source.
|
|
521
|
+
|
|
522
|
+
## Contributing
|
|
523
|
+
|
|
524
|
+
This SDK is for Fiction-owned projects only. For internal development:
|
|
525
|
+
|
|
526
|
+
1. Make changes in `packages/sdk/`
|
|
527
|
+
2. Build: `pnpm run sdk:build`
|
|
528
|
+
3. Test: `pnpm test packages/sdk/test/`
|
|
529
|
+
4. Update this README if public API changes
|
|
530
|
+
|
|
531
|
+
## License
|
|
532
|
+
|
|
533
|
+
Proprietary - Fiction Co.
|
|
534
|
+
|
|
535
|
+
## Support
|
|
536
|
+
|
|
537
|
+
Internal developers: See `.ai/spec-sdk.md` for complete architecture documentation.
|
|
538
|
+
|
|
539
|
+
External users: Contact support@fiction.com
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent as i, createBlock as n, openBlock as f, mergeProps as c, withCtx as m, createVNode as p } from "vue";
|
|
2
|
-
import { _ as d, a as _ } from "./SelfWrap.vue_vue_type_script_setup_true_lang-
|
|
2
|
+
import { _ as d, a as _ } from "./SelfWrap.vue_vue_type_script_setup_true_lang-DcjZRnSG.js";
|
|
3
3
|
const g = /* @__PURE__ */ i({
|
|
4
4
|
__name: "SelfProvider",
|
|
5
5
|
props: {
|
|
@@ -35,4 +35,4 @@ const g = /* @__PURE__ */ i({
|
|
|
35
35
|
export {
|
|
36
36
|
g as _
|
|
37
37
|
};
|
|
38
|
-
//# sourceMappingURL=SelfProvider.vue_vue_type_script_setup_true_lang-
|
|
38
|
+
//# sourceMappingURL=SelfProvider.vue_vue_type_script_setup_true_lang-BbEo445n.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelfProvider.vue_vue_type_script_setup_true_lang-
|
|
1
|
+
{"version":3,"file":"SelfProvider.vue_vue_type_script_setup_true_lang-BbEo445n.js","sources":["../self/ui/SelfProvider.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { FictionSDK } from '../../sdkClient'\nimport type { Self } from '../schema'\nimport SelfAgent from './SelfAgent.vue'\nimport SelfWrap from './SelfWrap.vue'\n\nconst props = defineProps<{\n sdk?: FictionSDK\n self?: Self\n handle?: string\n context?: string\n firstMessage?: string\n hasClose?: boolean\n apiBase?: string\n}>()\n\nconst emit = defineEmits<{\n close: [value: string]\n error: [message: string]\n}>()\n\n</script>\n\n<template>\n <SelfWrap\n v-slot=\"slotProps\"\n v-bind=\"props\"\n class=\"self-provider size-full relative\"\n >\n <SelfAgent\n :sdk=\"slotProps.sdk\"\n :self=\"slotProps.self\"\n :context=\"slotProps.context\"\n :first-message=\"slotProps.firstMessage\"\n :has-close=\"props.hasClose\"\n :is-active=\"true\"\n class=\"size-full\"\n @close=\"emit('close', $event)\"\n @error=\"emit('error', $event)\"\n />\n </SelfWrap>\n</template>\n"],"names":["props","__props","emit","__emit","_openBlock","_createBlock","SelfWrap","_mergeProps","_withCtx","slotProps","_createVNode","SelfAgent","_cache","$event"],"mappings":";;;;;;;;;;;;;;;AAMA,UAAMA,IAAQC,GAURC,IAAOC;sBAQXC,EAAA,GAAAC,EAgBWC,GAhBXC,EAgBWP,GAdI,EACb,OAAM,mCAAA,CAAkC,GAAA;AAAA,MAExC,SAAAQ,EAAA,CAJQC,MAAS;AAAA,QAIjBC,EAUEC,GAAA;AAAA,UATC,KAAKF,EAAU;AAAA,UACf,MAAMA,EAAU;AAAA,UAChB,SAASA,EAAU;AAAA,UACnB,iBAAeA,EAAU;AAAA,UACzB,aAAWT,EAAM;AAAA,UACjB,aAAW;AAAA,UACZ,OAAM;AAAA,UACL,SAAKY,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAEX,EAAI,SAAUW,CAAM;AAAA,UAC3B,SAAKD,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAEX,EAAI,SAAUW,CAAM;AAAA,QAAA;;;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var i = Object.defineProperty;
|
|
2
2
|
var c = (s, t) => i(s, "name", { value: t, configurable: !0 });
|
|
3
3
|
import { defineComponent as u, ref as o, createBlock as d, openBlock as m } from "vue";
|
|
4
|
-
import { _ as x } from "./SelfProvider.vue_vue_type_script_setup_true_lang-
|
|
4
|
+
import { _ as x } from "./SelfProvider.vue_vue_type_script_setup_true_lang-BbEo445n.js";
|
|
5
5
|
const M = /* @__PURE__ */ u({
|
|
6
6
|
__name: "SelfWidgetInline",
|
|
7
7
|
props: {
|
|
@@ -28,4 +28,4 @@ const M = /* @__PURE__ */ u({
|
|
|
28
28
|
export {
|
|
29
29
|
M as default
|
|
30
30
|
};
|
|
31
|
-
//# sourceMappingURL=SelfWidgetInline-
|
|
31
|
+
//# sourceMappingURL=SelfWidgetInline-DcJoMxUE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelfWidgetInline-
|
|
1
|
+
{"version":3,"file":"SelfWidgetInline-DcJoMxUE.js","sources":["../widget/ui/SelfWidgetInline.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { FictionSDK } from '../../sdkClient'\nimport type { Self } from '@fiction/types'\nimport { ref } from 'vue'\nimport SelfProvider from '../../self/ui/SelfProvider.vue'\n\nexport interface WidgetUpdate {\n self?: Self\n context?: string\n firstMessage?: string\n}\n\nconst props = defineProps<{\n sdk?: FictionSDK\n handle?: string\n self?: Self\n context?: string\n firstMessage?: string\n}>()\n\n// Local state for updateable props\nconst currentSelf = ref<Self | undefined>(props.self)\nconst currentContext = ref<string | undefined>(props.context)\nconst currentFirstMessage = ref<string | undefined>(props.firstMessage)\n\nfunction update(updates: WidgetUpdate) {\n if (updates.self !== undefined)\n currentSelf.value = updates.self\n if (updates.context !== undefined)\n currentContext.value = updates.context\n if (updates.firstMessage !== undefined)\n currentFirstMessage.value = updates.firstMessage\n}\n\ndefineExpose({ update })\n</script>\n\n<template>\n <SelfProvider\n :sdk=\"sdk\"\n :handle=\"handle\"\n :self=\"currentSelf\"\n :context=\"currentContext\"\n :first-message=\"currentFirstMessage\"\n />\n</template>\n"],"names":["props","__props","currentSelf","ref","currentContext","currentFirstMessage","update","updates","__name","__expose","_createBlock","SelfProvider"],"mappings":";;;;;;;;;;;;;;AAYA,UAAMA,IAAQC,GASRC,IAAcC,EAAsBH,EAAM,IAAI,GAC9CI,IAAiBD,EAAwBH,EAAM,OAAO,GACtDK,IAAsBF,EAAwBH,EAAM,YAAY;AAEtE,aAASM,EAAOC,GAAuB;AACrC,MAAIA,EAAQ,SAAS,WACnBL,EAAY,QAAQK,EAAQ,OAC1BA,EAAQ,YAAY,WACtBH,EAAe,QAAQG,EAAQ,UAC7BA,EAAQ,iBAAiB,WAC3BF,EAAoB,QAAQE,EAAQ;AAAA,IACxC;AAPS,WAAAC,EAAAF,GAAA,WASTG,EAAa,EAAE,QAAAH,GAAQ,mBAIrBI,EAMEC,GAAA;AAAA,MALC,KAAKV,EAAA;AAAA,MACL,QAAQA,EAAA;AAAA,MACR,MAAMC,EAAA;AAAA,MACN,SAASE,EAAA;AAAA,MACT,iBAAeC,EAAA;AAAA,IAAA;;;"}
|
|
@@ -2,7 +2,7 @@ var x = Object.defineProperty;
|
|
|
2
2
|
var n = (s, a) => x(s, "name", { value: a, configurable: !0 });
|
|
3
3
|
import { defineComponent as h, ref as l, onMounted as p, nextTick as g, createBlock as C, openBlock as k, withCtx as M, createVNode as _ } from "vue";
|
|
4
4
|
import { _ as w } from "./FModal.vue_vue_type_script_setup_true_lang-CUVfXWtt.js";
|
|
5
|
-
import { _ as T } from "./SelfProvider.vue_vue_type_script_setup_true_lang-
|
|
5
|
+
import { _ as T } from "./SelfProvider.vue_vue_type_script_setup_true_lang-BbEo445n.js";
|
|
6
6
|
const S = /* @__PURE__ */ h({
|
|
7
7
|
__name: "SelfWidgetModal",
|
|
8
8
|
props: {
|
|
@@ -59,4 +59,4 @@ const S = /* @__PURE__ */ h({
|
|
|
59
59
|
export {
|
|
60
60
|
S as default
|
|
61
61
|
};
|
|
62
|
-
//# sourceMappingURL=SelfWidgetModal-
|
|
62
|
+
//# sourceMappingURL=SelfWidgetModal-B-FWtiDd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelfWidgetModal-
|
|
1
|
+
{"version":3,"file":"SelfWidgetModal-B-FWtiDd.js","sources":["../widget/ui/SelfWidgetModal.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { FictionSDK } from '../../sdkClient'\nimport type { Self } from '@fiction/types'\nimport { nextTick, onMounted, ref } from 'vue'\nimport FModal from '@/ui/common/FModal.vue'\nimport SelfProvider from '../../self/ui/SelfProvider.vue'\n\nexport interface WidgetUpdate {\n self?: Self\n context?: string\n firstMessage?: string\n}\n\nconst props = defineProps<{\n sdk?: FictionSDK\n handle?: string\n self?: Self\n context?: string\n firstMessage?: string\n onClose?: () => void\n}>()\n\nconst currentSelf = ref<Self | undefined>(props.self)\nconst currentContext = ref<string | undefined>(props.context)\nconst currentFirstMessage = ref<string | undefined>(props.firstMessage)\nconst isVisible = ref(false)\n\n// Trigger transition after mount\nonMounted(async () => {\n await nextTick()\n // Small delay to ensure DOM is ready and transition fires\n setTimeout(() => {\n isVisible.value = true\n }, 10)\n})\n\nfunction update(updates: WidgetUpdate) {\n if (updates.self !== undefined)\n currentSelf.value = updates.self\n if (updates.context !== undefined)\n currentContext.value = updates.context\n if (updates.firstMessage !== undefined)\n currentFirstMessage.value = updates.firstMessage\n}\n\nfunction close() {\n isVisible.value = false\n // Wait for transition to complete before calling onClose\n setTimeout(() => {\n if (props.onClose) {\n props.onClose()\n }\n }, 300) // Match FModal transition duration\n}\n\nfunction open() {\n isVisible.value = true\n}\n\ndefineExpose({ update, close, open })\n</script>\n\n<template>\n <FModal\n :vis=\"isVisible\"\n :disable-teleport=\"true\"\n modal-class=\"max-w-4xl h-[80vh] md:h-[600px]\"\n :has-close=\"false\"\n @update:vis=\"isVisible = $event\"\n @close=\"close\"\n >\n <SelfProvider\n :sdk=\"sdk\"\n :handle=\"handle\"\n :self=\"currentSelf\"\n :context=\"currentContext\"\n :first-message=\"currentFirstMessage\"\n :has-close=\"true\"\n @close=\"close\"\n />\n </FModal>\n</template>\n"],"names":["props","__props","currentSelf","ref","currentContext","currentFirstMessage","isVisible","onMounted","nextTick","update","updates","__name","close","open","__expose","_createBlock","FModal","_cache","$event","_createVNode","SelfProvider"],"mappings":";;;;;;;;;;;;;;;;AAaA,UAAMA,IAAQC,GASRC,IAAcC,EAAsBH,EAAM,IAAI,GAC9CI,IAAiBD,EAAwBH,EAAM,OAAO,GACtDK,IAAsBF,EAAwBH,EAAM,YAAY,GAChEM,IAAYH,EAAI,EAAK;AAG3B,IAAAI,EAAU,YAAY;AACpB,YAAMC,EAAA,GAEN,WAAW,MAAM;AACf,QAAAF,EAAU,QAAQ;AAAA,MACpB,GAAG,EAAE;AAAA,IACP,CAAC;AAED,aAASG,EAAOC,GAAuB;AACrC,MAAIA,EAAQ,SAAS,WACnBR,EAAY,QAAQQ,EAAQ,OAC1BA,EAAQ,YAAY,WACtBN,EAAe,QAAQM,EAAQ,UAC7BA,EAAQ,iBAAiB,WAC3BL,EAAoB,QAAQK,EAAQ;AAAA,IACxC;AAPS,IAAAC,EAAAF,GAAA;AAST,aAASG,IAAQ;AACf,MAAAN,EAAU,QAAQ,IAElB,WAAW,MAAM;AACf,QAAIN,EAAM,WACRA,EAAM,QAAA;AAAA,MAEV,GAAG,GAAG;AAAA,IACR;AARS,IAAAW,EAAAC,GAAA;AAUT,aAASC,IAAO;AACd,MAAAP,EAAU,QAAQ;AAAA,IACpB;AAFS,WAAAK,EAAAE,GAAA,SAITC,EAAa,EAAE,QAAAL,GAAQ,OAAAG,GAAO,MAAAC,EAAA,CAAM,mBAIlCE,EAiBSC,GAAA;AAAA,MAhBN,KAAKV,EAAA;AAAA,MACL,oBAAkB;AAAA,MACnB,eAAY;AAAA,MACX,aAAW;AAAA,MACX,gBAAUW,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAEZ,EAAA,QAAYY;AAAA,MACxB,SAAON;AAAA,IAAA;iBAER,MAQE;AAAA,QARFO,EAQEC,GAAA;AAAA,UAPC,KAAKnB,EAAA;AAAA,UACL,QAAQA,EAAA;AAAA,UACR,MAAMC,EAAA;AAAA,UACN,SAASE,EAAA;AAAA,UACT,iBAAeC,EAAA;AAAA,UACf,aAAW;AAAA,UACX,SAAOO;AAAA,QAAA;;;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var M = Object.defineProperty;
|
|
2
2
|
var a = (l, u) => M(l, "name", { value: u, configurable: !0 });
|
|
3
3
|
import { defineComponent as A, ref as r, watch as S, nextTick as $, createBlock as x, openBlock as c, withCtx as B, createElementBlock as b, createCommentVNode as g, normalizeClass as w, createElementVNode as s, normalizeStyle as j, unref as k } from "vue";
|
|
4
|
-
import { _ as E, g as F, b as N, a as T } from "./SelfWrap.vue_vue_type_script_setup_true_lang-
|
|
4
|
+
import { _ as E, g as F, b as N, a as T } from "./SelfWrap.vue_vue_type_script_setup_true_lang-DcjZRnSG.js";
|
|
5
5
|
const U = {
|
|
6
6
|
key: 0,
|
|
7
7
|
class: "relative h-full w-full"
|
|
@@ -108,4 +108,4 @@ const U = {
|
|
|
108
108
|
export {
|
|
109
109
|
G as default
|
|
110
110
|
};
|
|
111
|
-
//# sourceMappingURL=SelfWidgetPopup-
|
|
111
|
+
//# sourceMappingURL=SelfWidgetPopup-BbrEUvSC.js.map
|