timeback 0.1.0 → 0.1.2
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 +349 -121
- package/dist/client/adapters/vue/SignInButton.vue +260 -0
- package/dist/client/adapters/vue/SignInButton.vue.d.ts +53 -0
- package/dist/client/adapters/vue/index.d.ts +43 -0
- package/dist/client/adapters/vue/index.d.ts.map +1 -0
- package/dist/client/adapters/vue/index.ts +48 -0
- package/dist/client/adapters/vue/provider.d.ts +94 -0
- package/dist/client/adapters/vue/provider.d.ts.map +1 -0
- package/dist/client/adapters/vue/provider.ts +147 -0
- package/dist/index.d.ts +20 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +271 -22
- package/dist/server/adapters/express.d.ts +9 -5
- package/dist/server/adapters/express.d.ts.map +1 -1
- package/dist/server/adapters/express.js +19 -3
- package/dist/server/adapters/native.d.ts +5 -3
- package/dist/server/adapters/native.d.ts.map +1 -1
- package/dist/server/adapters/native.js +11 -3
- package/dist/server/adapters/nextjs.d.ts +5 -3
- package/dist/server/adapters/nextjs.d.ts.map +1 -1
- package/dist/server/adapters/nextjs.js +11 -3
- package/dist/server/adapters/nuxt.d.ts +98 -0
- package/dist/server/adapters/nuxt.d.ts.map +1 -0
- package/dist/server/adapters/nuxt.js +673 -0
- package/dist/server/adapters/solid-start.d.ts +5 -3
- package/dist/server/adapters/solid-start.d.ts.map +1 -1
- package/dist/server/adapters/solid-start.js +16 -6
- package/dist/server/adapters/svelte-kit.d.ts +5 -3
- package/dist/server/adapters/svelte-kit.d.ts.map +1 -1
- package/dist/server/adapters/svelte-kit.js +16 -6
- package/dist/server/adapters/tanstack-start.d.ts +42 -0
- package/dist/server/adapters/tanstack-start.d.ts.map +1 -0
- package/dist/server/adapters/tanstack-start.js +11 -3
- package/dist/server/adapters/types.d.ts +91 -9
- package/dist/server/adapters/types.d.ts.map +1 -1
- package/dist/server/adapters/utils.d.ts +24 -5
- package/dist/server/adapters/utils.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/timeback.d.ts +39 -2
- package/dist/server/timeback.d.ts.map +1 -1
- package/dist/server/types.d.ts +37 -0
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +14 -2
package/README.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
# Timeback SDK
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for integrating
|
|
3
|
+
TypeScript SDK for integrating Timeback into your application. Provides server-side route handlers and client-side components for activity tracking and SSO authentication.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [Server Adapters](#server-adapters)
|
|
10
|
+
- [Next.js](#nextjs)
|
|
11
|
+
- [Nuxt](#nuxt)
|
|
12
|
+
- [SvelteKit](#sveltekit)
|
|
13
|
+
- [SolidStart](#solidstart)
|
|
14
|
+
- [TanStack Start](#tanstack-start)
|
|
15
|
+
- [Express](#express)
|
|
16
|
+
- [Client Adapters](#client-adapters)
|
|
17
|
+
- [React](#react)
|
|
18
|
+
- [Vue](#vue)
|
|
19
|
+
- [Svelte](#svelte)
|
|
20
|
+
- [Solid](#solid)
|
|
21
|
+
- [Identity Modes](#identity-modes)
|
|
22
|
+
- [Identity-Only Integration](#identity-only-integration)
|
|
23
|
+
- [Activity Tracking](#activity-tracking)
|
|
4
24
|
|
|
5
25
|
## Installation
|
|
6
26
|
|
|
@@ -10,210 +30,418 @@ npm install timeback
|
|
|
10
30
|
bun add timeback
|
|
11
31
|
```
|
|
12
32
|
|
|
13
|
-
##
|
|
33
|
+
## Quick Start
|
|
14
34
|
|
|
15
|
-
|
|
35
|
+
1. Create a server instance with your credentials
|
|
36
|
+
2. Mount the route handlers for your framework
|
|
37
|
+
3. Wrap your app with the client provider
|
|
38
|
+
4. Use hooks/composables to track activities
|
|
16
39
|
|
|
17
|
-
|
|
40
|
+
## Server Adapters
|
|
18
41
|
|
|
19
|
-
|
|
20
|
-
// app/lib/timeback.ts
|
|
21
|
-
import { createTimeback } from 'timeback'
|
|
42
|
+
All server adapters use the same core configuration:
|
|
22
43
|
|
|
23
|
-
|
|
24
|
-
|
|
44
|
+
```typescript
|
|
45
|
+
// lib/timeback.ts
|
|
46
|
+
import { createServer } from 'timeback'
|
|
25
47
|
|
|
26
|
-
|
|
48
|
+
export const timeback = await createServer({
|
|
49
|
+
env: 'staging', // 'development' | 'staging' | 'production'
|
|
27
50
|
api: {
|
|
28
51
|
clientId: process.env.TIMEBACK_API_CLIENT_ID!,
|
|
29
52
|
clientSecret: process.env.TIMEBACK_API_CLIENT_SECRET!,
|
|
30
53
|
},
|
|
31
|
-
|
|
32
|
-
// Identity configuration
|
|
33
54
|
identity: {
|
|
34
|
-
// Option A: Timeback SSO
|
|
35
55
|
mode: 'sso',
|
|
36
|
-
clientId: process.env.
|
|
37
|
-
clientSecret: process.env.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
name: session.user.name,
|
|
47
|
-
}
|
|
56
|
+
clientId: process.env.AWS_COGNITO_CLIENT_ID!,
|
|
57
|
+
clientSecret: process.env.AWS_COGNITO_CLIENT_SECRET!,
|
|
58
|
+
redirectUri: 'http://localhost:3000/api/auth/sso/callback/timeback',
|
|
59
|
+
onCallbackSuccess: ({ user, redirect }) => {
|
|
60
|
+
// Set session, then redirect
|
|
61
|
+
return redirect('/')
|
|
62
|
+
},
|
|
63
|
+
onCallbackError: ({ error, redirect }) => {
|
|
64
|
+
console.error('SSO Error:', error)
|
|
65
|
+
return redirect('/?error=sso_failed')
|
|
48
66
|
},
|
|
67
|
+
getUser: () => getSession(), // Return current user or undefined
|
|
49
68
|
},
|
|
50
69
|
})
|
|
51
70
|
```
|
|
52
71
|
|
|
53
|
-
### Next.js
|
|
72
|
+
### Next.js
|
|
54
73
|
|
|
55
74
|
```typescript
|
|
56
75
|
// app/api/timeback/[...timeback]/route.ts
|
|
76
|
+
import { toNextjsHandler } from 'timeback/nextjs'
|
|
77
|
+
|
|
57
78
|
import { timeback } from '@/lib/timeback'
|
|
58
79
|
|
|
59
|
-
export const { GET, POST } = timeback
|
|
80
|
+
export const { GET, POST } = toNextjsHandler(timeback)
|
|
60
81
|
```
|
|
61
82
|
|
|
62
|
-
|
|
83
|
+
### Nuxt
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// server/middleware/timeback.ts
|
|
87
|
+
import { nuxtHandler } from 'timeback/nuxt'
|
|
63
88
|
|
|
64
|
-
|
|
65
|
-
- `GET /api/timeback/identity/session` - Returns current user
|
|
66
|
-
- `GET /api/timeback/identity/signin` - Initiates SSO flow (SSO mode only)
|
|
67
|
-
- `GET /api/timeback/identity/callback` - SSO callback (SSO mode only)
|
|
89
|
+
import { timeback } from '../lib/timeback'
|
|
68
90
|
|
|
69
|
-
|
|
91
|
+
export default defineEventHandler(async event => {
|
|
92
|
+
const response = await nuxtHandler({
|
|
93
|
+
timeback,
|
|
94
|
+
event,
|
|
95
|
+
})
|
|
96
|
+
if (response) return response
|
|
97
|
+
})
|
|
98
|
+
```
|
|
70
99
|
|
|
71
|
-
###
|
|
100
|
+
### SvelteKit
|
|
72
101
|
|
|
73
102
|
```typescript
|
|
74
|
-
//
|
|
75
|
-
import {
|
|
103
|
+
// src/hooks.server.ts
|
|
104
|
+
import { building } from '$app/environment'
|
|
105
|
+
import { timeback } from '$lib/timeback'
|
|
106
|
+
import { svelteKitHandler } from 'timeback/svelte-kit'
|
|
107
|
+
|
|
108
|
+
import type { Handle } from '@sveltejs/kit'
|
|
109
|
+
|
|
110
|
+
export const handle: Handle = ({ event, resolve }) => {
|
|
111
|
+
return svelteKitHandler({
|
|
112
|
+
timeback,
|
|
113
|
+
event,
|
|
114
|
+
resolve,
|
|
115
|
+
building,
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
```
|
|
76
119
|
|
|
77
|
-
|
|
78
|
-
export const timebackClient = createTimebackClient()
|
|
120
|
+
### SolidStart
|
|
79
121
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
122
|
+
```typescript
|
|
123
|
+
// src/middleware.ts
|
|
124
|
+
import { createMiddleware } from '@solidjs/start/middleware'
|
|
125
|
+
import { timeback } from '~/lib/timeback'
|
|
126
|
+
import { solidStartHandler } from 'timeback/solid-start'
|
|
127
|
+
|
|
128
|
+
export default createMiddleware({
|
|
129
|
+
onRequest: [
|
|
130
|
+
async event => {
|
|
131
|
+
const response = await solidStartHandler({
|
|
132
|
+
timeback,
|
|
133
|
+
event,
|
|
134
|
+
})
|
|
135
|
+
if (response) return response
|
|
136
|
+
},
|
|
137
|
+
],
|
|
83
138
|
})
|
|
84
139
|
```
|
|
85
140
|
|
|
86
|
-
###
|
|
141
|
+
### TanStack Start
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// src/routes/api/timeback/$.ts
|
|
145
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
146
|
+
import { toTanStackStartHandler } from 'timeback/tanstack-start'
|
|
147
|
+
|
|
148
|
+
import { timeback } from '@/lib/timeback'
|
|
149
|
+
|
|
150
|
+
const handlers = toTanStackStartHandler(timeback)
|
|
151
|
+
|
|
152
|
+
export const Route = createFileRoute('/api/timeback/$')({
|
|
153
|
+
server: { handlers },
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Express
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// server.ts
|
|
161
|
+
import express from 'express'
|
|
162
|
+
import { toExpressMiddleware } from 'timeback/express'
|
|
163
|
+
|
|
164
|
+
import { timeback } from './lib/timeback'
|
|
165
|
+
|
|
166
|
+
const app = express()
|
|
167
|
+
app.use(express.json())
|
|
168
|
+
app.use('/api/timeback', toExpressMiddleware(timeback))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Client Adapters
|
|
172
|
+
|
|
173
|
+
### React
|
|
87
174
|
|
|
88
175
|
```tsx
|
|
89
176
|
// app/providers.tsx
|
|
90
|
-
|
|
177
|
+
'use client'
|
|
91
178
|
|
|
92
|
-
import {
|
|
179
|
+
import { TimebackProvider } from 'timeback/react'
|
|
93
180
|
|
|
94
|
-
export function Providers({ children }) {
|
|
95
|
-
return <TimebackProvider
|
|
181
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
182
|
+
return <TimebackProvider>{children}</TimebackProvider>
|
|
96
183
|
}
|
|
97
184
|
```
|
|
98
185
|
|
|
99
|
-
### Hooks
|
|
100
|
-
|
|
101
186
|
```tsx
|
|
102
|
-
|
|
187
|
+
// components/ActivityTracker.tsx
|
|
188
|
+
import { useEffect } from 'react'
|
|
189
|
+
import { SignInButton, useTimeback } from 'timeback/react'
|
|
103
190
|
|
|
104
|
-
function
|
|
105
|
-
const
|
|
191
|
+
function MyComponent() {
|
|
192
|
+
const timeback = useTimeback()
|
|
106
193
|
|
|
107
|
-
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
if (!timeback) return
|
|
108
196
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
197
|
+
const activity = timeback.activity
|
|
198
|
+
.new({ id: 'lesson-1', name: 'Intro', courseCode: 'MATH-101' })
|
|
199
|
+
.start()
|
|
112
200
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
201
|
+
return () => {
|
|
202
|
+
activity.end()
|
|
203
|
+
}
|
|
204
|
+
}, [timeback])
|
|
205
|
+
|
|
206
|
+
return <SignInButton size="lg" />
|
|
119
207
|
}
|
|
120
208
|
```
|
|
121
209
|
|
|
122
|
-
###
|
|
210
|
+
### Vue
|
|
123
211
|
|
|
124
|
-
|
|
212
|
+
```vue
|
|
213
|
+
<!-- app.vue -->
|
|
214
|
+
<script setup>
|
|
215
|
+
import { TimebackProvider } from 'timeback/vue'
|
|
216
|
+
</script>
|
|
125
217
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
218
|
+
<template>
|
|
219
|
+
<TimebackProvider>
|
|
220
|
+
<NuxtPage />
|
|
221
|
+
</TimebackProvider>
|
|
222
|
+
</template>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```vue
|
|
226
|
+
<!-- components/ActivityTracker.vue -->
|
|
227
|
+
<script setup>
|
|
228
|
+
import { SignInButton, useTimeback } from 'timeback/vue'
|
|
229
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
230
|
+
|
|
231
|
+
const timeback = useTimeback()
|
|
232
|
+
let activity
|
|
233
|
+
|
|
234
|
+
onMounted(() => {
|
|
235
|
+
if (timeback.value) {
|
|
236
|
+
activity = timeback.value.activity
|
|
237
|
+
.new({ id: 'lesson-1', name: 'Intro', courseCode: 'MATH-101' })
|
|
238
|
+
.start()
|
|
239
|
+
}
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
onUnmounted(() => activity?.end())
|
|
243
|
+
</script>
|
|
244
|
+
|
|
245
|
+
<template>
|
|
246
|
+
<SignInButton size="lg" />
|
|
247
|
+
</template>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Svelte
|
|
251
|
+
|
|
252
|
+
```svelte
|
|
253
|
+
<!-- +layout.svelte -->
|
|
254
|
+
<script>
|
|
255
|
+
import { initTimeback } from 'timeback/svelte'
|
|
256
|
+
|
|
257
|
+
initTimeback()
|
|
258
|
+
|
|
259
|
+
let { children } = $props()
|
|
260
|
+
</script>
|
|
261
|
+
|
|
262
|
+
{@render children()}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```svelte
|
|
266
|
+
<!-- +page.svelte -->
|
|
267
|
+
<script>
|
|
268
|
+
import { onMount, onDestroy } from 'svelte'
|
|
269
|
+
import { SignInButton, timeback } from 'timeback/svelte'
|
|
270
|
+
|
|
271
|
+
let activity
|
|
272
|
+
|
|
273
|
+
onMount(() => {
|
|
274
|
+
if ($timeback) {
|
|
275
|
+
activity = $timeback.activity
|
|
276
|
+
.new({ id: 'lesson-1', name: 'Intro', courseCode: 'MATH-101' })
|
|
277
|
+
.start()
|
|
278
|
+
}
|
|
133
279
|
})
|
|
134
280
|
|
|
281
|
+
onDestroy(() => activity?.end())
|
|
282
|
+
</script>
|
|
283
|
+
|
|
284
|
+
<SignInButton size="lg" />
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Solid
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
// app.tsx
|
|
291
|
+
import { TimebackProvider } from 'timeback/solid'
|
|
292
|
+
|
|
293
|
+
export default function App() {
|
|
135
294
|
return (
|
|
136
|
-
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
295
|
+
<TimebackProvider>
|
|
296
|
+
<Router root={props => <Suspense>{props.children}</Suspense>}>
|
|
297
|
+
<FileRoutes />
|
|
298
|
+
</Router>
|
|
299
|
+
</TimebackProvider>
|
|
141
300
|
)
|
|
142
301
|
}
|
|
143
302
|
```
|
|
144
303
|
|
|
145
|
-
|
|
304
|
+
```tsx
|
|
305
|
+
// components/ActivityTracker.tsx
|
|
306
|
+
import { onCleanup, onMount } from 'solid-js'
|
|
307
|
+
import { SignInButton, useTimeback } from 'timeback/solid'
|
|
146
308
|
|
|
147
|
-
|
|
148
|
-
|
|
309
|
+
function MyComponent() {
|
|
310
|
+
const timeback = useTimeback()
|
|
311
|
+
let activity
|
|
149
312
|
|
|
150
|
-
|
|
313
|
+
onMount(() => {
|
|
314
|
+
if (!timeback) return
|
|
151
315
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
courseCode: 'FASTMATH-1',
|
|
157
|
-
})
|
|
316
|
+
activity = timeback.activity
|
|
317
|
+
.new({ id: 'lesson-1', name: 'Intro', courseCode: 'MATH-101' })
|
|
318
|
+
.start()
|
|
319
|
+
})
|
|
158
320
|
|
|
159
|
-
|
|
160
|
-
activity.pause()
|
|
161
|
-
activity.resume()
|
|
321
|
+
onCleanup(() => activity?.end())
|
|
162
322
|
|
|
163
|
-
|
|
164
|
-
|
|
323
|
+
return <SignInButton size="lg" />
|
|
324
|
+
}
|
|
165
325
|
```
|
|
166
326
|
|
|
167
327
|
## Identity Modes
|
|
168
328
|
|
|
169
|
-
###
|
|
329
|
+
### SSO Mode
|
|
170
330
|
|
|
171
|
-
Uses Timeback as the identity provider via OIDC
|
|
331
|
+
Uses Timeback as the identity provider via OIDC:
|
|
172
332
|
|
|
173
333
|
```typescript
|
|
174
334
|
identity: {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
335
|
+
mode: 'sso',
|
|
336
|
+
clientId: process.env.AWS_COGNITO_CLIENT_ID!,
|
|
337
|
+
clientSecret: process.env.AWS_COGNITO_CLIENT_SECRET!,
|
|
338
|
+
redirectUri: 'http://localhost:3000/api/auth/sso/callback/timeback',
|
|
339
|
+
onCallbackSuccess: ({ user, state, redirect }) => redirect('/'),
|
|
340
|
+
onCallbackError: ({ error, redirect }) => redirect('/?error=sso_failed'),
|
|
341
|
+
getUser: () => getCurrentSession(),
|
|
178
342
|
}
|
|
179
343
|
```
|
|
180
344
|
|
|
181
|
-
### Custom
|
|
345
|
+
### Custom Mode
|
|
182
346
|
|
|
183
|
-
For apps with existing
|
|
347
|
+
For apps with existing auth (Clerk, Auth0, Supabase, etc.):
|
|
184
348
|
|
|
185
349
|
```typescript
|
|
186
350
|
identity: {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
email: session.user.email,
|
|
194
|
-
name: session.user.name,
|
|
195
|
-
}
|
|
196
|
-
},
|
|
351
|
+
mode: 'custom',
|
|
352
|
+
getUser: async (req) => {
|
|
353
|
+
const session = await getSession(req)
|
|
354
|
+
if (!session) return undefined
|
|
355
|
+
return { id: session.userId, email: session.email, name: session.name }
|
|
356
|
+
},
|
|
197
357
|
}
|
|
198
358
|
```
|
|
199
359
|
|
|
200
|
-
##
|
|
360
|
+
## Identity-Only Integration
|
|
201
361
|
|
|
202
|
-
|
|
362
|
+
If you only need Timeback SSO authentication without activity tracking or Timeback API integration, use `createIdentityServer()`. This is a lightweight alternative that:
|
|
203
363
|
|
|
204
|
-
-
|
|
205
|
-
- `timeback.
|
|
364
|
+
- Does not require Timeback API credentials
|
|
365
|
+
- Does not require `timeback.config.ts`
|
|
366
|
+
- Only exposes identity routes (sign-in, callback, sign-out)
|
|
206
367
|
|
|
207
|
-
###
|
|
368
|
+
### Server Setup
|
|
208
369
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
- `client.signOut()` - Sign out
|
|
213
|
-
- `client.fetchSession()` - Fetch current session
|
|
370
|
+
```typescript
|
|
371
|
+
// lib/timeback.ts
|
|
372
|
+
import { createIdentityServer } from 'timeback'
|
|
214
373
|
|
|
215
|
-
|
|
374
|
+
export const timeback = createIdentityServer({
|
|
375
|
+
env: 'production',
|
|
376
|
+
identity: {
|
|
377
|
+
mode: 'sso',
|
|
378
|
+
clientId: process.env.AWS_COGNITO_CLIENT_ID!,
|
|
379
|
+
clientSecret: process.env.AWS_COGNITO_CLIENT_SECRET!,
|
|
380
|
+
onCallbackSuccess: async ({ user, tokens, redirect }) => {
|
|
381
|
+
// Create your own session, then redirect
|
|
382
|
+
await createSession(user)
|
|
383
|
+
return redirect('/')
|
|
384
|
+
},
|
|
385
|
+
onCallbackError: ({ error, redirect }) => {
|
|
386
|
+
console.error('SSO Error:', error)
|
|
387
|
+
return redirect('/login?error=sso_failed')
|
|
388
|
+
},
|
|
389
|
+
getUser: req => getSessionFromRequest(req),
|
|
390
|
+
},
|
|
391
|
+
})
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Next.js
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
// app/api/timeback/[...timeback]/route.ts
|
|
398
|
+
import { toNextjsHandler } from 'timeback/nextjs'
|
|
399
|
+
|
|
400
|
+
import { timeback } from '@/lib/timeback'
|
|
401
|
+
|
|
402
|
+
export const { GET, POST } = toNextjsHandler(timeback)
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Express
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
// server.ts
|
|
409
|
+
import express from 'express'
|
|
410
|
+
import { toExpressMiddleware } from 'timeback/express'
|
|
411
|
+
|
|
412
|
+
import { timeback } from './lib/timeback'
|
|
413
|
+
|
|
414
|
+
const app = express()
|
|
415
|
+
app.use('/api/timeback', toExpressMiddleware(timeback))
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
All other framework adapters (Nuxt, SvelteKit, SolidStart, TanStack Start) work identically with identity-only instances.
|
|
419
|
+
|
|
420
|
+
## Activity Tracking
|
|
421
|
+
|
|
422
|
+
Activities track time spent on learning content:
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
// Start an activity
|
|
426
|
+
const activity = timeback.activity
|
|
427
|
+
.new({
|
|
428
|
+
id: 'lesson-123',
|
|
429
|
+
name: 'Introduction to Fractions',
|
|
430
|
+
courseCode: 'MATH-101',
|
|
431
|
+
})
|
|
432
|
+
.start()
|
|
433
|
+
|
|
434
|
+
// Pause/resume
|
|
435
|
+
activity.pause()
|
|
436
|
+
activity.resume()
|
|
437
|
+
|
|
438
|
+
// End with metrics
|
|
439
|
+
await activity.end({
|
|
440
|
+
totalQuestions: 10,
|
|
441
|
+
correctQuestions: 8,
|
|
442
|
+
xpEarned: 80,
|
|
443
|
+
masteredUnits: 1,
|
|
444
|
+
})
|
|
445
|
+
```
|
|
216
446
|
|
|
217
|
-
|
|
218
|
-
- `useTimeback()` - Hook for identity state and actions
|
|
219
|
-
- `useActivity(params)` - Hook for activity tracking with lifecycle management
|
|
447
|
+
The SDK automatically sends activity data to your server, which forwards it to the Timeback API.
|