foundation-sdk 0.1.11 → 0.1.12
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/dist/index.cjs +0 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/README.md +0 -563
package/dist/index.cjs
CHANGED
|
@@ -255,11 +255,8 @@ function createFoundationClient() {
|
|
|
255
255
|
return isReady;
|
|
256
256
|
},
|
|
257
257
|
auth: authService,
|
|
258
|
-
// only logout - this is problematic - provides user and account
|
|
259
258
|
theme: themeService,
|
|
260
|
-
// only useful for themed tailwind projects - still useful anyway
|
|
261
259
|
router: routerService,
|
|
262
|
-
// once you're in app - external or container-ui level routing it just not very useful.
|
|
263
260
|
db: dbService,
|
|
264
261
|
ui: uiService,
|
|
265
262
|
storage: storageService,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/client.ts"],"sourcesContent":["import type {\n FoundationClient,\n User,\n Theme,\n RouterState,\n EntityDefinition,\n EntityChangeEvent,\n SDKReadyPayload,\n SDKResponse,\n AuthService,\n ThemeService,\n RouterService,\n DbService,\n UIService,\n StorageService,\n FilesService,\n LogService,\n ConfigService,\n StuffService\n} from './types'\n\nlet clientInstance: FoundationClient | null = null\n\nexport function createFoundationClient(): FoundationClient {\n if (clientInstance) {\n return clientInstance\n }\n\n let isReady = false\n let readyResolve: (() => void) | null = null\n let messageId = 0\n const pendingRequests = new Map<number, { resolve: (data: unknown) => void; reject: (error: Error) => void }>()\n\n let user: User | null = null\n let theme: Theme = { isDark: false, mode: 'system' }\n let router: RouterState = { path: '/', query: {}, hash: '' }\n let config: { features: Record<string, unknown>; app: { id?: string; name?: string; environment?: string } } = { features: {}, app: {} }\n let entities: EntityDefinition[] = []\n\n const themeListeners: Array<(theme: Theme) => void> = []\n const authListeners: Array<(user: User | null) => void> = []\n const routerListeners: Array<(route: RouterState) => void> = []\n const entityListeners: Array<(event: EntityChangeEvent) => void> = []\n\n const readyPromise = new Promise<void>((resolve) => {\n readyResolve = resolve\n })\n\n function send<T = unknown>(namespace: string, type: string, data: Record<string, unknown> = {}): Promise<T> {\n return new Promise((resolve, reject) => {\n const id = ++messageId\n pendingRequests.set(id, {\n resolve: resolve as (data: unknown) => void,\n reject\n })\n\n window.parent.postMessage({\n id,\n namespace,\n type: `${namespace}.${type}`,\n data\n }, '*')\n\n setTimeout(() => {\n if (pendingRequests.has(id)) {\n pendingRequests.delete(id)\n reject(new Error(`Request timeout: ${namespace}.${type}`))\n }\n }, 30000)\n })\n }\n\n function handleMessage(event: MessageEvent) {\n const message = event.data\n\n if (message?.type === 'SDK_READY') {\n const payload = message.data as SDKReadyPayload\n user = payload.user || null\n theme = payload.theme || { isDark: false, mode: 'system' }\n router = payload.router || { path: '/', query: {}, hash: '' }\n config = {\n features: payload.config?.features || {},\n app: payload.config?.app || {}\n }\n entities = payload.entities || []\n\n if (!isReady) {\n isReady = true\n readyResolve?.()\n }\n return\n }\n\n if (message?.type === 'THEME_CHANGED') {\n theme = message.data as Theme\n themeListeners.forEach(fn => {\n try { fn(theme) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'AUTH_CHANGED') {\n user = message.data?.user || null\n authListeners.forEach(fn => {\n try { fn(user) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ROUTER_CHANGED') {\n router = message.data as RouterState\n routerListeners.forEach(fn => {\n try { fn(router) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ENTITY_CHANGED') {\n const event = message.data as EntityChangeEvent\n entityListeners.forEach(fn => {\n try { fn(event) } catch { /* ignore */ }\n })\n return\n }\n\n if (typeof message?.id === 'number' && pendingRequests.has(message.id)) {\n const { resolve, reject } = pendingRequests.get(message.id)!\n pendingRequests.delete(message.id)\n\n const response = message as SDKResponse\n if (response.success) {\n resolve(response.data)\n } else {\n reject(new Error(response.error || 'Unknown error'))\n }\n }\n }\n\n window.addEventListener('message', handleMessage)\n\n const authService: AuthService = {\n get user() { return user },\n get isAuthenticated() { return !!user },\n getToken: () => send<string>('auth', 'getToken'),\n login: () => send<void>('auth', 'login'),\n logout: () => send<void>('auth', 'logout'),\n onChange(callback) {\n authListeners.push(callback)\n return () => {\n const idx = authListeners.indexOf(callback)\n if (idx > -1) authListeners.splice(idx, 1)\n }\n }\n }\n\n const themeService: ThemeService = {\n get isDark() { return theme.isDark },\n get mode() { return theme.mode },\n setTheme: (mode) => send<void>('ui', 'setTheme', { mode }),\n toggle: () => send<void>('ui', 'toggleTheme', {}),\n onChange(callback) {\n themeListeners.push(callback)\n return () => {\n const idx = themeListeners.indexOf(callback)\n if (idx > -1) themeListeners.splice(idx, 1)\n }\n }\n }\n\n const routerService: RouterService = {\n get path() { return router.path },\n get query() { return router.query },\n get hash() { return router.hash },\n push: (path, options = {}) => send<void>('router', 'push', { path, ...options }),\n replace: (path, options = {}) => send<void>('router', 'replace', { path, ...options }),\n setQuery: (params, options = {}) => send<void>('router', 'setQuery', { params, ...options }),\n onChange(callback) {\n routerListeners.push(callback)\n return () => {\n const idx = routerListeners.indexOf(callback)\n if (idx > -1) routerListeners.splice(idx, 1)\n }\n }\n }\n\n const dbService: DbService = {\n list: (entity, options = {}) => send('db', 'list', { entity, ...options }),\n get: (entity, id) => send('db', 'get', { entity, itemId: id }),\n create: (entity, item) => send('db', 'create', { entity, item }),\n update: (entity, id, updates) => send('db', 'update', { entity, itemId: id, updates }),\n delete: (entity, id) => send('db', 'delete', { entity, itemId: id })\n }\n\n const uiService: UIService = {\n toast: (message, type = 'info') => send('ui', 'toast', { message, toastType: type }),\n confirm: (message) => send('ui', 'confirm', { message }),\n loading: {\n show: (message) => send('ui', 'loading.show', { message }),\n hide: () => send('ui', 'loading.hide', {})\n },\n banner: {\n show: (message, options = {}) => send('ui', 'banner.show', { message, ...options }),\n hide: (bannerId) => send('ui', 'banner.hide', { bannerId })\n }\n }\n\n const storageService: StorageService = {\n upload: (options) => send('storage', 'upload', options),\n get: (fileId) => send('storage', 'get', { fileId }),\n delete: (fileId) => send('storage', 'delete', { fileId }),\n list: (options = {}) => send('storage', 'list', options)\n }\n\n const filesService: FilesService = {\n initiate: (options) => send('files', 'initiate', options),\n upload: async (options) => {\n // Convert File/Blob to ArrayBuffer for postMessage transfer\n let fileData: ArrayBuffer\n if (options.file instanceof ArrayBuffer) {\n fileData = options.file\n } else {\n // File or Blob - use arrayBuffer()\n fileData = await options.file.arrayBuffer()\n }\n\n return send('files', 'upload', {\n name: options.name,\n contentType: options.contentType,\n fileData,\n sha256: options.sha256\n })\n },\n get: (fileId) => send('files', 'get', { fileId }),\n delete: (fileId) => send('files', 'delete', { fileId }),\n list: (options = {}) => send('files', 'list', options)\n }\n\n const logService: LogService = {\n info: (message, data) => { send('log', 'info', { message, data }).catch(() => {}) },\n warn: (message, data) => { send('log', 'warn', { message, data }).catch(() => {}) },\n error: (message, data) => { send('log', 'error', { message, data }).catch(() => {}) },\n event: (name, properties) => { send('log', 'event', { name, properties }).catch(() => {}) }\n }\n\n const configService: ConfigService = {\n get features() { return config.features },\n get app() { return config.app },\n get: (key) => send('config', 'get', { key })\n }\n\n const stuffService: StuffService = {\n set: (key, namespace, value) => send('stuff', 'set', { key, namespace, value }),\n get: (key, namespace) => send('stuff', 'get', { key, namespace }),\n list: (key) => send('stuff', 'list', { key }),\n delete: (key, namespace) => send('stuff', 'delete', { key, namespace })\n }\n\n clientInstance = {\n get ready() { return readyPromise },\n get isReady() { return isReady },\n\n auth: authService, // only logout - this is problematic - provides user and account\n theme: themeService, // only useful for themed tailwind projects - still useful anyway\n router: routerService, // once you're in app - external or container-ui level routing it just not very useful.\n db: dbService,\n ui: uiService,\n storage: storageService,\n files: filesService,\n log: logService,\n config: configService,\n stuff: stuffService,\n\n onEntityChange(callback) {\n entityListeners.push(callback)\n return () => {\n const idx = entityListeners.indexOf(callback)\n if (idx > -1) entityListeners.splice(idx, 1)\n }\n },\n\n get entities() { return entities }\n }\n\n return clientInstance\n}\n\nexport function resetFoundationClient(): void {\n clientInstance = null\n}\n"],"names":["event"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/client.ts"],"sourcesContent":["import type {\n FoundationClient,\n User,\n Theme,\n RouterState,\n EntityDefinition,\n EntityChangeEvent,\n SDKReadyPayload,\n SDKResponse,\n AuthService,\n ThemeService,\n RouterService,\n DbService,\n UIService,\n StorageService,\n FilesService,\n LogService,\n ConfigService,\n StuffService\n} from './types'\n\nlet clientInstance: FoundationClient | null = null\n\nexport function createFoundationClient(): FoundationClient {\n if (clientInstance) {\n return clientInstance\n }\n\n let isReady = false\n let readyResolve: (() => void) | null = null\n let messageId = 0\n const pendingRequests = new Map<number, { resolve: (data: unknown) => void; reject: (error: Error) => void }>()\n\n let user: User | null = null\n let theme: Theme = { isDark: false, mode: 'system' }\n let router: RouterState = { path: '/', query: {}, hash: '' }\n let config: { features: Record<string, unknown>; app: { id?: string; name?: string; environment?: string } } = { features: {}, app: {} }\n let entities: EntityDefinition[] = []\n\n const themeListeners: Array<(theme: Theme) => void> = []\n const authListeners: Array<(user: User | null) => void> = []\n const routerListeners: Array<(route: RouterState) => void> = []\n const entityListeners: Array<(event: EntityChangeEvent) => void> = []\n\n const readyPromise = new Promise<void>((resolve) => {\n readyResolve = resolve\n })\n\n function send<T = unknown>(namespace: string, type: string, data: Record<string, unknown> = {}): Promise<T> {\n return new Promise((resolve, reject) => {\n const id = ++messageId\n pendingRequests.set(id, {\n resolve: resolve as (data: unknown) => void,\n reject\n })\n\n window.parent.postMessage({\n id,\n namespace,\n type: `${namespace}.${type}`,\n data\n }, '*')\n\n setTimeout(() => {\n if (pendingRequests.has(id)) {\n pendingRequests.delete(id)\n reject(new Error(`Request timeout: ${namespace}.${type}`))\n }\n }, 30000)\n })\n }\n\n function handleMessage(event: MessageEvent) {\n const message = event.data\n\n if (message?.type === 'SDK_READY') {\n const payload = message.data as SDKReadyPayload\n user = payload.user || null\n theme = payload.theme || { isDark: false, mode: 'system' }\n router = payload.router || { path: '/', query: {}, hash: '' }\n config = {\n features: payload.config?.features || {},\n app: payload.config?.app || {}\n }\n entities = payload.entities || []\n\n if (!isReady) {\n isReady = true\n readyResolve?.()\n }\n return\n }\n\n if (message?.type === 'THEME_CHANGED') {\n theme = message.data as Theme\n themeListeners.forEach(fn => {\n try { fn(theme) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'AUTH_CHANGED') {\n user = message.data?.user || null\n authListeners.forEach(fn => {\n try { fn(user) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ROUTER_CHANGED') {\n router = message.data as RouterState\n routerListeners.forEach(fn => {\n try { fn(router) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ENTITY_CHANGED') {\n const event = message.data as EntityChangeEvent\n entityListeners.forEach(fn => {\n try { fn(event) } catch { /* ignore */ }\n })\n return\n }\n\n if (typeof message?.id === 'number' && pendingRequests.has(message.id)) {\n const { resolve, reject } = pendingRequests.get(message.id)!\n pendingRequests.delete(message.id)\n\n const response = message as SDKResponse\n if (response.success) {\n resolve(response.data)\n } else {\n reject(new Error(response.error || 'Unknown error'))\n }\n }\n }\n\n window.addEventListener('message', handleMessage)\n\n const authService: AuthService = {\n get user() { return user },\n get isAuthenticated() { return !!user },\n getToken: () => send<string>('auth', 'getToken'),\n login: () => send<void>('auth', 'login'),\n logout: () => send<void>('auth', 'logout'),\n onChange(callback) {\n authListeners.push(callback)\n return () => {\n const idx = authListeners.indexOf(callback)\n if (idx > -1) authListeners.splice(idx, 1)\n }\n }\n }\n\n const themeService: ThemeService = {\n get isDark() { return theme.isDark },\n get mode() { return theme.mode },\n setTheme: (mode) => send<void>('ui', 'setTheme', { mode }),\n toggle: () => send<void>('ui', 'toggleTheme', {}),\n onChange(callback) {\n themeListeners.push(callback)\n return () => {\n const idx = themeListeners.indexOf(callback)\n if (idx > -1) themeListeners.splice(idx, 1)\n }\n }\n }\n\n const routerService: RouterService = {\n get path() { return router.path },\n get query() { return router.query },\n get hash() { return router.hash },\n push: (path, options = {}) => send<void>('router', 'push', { path, ...options }),\n replace: (path, options = {}) => send<void>('router', 'replace', { path, ...options }),\n setQuery: (params, options = {}) => send<void>('router', 'setQuery', { params, ...options }),\n onChange(callback) {\n routerListeners.push(callback)\n return () => {\n const idx = routerListeners.indexOf(callback)\n if (idx > -1) routerListeners.splice(idx, 1)\n }\n }\n }\n\n const dbService: DbService = {\n list: (entity, options = {}) => send('db', 'list', { entity, ...options }),\n get: (entity, id) => send('db', 'get', { entity, itemId: id }),\n create: (entity, item) => send('db', 'create', { entity, item }),\n update: (entity, id, updates) => send('db', 'update', { entity, itemId: id, updates }),\n delete: (entity, id) => send('db', 'delete', { entity, itemId: id })\n }\n\n const uiService: UIService = {\n toast: (message, type = 'info') => send('ui', 'toast', { message, toastType: type }),\n confirm: (message) => send('ui', 'confirm', { message }),\n loading: {\n show: (message) => send('ui', 'loading.show', { message }),\n hide: () => send('ui', 'loading.hide', {})\n },\n banner: {\n show: (message, options = {}) => send('ui', 'banner.show', { message, ...options }),\n hide: (bannerId) => send('ui', 'banner.hide', { bannerId })\n }\n }\n\n const storageService: StorageService = {\n upload: (options) => send('storage', 'upload', options),\n get: (fileId) => send('storage', 'get', { fileId }),\n delete: (fileId) => send('storage', 'delete', { fileId }),\n list: (options = {}) => send('storage', 'list', options)\n }\n\n const filesService: FilesService = {\n initiate: (options) => send('files', 'initiate', options),\n upload: async (options) => {\n // Convert File/Blob to ArrayBuffer for postMessage transfer\n let fileData: ArrayBuffer\n if (options.file instanceof ArrayBuffer) {\n fileData = options.file\n } else {\n // File or Blob - use arrayBuffer()\n fileData = await options.file.arrayBuffer()\n }\n\n return send('files', 'upload', {\n name: options.name,\n contentType: options.contentType,\n fileData,\n sha256: options.sha256\n })\n },\n get: (fileId) => send('files', 'get', { fileId }),\n delete: (fileId) => send('files', 'delete', { fileId }),\n list: (options = {}) => send('files', 'list', options)\n }\n\n const logService: LogService = {\n info: (message, data) => { send('log', 'info', { message, data }).catch(() => {}) },\n warn: (message, data) => { send('log', 'warn', { message, data }).catch(() => {}) },\n error: (message, data) => { send('log', 'error', { message, data }).catch(() => {}) },\n event: (name, properties) => { send('log', 'event', { name, properties }).catch(() => {}) }\n }\n\n const configService: ConfigService = {\n get features() { return config.features },\n get app() { return config.app },\n get: (key) => send('config', 'get', { key })\n }\n\n const stuffService: StuffService = {\n set: (key, namespace, value) => send('stuff', 'set', { key, namespace, value }),\n get: (key, namespace) => send('stuff', 'get', { key, namespace }),\n list: (key) => send('stuff', 'list', { key }),\n delete: (key, namespace) => send('stuff', 'delete', { key, namespace })\n }\n\n clientInstance = {\n get ready() { return readyPromise },\n get isReady() { return isReady },\n\n auth: authService,\n theme: themeService,\n router: routerService,\n db: dbService,\n ui: uiService,\n storage: storageService,\n files: filesService,\n log: logService,\n config: configService,\n stuff: stuffService,\n\n onEntityChange(callback) {\n entityListeners.push(callback)\n return () => {\n const idx = entityListeners.indexOf(callback)\n if (idx > -1) entityListeners.splice(idx, 1)\n }\n },\n\n get entities() { return entities }\n }\n\n return clientInstance\n}\n\nexport function resetFoundationClient(): void {\n clientInstance = null\n}\n"],"names":["event"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -253,11 +253,8 @@ function createFoundationClient() {
|
|
|
253
253
|
return isReady;
|
|
254
254
|
},
|
|
255
255
|
auth: authService,
|
|
256
|
-
// only logout - this is problematic - provides user and account
|
|
257
256
|
theme: themeService,
|
|
258
|
-
// only useful for themed tailwind projects - still useful anyway
|
|
259
257
|
router: routerService,
|
|
260
|
-
// once you're in app - external or container-ui level routing it just not very useful.
|
|
261
258
|
db: dbService,
|
|
262
259
|
ui: uiService,
|
|
263
260
|
storage: storageService,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/client.ts"],"sourcesContent":["import type {\n FoundationClient,\n User,\n Theme,\n RouterState,\n EntityDefinition,\n EntityChangeEvent,\n SDKReadyPayload,\n SDKResponse,\n AuthService,\n ThemeService,\n RouterService,\n DbService,\n UIService,\n StorageService,\n FilesService,\n LogService,\n ConfigService,\n StuffService\n} from './types'\n\nlet clientInstance: FoundationClient | null = null\n\nexport function createFoundationClient(): FoundationClient {\n if (clientInstance) {\n return clientInstance\n }\n\n let isReady = false\n let readyResolve: (() => void) | null = null\n let messageId = 0\n const pendingRequests = new Map<number, { resolve: (data: unknown) => void; reject: (error: Error) => void }>()\n\n let user: User | null = null\n let theme: Theme = { isDark: false, mode: 'system' }\n let router: RouterState = { path: '/', query: {}, hash: '' }\n let config: { features: Record<string, unknown>; app: { id?: string; name?: string; environment?: string } } = { features: {}, app: {} }\n let entities: EntityDefinition[] = []\n\n const themeListeners: Array<(theme: Theme) => void> = []\n const authListeners: Array<(user: User | null) => void> = []\n const routerListeners: Array<(route: RouterState) => void> = []\n const entityListeners: Array<(event: EntityChangeEvent) => void> = []\n\n const readyPromise = new Promise<void>((resolve) => {\n readyResolve = resolve\n })\n\n function send<T = unknown>(namespace: string, type: string, data: Record<string, unknown> = {}): Promise<T> {\n return new Promise((resolve, reject) => {\n const id = ++messageId\n pendingRequests.set(id, {\n resolve: resolve as (data: unknown) => void,\n reject\n })\n\n window.parent.postMessage({\n id,\n namespace,\n type: `${namespace}.${type}`,\n data\n }, '*')\n\n setTimeout(() => {\n if (pendingRequests.has(id)) {\n pendingRequests.delete(id)\n reject(new Error(`Request timeout: ${namespace}.${type}`))\n }\n }, 30000)\n })\n }\n\n function handleMessage(event: MessageEvent) {\n const message = event.data\n\n if (message?.type === 'SDK_READY') {\n const payload = message.data as SDKReadyPayload\n user = payload.user || null\n theme = payload.theme || { isDark: false, mode: 'system' }\n router = payload.router || { path: '/', query: {}, hash: '' }\n config = {\n features: payload.config?.features || {},\n app: payload.config?.app || {}\n }\n entities = payload.entities || []\n\n if (!isReady) {\n isReady = true\n readyResolve?.()\n }\n return\n }\n\n if (message?.type === 'THEME_CHANGED') {\n theme = message.data as Theme\n themeListeners.forEach(fn => {\n try { fn(theme) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'AUTH_CHANGED') {\n user = message.data?.user || null\n authListeners.forEach(fn => {\n try { fn(user) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ROUTER_CHANGED') {\n router = message.data as RouterState\n routerListeners.forEach(fn => {\n try { fn(router) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ENTITY_CHANGED') {\n const event = message.data as EntityChangeEvent\n entityListeners.forEach(fn => {\n try { fn(event) } catch { /* ignore */ }\n })\n return\n }\n\n if (typeof message?.id === 'number' && pendingRequests.has(message.id)) {\n const { resolve, reject } = pendingRequests.get(message.id)!\n pendingRequests.delete(message.id)\n\n const response = message as SDKResponse\n if (response.success) {\n resolve(response.data)\n } else {\n reject(new Error(response.error || 'Unknown error'))\n }\n }\n }\n\n window.addEventListener('message', handleMessage)\n\n const authService: AuthService = {\n get user() { return user },\n get isAuthenticated() { return !!user },\n getToken: () => send<string>('auth', 'getToken'),\n login: () => send<void>('auth', 'login'),\n logout: () => send<void>('auth', 'logout'),\n onChange(callback) {\n authListeners.push(callback)\n return () => {\n const idx = authListeners.indexOf(callback)\n if (idx > -1) authListeners.splice(idx, 1)\n }\n }\n }\n\n const themeService: ThemeService = {\n get isDark() { return theme.isDark },\n get mode() { return theme.mode },\n setTheme: (mode) => send<void>('ui', 'setTheme', { mode }),\n toggle: () => send<void>('ui', 'toggleTheme', {}),\n onChange(callback) {\n themeListeners.push(callback)\n return () => {\n const idx = themeListeners.indexOf(callback)\n if (idx > -1) themeListeners.splice(idx, 1)\n }\n }\n }\n\n const routerService: RouterService = {\n get path() { return router.path },\n get query() { return router.query },\n get hash() { return router.hash },\n push: (path, options = {}) => send<void>('router', 'push', { path, ...options }),\n replace: (path, options = {}) => send<void>('router', 'replace', { path, ...options }),\n setQuery: (params, options = {}) => send<void>('router', 'setQuery', { params, ...options }),\n onChange(callback) {\n routerListeners.push(callback)\n return () => {\n const idx = routerListeners.indexOf(callback)\n if (idx > -1) routerListeners.splice(idx, 1)\n }\n }\n }\n\n const dbService: DbService = {\n list: (entity, options = {}) => send('db', 'list', { entity, ...options }),\n get: (entity, id) => send('db', 'get', { entity, itemId: id }),\n create: (entity, item) => send('db', 'create', { entity, item }),\n update: (entity, id, updates) => send('db', 'update', { entity, itemId: id, updates }),\n delete: (entity, id) => send('db', 'delete', { entity, itemId: id })\n }\n\n const uiService: UIService = {\n toast: (message, type = 'info') => send('ui', 'toast', { message, toastType: type }),\n confirm: (message) => send('ui', 'confirm', { message }),\n loading: {\n show: (message) => send('ui', 'loading.show', { message }),\n hide: () => send('ui', 'loading.hide', {})\n },\n banner: {\n show: (message, options = {}) => send('ui', 'banner.show', { message, ...options }),\n hide: (bannerId) => send('ui', 'banner.hide', { bannerId })\n }\n }\n\n const storageService: StorageService = {\n upload: (options) => send('storage', 'upload', options),\n get: (fileId) => send('storage', 'get', { fileId }),\n delete: (fileId) => send('storage', 'delete', { fileId }),\n list: (options = {}) => send('storage', 'list', options)\n }\n\n const filesService: FilesService = {\n initiate: (options) => send('files', 'initiate', options),\n upload: async (options) => {\n // Convert File/Blob to ArrayBuffer for postMessage transfer\n let fileData: ArrayBuffer\n if (options.file instanceof ArrayBuffer) {\n fileData = options.file\n } else {\n // File or Blob - use arrayBuffer()\n fileData = await options.file.arrayBuffer()\n }\n\n return send('files', 'upload', {\n name: options.name,\n contentType: options.contentType,\n fileData,\n sha256: options.sha256\n })\n },\n get: (fileId) => send('files', 'get', { fileId }),\n delete: (fileId) => send('files', 'delete', { fileId }),\n list: (options = {}) => send('files', 'list', options)\n }\n\n const logService: LogService = {\n info: (message, data) => { send('log', 'info', { message, data }).catch(() => {}) },\n warn: (message, data) => { send('log', 'warn', { message, data }).catch(() => {}) },\n error: (message, data) => { send('log', 'error', { message, data }).catch(() => {}) },\n event: (name, properties) => { send('log', 'event', { name, properties }).catch(() => {}) }\n }\n\n const configService: ConfigService = {\n get features() { return config.features },\n get app() { return config.app },\n get: (key) => send('config', 'get', { key })\n }\n\n const stuffService: StuffService = {\n set: (key, namespace, value) => send('stuff', 'set', { key, namespace, value }),\n get: (key, namespace) => send('stuff', 'get', { key, namespace }),\n list: (key) => send('stuff', 'list', { key }),\n delete: (key, namespace) => send('stuff', 'delete', { key, namespace })\n }\n\n clientInstance = {\n get ready() { return readyPromise },\n get isReady() { return isReady },\n\n auth: authService, // only logout - this is problematic - provides user and account\n theme: themeService, // only useful for themed tailwind projects - still useful anyway\n router: routerService, // once you're in app - external or container-ui level routing it just not very useful.\n db: dbService,\n ui: uiService,\n storage: storageService,\n files: filesService,\n log: logService,\n config: configService,\n stuff: stuffService,\n\n onEntityChange(callback) {\n entityListeners.push(callback)\n return () => {\n const idx = entityListeners.indexOf(callback)\n if (idx > -1) entityListeners.splice(idx, 1)\n }\n },\n\n get entities() { return entities }\n }\n\n return clientInstance\n}\n\nexport function resetFoundationClient(): void {\n clientInstance = null\n}\n"],"names":["event"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/client.ts"],"sourcesContent":["import type {\n FoundationClient,\n User,\n Theme,\n RouterState,\n EntityDefinition,\n EntityChangeEvent,\n SDKReadyPayload,\n SDKResponse,\n AuthService,\n ThemeService,\n RouterService,\n DbService,\n UIService,\n StorageService,\n FilesService,\n LogService,\n ConfigService,\n StuffService\n} from './types'\n\nlet clientInstance: FoundationClient | null = null\n\nexport function createFoundationClient(): FoundationClient {\n if (clientInstance) {\n return clientInstance\n }\n\n let isReady = false\n let readyResolve: (() => void) | null = null\n let messageId = 0\n const pendingRequests = new Map<number, { resolve: (data: unknown) => void; reject: (error: Error) => void }>()\n\n let user: User | null = null\n let theme: Theme = { isDark: false, mode: 'system' }\n let router: RouterState = { path: '/', query: {}, hash: '' }\n let config: { features: Record<string, unknown>; app: { id?: string; name?: string; environment?: string } } = { features: {}, app: {} }\n let entities: EntityDefinition[] = []\n\n const themeListeners: Array<(theme: Theme) => void> = []\n const authListeners: Array<(user: User | null) => void> = []\n const routerListeners: Array<(route: RouterState) => void> = []\n const entityListeners: Array<(event: EntityChangeEvent) => void> = []\n\n const readyPromise = new Promise<void>((resolve) => {\n readyResolve = resolve\n })\n\n function send<T = unknown>(namespace: string, type: string, data: Record<string, unknown> = {}): Promise<T> {\n return new Promise((resolve, reject) => {\n const id = ++messageId\n pendingRequests.set(id, {\n resolve: resolve as (data: unknown) => void,\n reject\n })\n\n window.parent.postMessage({\n id,\n namespace,\n type: `${namespace}.${type}`,\n data\n }, '*')\n\n setTimeout(() => {\n if (pendingRequests.has(id)) {\n pendingRequests.delete(id)\n reject(new Error(`Request timeout: ${namespace}.${type}`))\n }\n }, 30000)\n })\n }\n\n function handleMessage(event: MessageEvent) {\n const message = event.data\n\n if (message?.type === 'SDK_READY') {\n const payload = message.data as SDKReadyPayload\n user = payload.user || null\n theme = payload.theme || { isDark: false, mode: 'system' }\n router = payload.router || { path: '/', query: {}, hash: '' }\n config = {\n features: payload.config?.features || {},\n app: payload.config?.app || {}\n }\n entities = payload.entities || []\n\n if (!isReady) {\n isReady = true\n readyResolve?.()\n }\n return\n }\n\n if (message?.type === 'THEME_CHANGED') {\n theme = message.data as Theme\n themeListeners.forEach(fn => {\n try { fn(theme) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'AUTH_CHANGED') {\n user = message.data?.user || null\n authListeners.forEach(fn => {\n try { fn(user) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ROUTER_CHANGED') {\n router = message.data as RouterState\n routerListeners.forEach(fn => {\n try { fn(router) } catch { /* ignore */ }\n })\n return\n }\n\n if (message?.type === 'ENTITY_CHANGED') {\n const event = message.data as EntityChangeEvent\n entityListeners.forEach(fn => {\n try { fn(event) } catch { /* ignore */ }\n })\n return\n }\n\n if (typeof message?.id === 'number' && pendingRequests.has(message.id)) {\n const { resolve, reject } = pendingRequests.get(message.id)!\n pendingRequests.delete(message.id)\n\n const response = message as SDKResponse\n if (response.success) {\n resolve(response.data)\n } else {\n reject(new Error(response.error || 'Unknown error'))\n }\n }\n }\n\n window.addEventListener('message', handleMessage)\n\n const authService: AuthService = {\n get user() { return user },\n get isAuthenticated() { return !!user },\n getToken: () => send<string>('auth', 'getToken'),\n login: () => send<void>('auth', 'login'),\n logout: () => send<void>('auth', 'logout'),\n onChange(callback) {\n authListeners.push(callback)\n return () => {\n const idx = authListeners.indexOf(callback)\n if (idx > -1) authListeners.splice(idx, 1)\n }\n }\n }\n\n const themeService: ThemeService = {\n get isDark() { return theme.isDark },\n get mode() { return theme.mode },\n setTheme: (mode) => send<void>('ui', 'setTheme', { mode }),\n toggle: () => send<void>('ui', 'toggleTheme', {}),\n onChange(callback) {\n themeListeners.push(callback)\n return () => {\n const idx = themeListeners.indexOf(callback)\n if (idx > -1) themeListeners.splice(idx, 1)\n }\n }\n }\n\n const routerService: RouterService = {\n get path() { return router.path },\n get query() { return router.query },\n get hash() { return router.hash },\n push: (path, options = {}) => send<void>('router', 'push', { path, ...options }),\n replace: (path, options = {}) => send<void>('router', 'replace', { path, ...options }),\n setQuery: (params, options = {}) => send<void>('router', 'setQuery', { params, ...options }),\n onChange(callback) {\n routerListeners.push(callback)\n return () => {\n const idx = routerListeners.indexOf(callback)\n if (idx > -1) routerListeners.splice(idx, 1)\n }\n }\n }\n\n const dbService: DbService = {\n list: (entity, options = {}) => send('db', 'list', { entity, ...options }),\n get: (entity, id) => send('db', 'get', { entity, itemId: id }),\n create: (entity, item) => send('db', 'create', { entity, item }),\n update: (entity, id, updates) => send('db', 'update', { entity, itemId: id, updates }),\n delete: (entity, id) => send('db', 'delete', { entity, itemId: id })\n }\n\n const uiService: UIService = {\n toast: (message, type = 'info') => send('ui', 'toast', { message, toastType: type }),\n confirm: (message) => send('ui', 'confirm', { message }),\n loading: {\n show: (message) => send('ui', 'loading.show', { message }),\n hide: () => send('ui', 'loading.hide', {})\n },\n banner: {\n show: (message, options = {}) => send('ui', 'banner.show', { message, ...options }),\n hide: (bannerId) => send('ui', 'banner.hide', { bannerId })\n }\n }\n\n const storageService: StorageService = {\n upload: (options) => send('storage', 'upload', options),\n get: (fileId) => send('storage', 'get', { fileId }),\n delete: (fileId) => send('storage', 'delete', { fileId }),\n list: (options = {}) => send('storage', 'list', options)\n }\n\n const filesService: FilesService = {\n initiate: (options) => send('files', 'initiate', options),\n upload: async (options) => {\n // Convert File/Blob to ArrayBuffer for postMessage transfer\n let fileData: ArrayBuffer\n if (options.file instanceof ArrayBuffer) {\n fileData = options.file\n } else {\n // File or Blob - use arrayBuffer()\n fileData = await options.file.arrayBuffer()\n }\n\n return send('files', 'upload', {\n name: options.name,\n contentType: options.contentType,\n fileData,\n sha256: options.sha256\n })\n },\n get: (fileId) => send('files', 'get', { fileId }),\n delete: (fileId) => send('files', 'delete', { fileId }),\n list: (options = {}) => send('files', 'list', options)\n }\n\n const logService: LogService = {\n info: (message, data) => { send('log', 'info', { message, data }).catch(() => {}) },\n warn: (message, data) => { send('log', 'warn', { message, data }).catch(() => {}) },\n error: (message, data) => { send('log', 'error', { message, data }).catch(() => {}) },\n event: (name, properties) => { send('log', 'event', { name, properties }).catch(() => {}) }\n }\n\n const configService: ConfigService = {\n get features() { return config.features },\n get app() { return config.app },\n get: (key) => send('config', 'get', { key })\n }\n\n const stuffService: StuffService = {\n set: (key, namespace, value) => send('stuff', 'set', { key, namespace, value }),\n get: (key, namespace) => send('stuff', 'get', { key, namespace }),\n list: (key) => send('stuff', 'list', { key }),\n delete: (key, namespace) => send('stuff', 'delete', { key, namespace })\n }\n\n clientInstance = {\n get ready() { return readyPromise },\n get isReady() { return isReady },\n\n auth: authService,\n theme: themeService,\n router: routerService,\n db: dbService,\n ui: uiService,\n storage: storageService,\n files: filesService,\n log: logService,\n config: configService,\n stuff: stuffService,\n\n onEntityChange(callback) {\n entityListeners.push(callback)\n return () => {\n const idx = entityListeners.indexOf(callback)\n if (idx > -1) entityListeners.splice(idx, 1)\n }\n },\n\n get entities() { return entities }\n }\n\n return clientInstance\n}\n\nexport function resetFoundationClient(): void {\n clientInstance = null\n}\n"],"names":["event"],"mappings":"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"}
|
package/package.json
CHANGED
package/README.md
DELETED
|
@@ -1,563 +0,0 @@
|
|
|
1
|
-
# foundation-sdk
|
|
2
|
-
|
|
3
|
-
SDK for building applications that embed within the Foundation container.
|
|
4
|
-
|
|
5
|
-
> **Future Migration:** This package will be renamed to `@foundation/iframe-sdk` when the npm organization is set up.
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install foundation-sdk
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Vue is an optional peer dependency - only required if using the `/vue` entry point:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install foundation-sdk vue
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Quick Start
|
|
20
|
-
|
|
21
|
-
### Vanilla TypeScript/JavaScript
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import { createFoundationClient } from 'foundation-sdk'
|
|
25
|
-
|
|
26
|
-
const sdk = createFoundationClient()
|
|
27
|
-
|
|
28
|
-
// Wait for SDK to be ready (receives initial state from container)
|
|
29
|
-
await sdk.ready
|
|
30
|
-
|
|
31
|
-
// Access current user
|
|
32
|
-
console.log(sdk.auth.user)
|
|
33
|
-
|
|
34
|
-
// Fetch data
|
|
35
|
-
const { items } = await sdk.db.list('projects', { limit: 10 })
|
|
36
|
-
|
|
37
|
-
// Show a toast notification
|
|
38
|
-
await sdk.ui.toast('Hello from embedded app!', 'success')
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Vue 3
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
import { useFoundation } from 'foundation-sdk/vue'
|
|
45
|
-
|
|
46
|
-
// In your component setup
|
|
47
|
-
const { isReady, user, isDark, db, ui } = useFoundation()
|
|
48
|
-
|
|
49
|
-
// Reactive state is automatically updated
|
|
50
|
-
watch(isReady, (ready) => {
|
|
51
|
-
if (ready) {
|
|
52
|
-
console.log('SDK ready, user:', user.value)
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
// Use services directly
|
|
57
|
-
const { items } = await db.list('projects', { limit: 10 })
|
|
58
|
-
await ui.toast('Hello!', 'success')
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## API Reference
|
|
62
|
-
|
|
63
|
-
### Initialization
|
|
64
|
-
|
|
65
|
-
#### `createFoundationClient(): FoundationClient`
|
|
66
|
-
|
|
67
|
-
Creates or returns the singleton SDK client instance.
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
const sdk = createFoundationClient()
|
|
71
|
-
|
|
72
|
-
// Check if ready
|
|
73
|
-
if (sdk.isReady) {
|
|
74
|
-
// SDK has received initial state
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Wait for ready
|
|
78
|
-
await sdk.ready
|
|
79
|
-
|
|
80
|
-
// Access available entity definitions
|
|
81
|
-
console.log(sdk.entities) // EntityDefinition[]
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
#### `resetFoundationClient(): void`
|
|
85
|
-
|
|
86
|
-
Resets the singleton instance. Useful for testing or re-initialization.
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
import { resetFoundationClient } from 'foundation-sdk'
|
|
90
|
-
|
|
91
|
-
resetFoundationClient()
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
### Authentication (`sdk.auth`)
|
|
97
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
interface AuthService {
|
|
100
|
-
readonly user: User | null // Current user
|
|
101
|
-
readonly isAuthenticated: boolean // Is user logged in
|
|
102
|
-
getToken(): Promise<string> // Get auth token
|
|
103
|
-
login(): Promise<void> // Trigger login flow
|
|
104
|
-
logout(): Promise<void> // Trigger logout
|
|
105
|
-
onChange(callback): () => void // Subscribe to auth changes
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**Example:**
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
// Get current user
|
|
113
|
-
const user = sdk.auth.user
|
|
114
|
-
console.log(user?.email, user?.name)
|
|
115
|
-
|
|
116
|
-
// Get token for API calls
|
|
117
|
-
const token = await sdk.auth.getToken()
|
|
118
|
-
|
|
119
|
-
// Subscribe to auth changes
|
|
120
|
-
const unsubscribe = sdk.auth.onChange((user) => {
|
|
121
|
-
console.log('Auth changed:', user)
|
|
122
|
-
})
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
### Database (`sdk.db`)
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
interface DbService {
|
|
131
|
-
list<T>(entity: string, options?: ListOptions): Promise<{ items: T[]; nextCursor?: string }>
|
|
132
|
-
get<T>(entity: string, id: string): Promise<T>
|
|
133
|
-
create<T>(entity: string, data: Partial<T>): Promise<T>
|
|
134
|
-
update<T>(entity: string, id: string, updates: Partial<T>): Promise<T>
|
|
135
|
-
delete(entity: string, id: string): Promise<void>
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
interface ListOptions {
|
|
139
|
-
filters?: Record<string, unknown>
|
|
140
|
-
limit?: number
|
|
141
|
-
cursor?: string
|
|
142
|
-
orderBy?: string
|
|
143
|
-
orderDir?: 'asc' | 'desc'
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
**Example:**
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// List with filters and pagination
|
|
151
|
-
const { items, nextCursor } = await sdk.db.list('projects', {
|
|
152
|
-
filters: { status: 'active' },
|
|
153
|
-
limit: 20,
|
|
154
|
-
orderBy: 'createdAt',
|
|
155
|
-
orderDir: 'desc'
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
// Get single item
|
|
159
|
-
const project = await sdk.db.get('projects', 'project-123')
|
|
160
|
-
|
|
161
|
-
// Create
|
|
162
|
-
const newProject = await sdk.db.create('projects', {
|
|
163
|
-
name: 'New Project',
|
|
164
|
-
status: 'active'
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
// Update
|
|
168
|
-
const updated = await sdk.db.update('projects', 'project-123', {
|
|
169
|
-
name: 'Updated Name'
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
// Delete
|
|
173
|
-
await sdk.db.delete('projects', 'project-123')
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
### UI (`sdk.ui`)
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
interface UIService {
|
|
182
|
-
toast(message: string, type?: 'success' | 'error' | 'warn' | 'info'): Promise<void>
|
|
183
|
-
confirm(message: string): Promise<{ confirmed: boolean }>
|
|
184
|
-
loading: {
|
|
185
|
-
show(message?: string): Promise<void>
|
|
186
|
-
hide(): Promise<void>
|
|
187
|
-
}
|
|
188
|
-
banner: {
|
|
189
|
-
show(message: string, options?: BannerOptions): Promise<{ bannerId: string }>
|
|
190
|
-
hide(bannerId: string): Promise<void>
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
**Example:**
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
// Toast notifications
|
|
199
|
-
await sdk.ui.toast('Operation successful', 'success')
|
|
200
|
-
await sdk.ui.toast('Something went wrong', 'error')
|
|
201
|
-
|
|
202
|
-
// Confirmation dialog
|
|
203
|
-
const { confirmed } = await sdk.ui.confirm('Delete this item?')
|
|
204
|
-
if (confirmed) {
|
|
205
|
-
await sdk.db.delete('items', itemId)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Loading overlay
|
|
209
|
-
sdk.ui.loading.show('Processing...')
|
|
210
|
-
try {
|
|
211
|
-
await doSomething()
|
|
212
|
-
} finally {
|
|
213
|
-
sdk.ui.loading.hide()
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Banners
|
|
217
|
-
const { bannerId } = await sdk.ui.banner.show('New feature available!', {
|
|
218
|
-
type: 'info',
|
|
219
|
-
dismissible: true
|
|
220
|
-
})
|
|
221
|
-
// Later...
|
|
222
|
-
await sdk.ui.banner.hide(bannerId)
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
---
|
|
226
|
-
|
|
227
|
-
### Router (`sdk.router`)
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
interface RouterService {
|
|
231
|
-
readonly path: string
|
|
232
|
-
readonly query: Record<string, string>
|
|
233
|
-
readonly hash: string
|
|
234
|
-
push(path: string, options?: NavOptions): Promise<void>
|
|
235
|
-
replace(path: string, options?: NavOptions): Promise<void>
|
|
236
|
-
setQuery(params: Record<string, string>, options?: { replace?: boolean }): Promise<void>
|
|
237
|
-
onChange(callback: (route: RouterState) => void): () => void
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
**Example:**
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
// Navigate
|
|
245
|
-
await sdk.router.push('/dashboard')
|
|
246
|
-
await sdk.router.push('/projects', { query: { filter: 'active' } })
|
|
247
|
-
|
|
248
|
-
// Replace (no history entry)
|
|
249
|
-
await sdk.router.replace('/login')
|
|
250
|
-
|
|
251
|
-
// Update query params
|
|
252
|
-
await sdk.router.setQuery({ page: '2', sort: 'name' })
|
|
253
|
-
|
|
254
|
-
// Subscribe to route changes
|
|
255
|
-
const unsubscribe = sdk.router.onChange((route) => {
|
|
256
|
-
console.log('Route changed:', route.path, route.query)
|
|
257
|
-
})
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
### Theme (`sdk.theme`)
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
interface ThemeService {
|
|
266
|
-
readonly isDark: boolean
|
|
267
|
-
readonly mode: 'light' | 'dark' | 'system'
|
|
268
|
-
setTheme(mode: 'light' | 'dark' | 'system'): Promise<void>
|
|
269
|
-
toggle(): Promise<void>
|
|
270
|
-
onChange(callback: (theme: Theme) => void): () => void
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
**Example:**
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
// Check current theme
|
|
278
|
-
if (sdk.theme.isDark) {
|
|
279
|
-
// Apply dark styles
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Set specific theme mode
|
|
283
|
-
await sdk.theme.setTheme('dark')
|
|
284
|
-
await sdk.theme.setTheme('system')
|
|
285
|
-
|
|
286
|
-
// Toggle between light/dark
|
|
287
|
-
await sdk.theme.toggle()
|
|
288
|
-
|
|
289
|
-
// Subscribe to theme changes
|
|
290
|
-
const unsubscribe = sdk.theme.onChange((theme) => {
|
|
291
|
-
document.body.classList.toggle('dark', theme.isDark)
|
|
292
|
-
})
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
### Storage (`sdk.storage`)
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
interface StorageService {
|
|
301
|
-
upload(options: UploadOptions): Promise<{ id: string; url: string; name: string }>
|
|
302
|
-
get(fileId: string): Promise<FileMetadata>
|
|
303
|
-
delete(fileId: string): Promise<void>
|
|
304
|
-
list(options?: ListOptions): Promise<{ items: FileMetadata[]; nextCursor?: string }>
|
|
305
|
-
}
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
**Example:**
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
// Upload a file (base64 encoded)
|
|
312
|
-
const file = await sdk.storage.upload({
|
|
313
|
-
name: 'document.pdf',
|
|
314
|
-
type: 'application/pdf',
|
|
315
|
-
size: fileBuffer.byteLength,
|
|
316
|
-
data: btoa(String.fromCharCode(...new Uint8Array(fileBuffer))),
|
|
317
|
-
folder: 'documents'
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
console.log(file.url) // URL to access the file
|
|
321
|
-
|
|
322
|
-
// List files
|
|
323
|
-
const { items } = await sdk.storage.list({ folder: 'documents' })
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
---
|
|
327
|
-
|
|
328
|
-
### Files (`sdk.files`)
|
|
329
|
-
|
|
330
|
-
For large file uploads using presigned URLs:
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
interface FilesService {
|
|
334
|
-
initiate(options: InitiateOptions): Promise<{
|
|
335
|
-
id: string
|
|
336
|
-
name: string
|
|
337
|
-
signedUrl: string
|
|
338
|
-
signedData: Record<string, string>
|
|
339
|
-
}>
|
|
340
|
-
get(fileId: string): Promise<FileMetadata>
|
|
341
|
-
delete(fileId: string): Promise<void>
|
|
342
|
-
list(options?: ListOptions): Promise<{ items: FileMetadata[]; nextCursor?: string }>
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
**Example:**
|
|
347
|
-
|
|
348
|
-
```typescript
|
|
349
|
-
// Initiate upload to get presigned URL
|
|
350
|
-
const { signedUrl, signedData, id } = await sdk.files.initiate({
|
|
351
|
-
name: 'large-video.mp4',
|
|
352
|
-
contentType: 'video/mp4',
|
|
353
|
-
contentLength: file.size
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
// Upload directly to storage
|
|
357
|
-
const formData = new FormData()
|
|
358
|
-
Object.entries(signedData).forEach(([key, value]) => {
|
|
359
|
-
formData.append(key, value)
|
|
360
|
-
})
|
|
361
|
-
formData.append('file', file)
|
|
362
|
-
|
|
363
|
-
await fetch(signedUrl, { method: 'POST', body: formData })
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
---
|
|
367
|
-
|
|
368
|
-
### Logging (`sdk.log`)
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
interface LogService {
|
|
372
|
-
info(message: string, data?: Record<string, unknown>): void
|
|
373
|
-
warn(message: string, data?: Record<string, unknown>): void
|
|
374
|
-
error(message: string, data?: Record<string, unknown>): void
|
|
375
|
-
event(name: string, properties?: Record<string, unknown>): void
|
|
376
|
-
}
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
**Example:**
|
|
380
|
-
|
|
381
|
-
```typescript
|
|
382
|
-
// Log messages
|
|
383
|
-
sdk.log.info('User completed onboarding', { userId: user.id })
|
|
384
|
-
sdk.log.warn('API rate limit approaching', { remaining: 10 })
|
|
385
|
-
sdk.log.error('Failed to save', { error: err.message })
|
|
386
|
-
|
|
387
|
-
// Track analytics events
|
|
388
|
-
sdk.log.event('button_clicked', { buttonId: 'submit', page: 'checkout' })
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
---
|
|
392
|
-
|
|
393
|
-
### Config (`sdk.config`)
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
interface ConfigService {
|
|
397
|
-
readonly features: Record<string, unknown>
|
|
398
|
-
readonly app: { id?: string; name?: string; environment?: string }
|
|
399
|
-
get(key: string): Promise<unknown>
|
|
400
|
-
}
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
**Example:**
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
406
|
-
// Check feature flags
|
|
407
|
-
if (sdk.config.features.newDashboard) {
|
|
408
|
-
// Show new dashboard
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// Get app info
|
|
412
|
-
console.log(sdk.config.app.environment) // 'production' | 'staging' | 'development'
|
|
413
|
-
|
|
414
|
-
// Get specific config value
|
|
415
|
-
const apiUrl = await sdk.config.get('apiBaseUrl')
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
---
|
|
419
|
-
|
|
420
|
-
### Entity Changes
|
|
421
|
-
|
|
422
|
-
Subscribe to real-time entity changes for cache invalidation:
|
|
423
|
-
|
|
424
|
-
```typescript
|
|
425
|
-
const unsubscribe = sdk.onEntityChange((event) => {
|
|
426
|
-
console.log('Entity changed:', event)
|
|
427
|
-
// event.changeType: 'entity.created' | 'entity.updated' | 'entity.deleted'
|
|
428
|
-
// event.entityId: 'projects'
|
|
429
|
-
// event.id: 'project-123'
|
|
430
|
-
|
|
431
|
-
// Invalidate your cache
|
|
432
|
-
if (event.entityId === 'projects') {
|
|
433
|
-
refetchProjects()
|
|
434
|
-
}
|
|
435
|
-
})
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
---
|
|
439
|
-
|
|
440
|
-
## Vue Integration
|
|
441
|
-
|
|
442
|
-
The SDK provides a Vue 3 composable for reactive state management:
|
|
443
|
-
|
|
444
|
-
```typescript
|
|
445
|
-
import { useFoundation } from 'foundation-sdk/vue'
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
### `useFoundation()`
|
|
449
|
-
|
|
450
|
-
Returns reactive state and direct service access:
|
|
451
|
-
|
|
452
|
-
```typescript
|
|
453
|
-
interface UseFoundationReturn {
|
|
454
|
-
// Reactive state (readonly refs)
|
|
455
|
-
isReady: Ref<boolean>
|
|
456
|
-
user: ShallowRef<User | null>
|
|
457
|
-
isDark: Ref<boolean>
|
|
458
|
-
themeMode: Ref<'light' | 'dark' | 'system'>
|
|
459
|
-
routerPath: Ref<string>
|
|
460
|
-
routerQuery: ShallowRef<Record<string, string>>
|
|
461
|
-
routerHash: Ref<string>
|
|
462
|
-
entities: ShallowRef<EntityDefinition[]>
|
|
463
|
-
|
|
464
|
-
// Computed helpers
|
|
465
|
-
isAuthenticated: boolean
|
|
466
|
-
currentUser: User | null
|
|
467
|
-
|
|
468
|
-
// Direct service access
|
|
469
|
-
client: FoundationClient
|
|
470
|
-
auth: AuthService
|
|
471
|
-
ui: UIService
|
|
472
|
-
db: DbService
|
|
473
|
-
router: RouterService
|
|
474
|
-
config: ConfigService
|
|
475
|
-
files: FilesService
|
|
476
|
-
storage: StorageService
|
|
477
|
-
log: LogService
|
|
478
|
-
theme: ThemeService
|
|
479
|
-
|
|
480
|
-
// Theme control shortcuts
|
|
481
|
-
setTheme(mode: 'light' | 'dark' | 'system'): Promise<void>
|
|
482
|
-
toggleTheme(): Promise<void>
|
|
483
|
-
|
|
484
|
-
// Entity change subscription
|
|
485
|
-
onEntityChange(callback: (event: EntityChangeEvent) => void): () => void
|
|
486
|
-
}
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
**Example:**
|
|
490
|
-
|
|
491
|
-
```vue
|
|
492
|
-
<script setup lang="ts">
|
|
493
|
-
import { useFoundation } from 'foundation-sdk/vue'
|
|
494
|
-
import { watch } from 'vue'
|
|
495
|
-
|
|
496
|
-
const { isReady, user, isDark, db, ui, toggleTheme } = useFoundation()
|
|
497
|
-
|
|
498
|
-
// Reactive state updates automatically
|
|
499
|
-
watch(user, (newUser) => {
|
|
500
|
-
console.log('User changed:', newUser?.email)
|
|
501
|
-
})
|
|
502
|
-
|
|
503
|
-
// Theme reactivity
|
|
504
|
-
watch(isDark, (dark) => {
|
|
505
|
-
document.body.classList.toggle('dark-mode', dark)
|
|
506
|
-
})
|
|
507
|
-
|
|
508
|
-
async function loadProjects() {
|
|
509
|
-
const { items } = await db.list('projects', { limit: 10 })
|
|
510
|
-
return items
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
async function handleClick() {
|
|
514
|
-
await toggleTheme()
|
|
515
|
-
await ui.toast('Theme toggled!', 'success')
|
|
516
|
-
}
|
|
517
|
-
</script>
|
|
518
|
-
|
|
519
|
-
<template>
|
|
520
|
-
<div v-if="isReady">
|
|
521
|
-
<p>Welcome, {{ user?.name }}</p>
|
|
522
|
-
<button @click="handleClick">Toggle Theme</button>
|
|
523
|
-
</div>
|
|
524
|
-
<div v-else>Loading...</div>
|
|
525
|
-
</template>
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
---
|
|
529
|
-
|
|
530
|
-
## TypeScript
|
|
531
|
-
|
|
532
|
-
Full TypeScript support with exported types:
|
|
533
|
-
|
|
534
|
-
```typescript
|
|
535
|
-
import type {
|
|
536
|
-
FoundationClient,
|
|
537
|
-
User,
|
|
538
|
-
Theme,
|
|
539
|
-
RouterState,
|
|
540
|
-
EntityDefinition,
|
|
541
|
-
EntityChangeEvent,
|
|
542
|
-
AuthService,
|
|
543
|
-
ThemeService,
|
|
544
|
-
RouterService,
|
|
545
|
-
DbService,
|
|
546
|
-
UIService,
|
|
547
|
-
StorageService,
|
|
548
|
-
FilesService,
|
|
549
|
-
FileMetadata,
|
|
550
|
-
LogService,
|
|
551
|
-
ConfigService
|
|
552
|
-
} from 'foundation-sdk'
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
---
|
|
556
|
-
|
|
557
|
-
## Architecture
|
|
558
|
-
|
|
559
|
-
See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed diagrams of how the SDK communicates with the container.
|
|
560
|
-
|
|
561
|
-
## License
|
|
562
|
-
|
|
563
|
-
MIT
|