@timeback/sdk 0.1.9 → 0.1.10
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/chunk-3mqpr9vx.js +2 -0
- package/dist/chunk-92nnwa7t.js +2 -0
- package/dist/{chunk-agpf1x3g.js → chunk-af3xwwsv.js} +1 -1
- package/dist/{chunk-07j8zre9.js → chunk-b8649tw4.js} +1 -1
- package/dist/{chunk-63afdp3y.js → chunk-bd09q1fw.js} +6 -6
- package/dist/chunk-js665z11.js +1 -0
- package/dist/chunk-nsr7a2dv.js +2 -0
- package/dist/chunk-sgcwg4j6.js +1 -0
- package/dist/{chunk-9se82640.js → chunk-txwjkpfz.js} +1 -1
- package/dist/client/adapters/react/hooks/types.d.ts +2 -29
- package/dist/client/adapters/react/hooks/types.d.ts.map +1 -1
- package/dist/client/adapters/react/hooks/useTimebackVerification.d.ts.map +1 -1
- package/dist/client/adapters/react/index.js +2 -2
- package/dist/client/adapters/solid/types.d.ts +2 -29
- package/dist/client/adapters/solid/types.d.ts.map +1 -1
- package/dist/client/adapters/solid/types.ts +2 -18
- package/dist/client/adapters/svelte/stores/client.d.ts.map +1 -1
- package/dist/client/adapters/svelte/stores/client.ts +2 -9
- package/dist/client/adapters/svelte/stores/profile.d.ts +1 -1
- package/dist/client/adapters/svelte/stores/profile.d.ts.map +1 -1
- package/dist/client/adapters/svelte/stores/profile.ts +4 -11
- package/dist/client/adapters/svelte/stores/verification.d.ts.map +1 -1
- package/dist/client/adapters/svelte/stores/verification.ts +1 -10
- package/dist/client/adapters/svelte/types.d.ts +1 -29
- package/dist/client/adapters/svelte/types.d.ts.map +1 -1
- package/dist/client/adapters/vue/provider.d.ts.map +1 -1
- package/dist/client/adapters/vue/provider.ts +4 -11
- package/dist/client/adapters/vue/types.d.ts +2 -29
- package/dist/client/adapters/vue/types.d.ts.map +1 -1
- package/dist/client/adapters/vue/types.ts +2 -18
- package/dist/client/auth/types.d.ts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/lib/activity/activity.class.d.ts +130 -22
- package/dist/client/lib/activity/activity.class.d.ts.map +1 -1
- package/dist/client/lib/activity/transport.d.ts +15 -0
- package/dist/client/lib/activity/transport.d.ts.map +1 -0
- package/dist/client/lib/activity/types.d.ts +53 -0
- package/dist/client/lib/activity/types.d.ts.map +1 -0
- package/dist/client/lib/utils.d.ts +18 -0
- package/dist/client/lib/utils.d.ts.map +1 -1
- package/dist/client/lib/utils.ts +109 -0
- package/dist/client/namespaces/activity.d.ts +45 -6
- package/dist/client/namespaces/activity.d.ts.map +1 -1
- package/dist/client/timeback-client.class.d.ts +7 -1
- package/dist/client/timeback-client.class.d.ts.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/edge.js +1 -1
- package/dist/identity.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -22
- package/dist/server/adapters/express.d.ts.map +1 -1
- package/dist/server/adapters/express.js +1 -1
- package/dist/server/adapters/native.d.ts.map +1 -1
- package/dist/server/adapters/native.js +1 -1
- package/dist/server/adapters/nextjs.js +1 -1
- package/dist/server/adapters/nuxt.d.ts.map +1 -1
- package/dist/server/adapters/nuxt.js +1 -1
- package/dist/server/adapters/solid-start.d.ts.map +1 -1
- package/dist/server/adapters/solid-start.js +1 -1
- package/dist/server/adapters/svelte-kit.d.ts.map +1 -1
- package/dist/server/adapters/svelte-kit.js +1 -1
- package/dist/server/adapters/tanstack-start.d.ts.map +1 -1
- package/dist/server/adapters/tanstack-start.js +1 -1
- package/dist/server/adapters/utils.d.ts +1 -1
- package/dist/server/adapters/utils.d.ts.map +1 -1
- package/dist/server/handlers/activity/caliper.d.ts +50 -14
- package/dist/server/handlers/activity/caliper.d.ts.map +1 -1
- package/dist/server/handlers/activity/heartbeat-handler.d.ts +15 -0
- package/dist/server/handlers/activity/heartbeat-handler.d.ts.map +1 -0
- package/dist/server/handlers/activity/index.d.ts +5 -3
- package/dist/server/handlers/activity/index.d.ts.map +1 -1
- package/dist/server/handlers/activity/progress.d.ts +2 -2
- package/dist/server/handlers/activity/progress.d.ts.map +1 -1
- package/dist/server/handlers/activity/schema.d.ts +40 -6
- package/dist/server/handlers/activity/schema.d.ts.map +1 -1
- package/dist/server/handlers/activity/submit-handler.d.ts +29 -0
- package/dist/server/handlers/activity/submit-handler.d.ts.map +1 -0
- package/dist/server/handlers/activity/submit.d.ts +44 -0
- package/dist/server/handlers/activity/submit.d.ts.map +1 -0
- package/dist/server/handlers/activity/types.d.ts +126 -5
- package/dist/server/handlers/activity/types.d.ts.map +1 -1
- package/dist/server/handlers/identity/handler.d.ts +23 -4
- package/dist/server/handlers/identity/handler.d.ts.map +1 -1
- package/dist/server/handlers/identity/index.d.ts +2 -2
- package/dist/server/handlers/identity/index.d.ts.map +1 -1
- package/dist/server/handlers/identity/oidc.d.ts.map +1 -1
- package/dist/server/handlers/identity/types.d.ts +0 -6
- package/dist/server/handlers/identity/types.d.ts.map +1 -1
- package/dist/server/handlers/index.d.ts +3 -3
- package/dist/server/handlers/index.d.ts.map +1 -1
- package/dist/server/handlers/user/handler.d.ts.map +1 -1
- package/dist/server/handlers/user/profile.d.ts.map +1 -1
- package/dist/server/handlers/user/types.d.ts +3 -0
- package/dist/server/handlers/user/types.d.ts.map +1 -1
- package/dist/server/handlers/user/verify.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/lib/hooks.d.ts +20 -0
- package/dist/server/lib/hooks.d.ts.map +1 -0
- package/dist/server/lib/index.d.ts +4 -2
- package/dist/server/lib/index.d.ts.map +1 -1
- package/dist/server/lib/logger.d.ts +36 -9
- package/dist/server/lib/logger.d.ts.map +1 -1
- package/dist/server/lib/resolve.d.ts +1 -1
- package/dist/server/lib/resolve.d.ts.map +1 -1
- package/dist/server/lib/utils.d.ts +19 -1
- package/dist/server/lib/utils.d.ts.map +1 -1
- package/dist/server/lib/validation.d.ts +55 -0
- package/dist/server/lib/validation.d.ts.map +1 -0
- package/dist/server/namespaces/activity/index.d.ts +8 -0
- package/dist/server/namespaces/activity/index.d.ts.map +1 -0
- package/dist/server/namespaces/activity/record.d.ts +49 -0
- package/dist/server/namespaces/activity/record.d.ts.map +1 -0
- package/dist/server/namespaces/activity/schema.d.ts +50 -0
- package/dist/server/namespaces/activity/schema.d.ts.map +1 -0
- package/dist/server/namespaces/user/get-profile.d.ts +32 -0
- package/dist/server/namespaces/user/get-profile.d.ts.map +1 -0
- package/dist/server/namespaces/user/index.d.ts +8 -0
- package/dist/server/namespaces/user/index.d.ts.map +1 -0
- package/dist/server/namespaces/user/verify.d.ts +28 -0
- package/dist/server/namespaces/user/verify.d.ts.map +1 -0
- package/dist/server/timeback.d.ts +1 -1
- package/dist/server/timeback.d.ts.map +1 -1
- package/dist/server/types.d.ts +394 -12
- package/dist/server/types.d.ts.map +1 -1
- package/dist/shared/constants.d.ts +7 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.ts +51 -0
- package/dist/shared/index.d.ts +9 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/schemas.d.ts +57 -0
- package/dist/shared/schemas.d.ts.map +1 -0
- package/dist/shared/types.d.ts +263 -10
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.ts +620 -0
- package/package.json +2 -2
- package/dist/chunk-5171mkp2.js +0 -2
- package/dist/chunk-8gg8n8v9.js +0 -2
- package/dist/chunk-hnf0tart.js +0 -2
- package/dist/chunk-qr0bbnsr.js +0 -1
- package/dist/chunk-x9gvef7q.js +0 -1
- package/dist/server/handlers/activity/handler.d.ts +0 -32
- package/dist/server/handlers/activity/handler.d.ts.map +0 -1
- package/dist/shared/xp-calculator.d.ts +0 -25
- package/dist/shared/xp-calculator.d.ts.map +0 -1
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Types
|
|
3
|
+
*
|
|
4
|
+
* Types shared between client and server.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { TimebackGrade, TimebackSubject } from '@timeback/types'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* User identity returned from SSO.
|
|
11
|
+
*/
|
|
12
|
+
export interface TimebackIdentity {
|
|
13
|
+
id: string
|
|
14
|
+
email: string
|
|
15
|
+
name?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Timeback user profile with enriched data from the Timeback API.
|
|
20
|
+
*/
|
|
21
|
+
export interface TimebackProfile {
|
|
22
|
+
/** Timeback user ID */
|
|
23
|
+
id: string
|
|
24
|
+
/** User's email address */
|
|
25
|
+
email: string
|
|
26
|
+
/** User's display name */
|
|
27
|
+
name?: string
|
|
28
|
+
|
|
29
|
+
/** School information */
|
|
30
|
+
school?: {
|
|
31
|
+
id: string
|
|
32
|
+
name: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Grade level */
|
|
36
|
+
grade?: number
|
|
37
|
+
|
|
38
|
+
/** XP earned on this app */
|
|
39
|
+
xp?: {
|
|
40
|
+
/** XP earned today (UTC day range) */
|
|
41
|
+
today: number
|
|
42
|
+
/** XP earned across all time (computed from analytics) */
|
|
43
|
+
all: number
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Enrolled courses */
|
|
47
|
+
courses?: Array<{
|
|
48
|
+
id: string
|
|
49
|
+
code: string
|
|
50
|
+
name: string
|
|
51
|
+
}>
|
|
52
|
+
|
|
53
|
+
/** Goals and progress */
|
|
54
|
+
goals?: {
|
|
55
|
+
dailyXp?: number
|
|
56
|
+
dailyLessons?: number
|
|
57
|
+
dailyActiveMinutes?: number
|
|
58
|
+
dailyAccuracy?: number
|
|
59
|
+
dailyMasteredUnits?: number
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Recommended minimal user payload to persist in a session.
|
|
65
|
+
*
|
|
66
|
+
* **User-facing note:** this type is part of the SDK’s developer experience.
|
|
67
|
+
* It exists to give you a “safe default” session shape that works well for
|
|
68
|
+
* cookie-based sessions (small payload) while still carrying enough Timeback
|
|
69
|
+
* context to power common UI affordances (e.g. showing a school name or grade).
|
|
70
|
+
*
|
|
71
|
+
* **What it is:** a minimal, serializable subset of `TimebackProfile`.
|
|
72
|
+
* **What it isn’t:** a guarantee that you’ll always have the full Timeback
|
|
73
|
+
* profile (courses, goals, xp, etc.) in-session. If you need richer data, fetch
|
|
74
|
+
* it from the API (e.g. `timeback.user.fetch()`) and cache/store it according
|
|
75
|
+
* to your app’s needs.
|
|
76
|
+
*
|
|
77
|
+
* **Stability:** this is still early and we’re actively iterating on identity
|
|
78
|
+
* and session ergonomics. We may rename, restructure, or remove this type from
|
|
79
|
+
* the public surface as the SDK evolves.
|
|
80
|
+
*/
|
|
81
|
+
export type TimebackSessionUser = Pick<
|
|
82
|
+
TimebackProfile,
|
|
83
|
+
'id' | 'email' | 'name' | 'school' | 'grade'
|
|
84
|
+
>
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Claims from the identity provider (IdP).
|
|
88
|
+
*
|
|
89
|
+
* Normalized subset of OIDC UserInfo claims.
|
|
90
|
+
*/
|
|
91
|
+
export interface IdentityClaims {
|
|
92
|
+
/** Subject identifier (unique user ID from IdP) */
|
|
93
|
+
sub: string
|
|
94
|
+
/** User's email address */
|
|
95
|
+
email: string
|
|
96
|
+
/** User's first/given name */
|
|
97
|
+
firstName?: string
|
|
98
|
+
/** User's last/family name */
|
|
99
|
+
lastName?: string
|
|
100
|
+
/** User's profile picture URL */
|
|
101
|
+
pictureUrl?: string
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Authenticated user with Timeback profile and IdP claims.
|
|
106
|
+
*
|
|
107
|
+
* This is the primary user object returned during SSO callback when using
|
|
108
|
+
* `createTimeback()`. The `id` field is the canonical `timebackId` (stable identifier).
|
|
109
|
+
*/
|
|
110
|
+
export interface TimebackAuthUser extends TimebackProfile {
|
|
111
|
+
/** IdP claims (raw identity provider data) */
|
|
112
|
+
claims: IdentityClaims
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Course selector by subject and grade (grade-based apps).
|
|
117
|
+
*
|
|
118
|
+
* Use this for traditional K-12 apps where courses are identified by subject + grade.
|
|
119
|
+
*/
|
|
120
|
+
export interface SubjectGradeCourseRef {
|
|
121
|
+
subject: TimebackSubject
|
|
122
|
+
grade: TimebackGrade
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Course selector by code (grade-less apps).
|
|
127
|
+
*
|
|
128
|
+
* Use this for apps without grade levels (e.g., CS platforms) where courses
|
|
129
|
+
* are identified by a unique course code.
|
|
130
|
+
*/
|
|
131
|
+
export interface CourseCodeRef {
|
|
132
|
+
code: string
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Course selector for activity tracking.
|
|
137
|
+
*
|
|
138
|
+
* This should correspond to a unique course entry in `timeback.config.json`.
|
|
139
|
+
*
|
|
140
|
+
* Two selector modes are supported:
|
|
141
|
+
* - **Grade-based**: `{ subject, grade }` — K-12 style
|
|
142
|
+
* - **Grade-less**: `{ code }` — CS/skill-based
|
|
143
|
+
*
|
|
144
|
+
* @example Grade-based
|
|
145
|
+
* ```typescript
|
|
146
|
+
* { subject: 'Math', grade: 3 }
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @example Grade-less
|
|
150
|
+
* ```typescript
|
|
151
|
+
* { code: 'CS-101' }
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export type ActivityCourseRef = SubjectGradeCourseRef | CourseCodeRef
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Type guard: Check if a course ref uses subject+grade identity.
|
|
158
|
+
*
|
|
159
|
+
* @param ref - Course reference to check
|
|
160
|
+
* @returns True if grade-based selector
|
|
161
|
+
*/
|
|
162
|
+
export function isSubjectGradeCourseRef(ref: ActivityCourseRef): ref is SubjectGradeCourseRef {
|
|
163
|
+
return 'grade' in ref && ref.grade !== undefined
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Time tracking configuration options.
|
|
168
|
+
*
|
|
169
|
+
* Controls how the SDK tracks and reports time-spent data via heartbeats.
|
|
170
|
+
*/
|
|
171
|
+
export interface TimeTrackingOptions {
|
|
172
|
+
/**
|
|
173
|
+
* Interval in milliseconds between automatic heartbeat flushes.
|
|
174
|
+
* @default 15000 (15 seconds)
|
|
175
|
+
*/
|
|
176
|
+
flushIntervalMs?: number
|
|
177
|
+
/**
|
|
178
|
+
* Whether to pause time tracking when the tab is not visible.
|
|
179
|
+
* @default true
|
|
180
|
+
*/
|
|
181
|
+
visibilityAware?: boolean
|
|
182
|
+
/**
|
|
183
|
+
* Whether to flush accumulated time when the tab becomes hidden.
|
|
184
|
+
* @default true
|
|
185
|
+
*/
|
|
186
|
+
flushOnVisibilityHidden?: boolean
|
|
187
|
+
/**
|
|
188
|
+
* Whether to attempt a best-effort flush on page unload (pagehide event).
|
|
189
|
+
*
|
|
190
|
+
* Implementation notes:
|
|
191
|
+
* - Prefer `navigator.sendBeacon()` when available and safe to use
|
|
192
|
+
* - Fall back to `fetch(..., { keepalive: true })` otherwise
|
|
193
|
+
*
|
|
194
|
+
* sendBeacon cannot set arbitrary headers (e.g. Authorization), so
|
|
195
|
+
* integrations that rely on bearer tokens typically use the keepalive
|
|
196
|
+
* fetch fallback.
|
|
197
|
+
* @default true
|
|
198
|
+
*/
|
|
199
|
+
flushOnPageHide?: boolean
|
|
200
|
+
/**
|
|
201
|
+
* Timeout in milliseconds after which hidden time stops being tracked.
|
|
202
|
+
*
|
|
203
|
+
* When the tab is hidden for longer than this duration, heartbeats stop
|
|
204
|
+
* and the hidden time is not counted. When the user returns, tracking
|
|
205
|
+
* resumes fresh without counting the extended absence.
|
|
206
|
+
*
|
|
207
|
+
* Set to `null` or `Infinity` to disable (always track hidden time).
|
|
208
|
+
* @default 600000 (10 minutes)
|
|
209
|
+
*/
|
|
210
|
+
hiddenTimeoutMs?: number | null
|
|
211
|
+
/**
|
|
212
|
+
* Number of retry attempts for failed heartbeat sends.
|
|
213
|
+
*
|
|
214
|
+
* Set to `0` (default) for no retries. Retries use exponential backoff
|
|
215
|
+
* with delays configured by `retryDelaysMs`.
|
|
216
|
+
*
|
|
217
|
+
* @default 0
|
|
218
|
+
*/
|
|
219
|
+
retryAttempts?: number
|
|
220
|
+
/**
|
|
221
|
+
* Delay schedule (in milliseconds) between retry attempts.
|
|
222
|
+
*
|
|
223
|
+
* Each index corresponds to the delay before that retry attempt.
|
|
224
|
+
* If more attempts are made than there are entries, the last value is reused.
|
|
225
|
+
*
|
|
226
|
+
* @default [100, 300, 1000]
|
|
227
|
+
*/
|
|
228
|
+
retryDelaysMs?: number[]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Activity start parameters.
|
|
233
|
+
*
|
|
234
|
+
* @remarks
|
|
235
|
+
* The `id` field is treated as a **slug** (not a URL). The SDK derives the
|
|
236
|
+
* canonical activity URL (`event.object.id`) from:
|
|
237
|
+
* - The configured sensor URL
|
|
238
|
+
* - The course selector (subject + grade or code)
|
|
239
|
+
* - This slug (URI-encoded)
|
|
240
|
+
*
|
|
241
|
+
* This allows upstream systems to process activities without requiring
|
|
242
|
+
* pre-synced OneRoster component resources.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* // Grade-based course
|
|
247
|
+
* timeback.activity.start({
|
|
248
|
+
* id: 'fractions-with-like-denominators', // slug
|
|
249
|
+
* name: 'Fractions with Like Denominators', // human-readable
|
|
250
|
+
* course: { subject: 'Math', grade: 3 },
|
|
251
|
+
* })
|
|
252
|
+
* // => object.id: https://sensor.example.com/activities/Math/g3/fractions-with-like-denominators
|
|
253
|
+
*
|
|
254
|
+
* // Grade-less course
|
|
255
|
+
* timeback.activity.start({
|
|
256
|
+
* id: 'intro-to-loops',
|
|
257
|
+
* name: 'Introduction to Loops',
|
|
258
|
+
* course: { code: 'CS-101' },
|
|
259
|
+
* })
|
|
260
|
+
* // => object.id: https://sensor.example.com/activities/CS-101/intro-to-loops
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
export interface ActivityParams {
|
|
264
|
+
/**
|
|
265
|
+
* Activity slug (stable identifier for the learning object).
|
|
266
|
+
*
|
|
267
|
+
* This is used to construct the canonical activity URL sent to Caliper.
|
|
268
|
+
* Use a short, URL-safe slug like `"fractions-with-like-denominators"` or
|
|
269
|
+
* `"lesson-1"`. Special characters will be URI-encoded.
|
|
270
|
+
*
|
|
271
|
+
* @example 'fractions-with-like-denominators'
|
|
272
|
+
* @example 'ccss.math.content.3.nf.a.1'
|
|
273
|
+
* @example 'lesson-1'
|
|
274
|
+
*/
|
|
275
|
+
id: string
|
|
276
|
+
/**
|
|
277
|
+
* Human-readable display name of the activity.
|
|
278
|
+
*
|
|
279
|
+
* This is sent as `object.activity.name` in Caliper events.
|
|
280
|
+
*
|
|
281
|
+
* @example 'Fractions with Like Denominators'
|
|
282
|
+
*/
|
|
283
|
+
name: string
|
|
284
|
+
/** Course selector (must match a unique course in timeback.config.json) */
|
|
285
|
+
course: ActivityCourseRef
|
|
286
|
+
/**
|
|
287
|
+
* Optional run identifier for correlating events across sessions.
|
|
288
|
+
*
|
|
289
|
+
* When resuming an activity, provide the same `runId` from the previous session
|
|
290
|
+
* to correlate time-spent events with the eventual completion event.
|
|
291
|
+
*
|
|
292
|
+
* If not provided, the SDK generates a new UUID.
|
|
293
|
+
*/
|
|
294
|
+
runId?: string
|
|
295
|
+
/**
|
|
296
|
+
* Time tracking configuration options.
|
|
297
|
+
*
|
|
298
|
+
* Heartbeats are enabled by default. Use this to customize flush intervals
|
|
299
|
+
* or disable visibility-aware tracking.
|
|
300
|
+
*
|
|
301
|
+
* Set to `false` to disable client-side time tracking entirely. When
|
|
302
|
+
* disabled, no heartbeats are sent, no visibility handlers are registered,
|
|
303
|
+
* and `end()` skips the final time flush. Use this when time is managed
|
|
304
|
+
* server-side (e.g. via `timeback.activity.record()`).
|
|
305
|
+
*/
|
|
306
|
+
time?: TimeTrackingOptions | false
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Called when a heartbeat or submission fails.
|
|
310
|
+
*
|
|
311
|
+
* Heartbeat errors are non-fatal — the SDK continues tracking time
|
|
312
|
+
* regardless. Submit errors (from `end()`) are also surfaced here
|
|
313
|
+
* before being re-thrown.
|
|
314
|
+
*
|
|
315
|
+
* @param error - The error that occurred
|
|
316
|
+
* @param context - Details about the failed operation
|
|
317
|
+
*/
|
|
318
|
+
onError?: (error: Error, context: ActivityErrorContext) => void
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Called when the activity is paused (via `pause()` or visibility timeout).
|
|
322
|
+
*/
|
|
323
|
+
onPause?: () => void
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Called when the activity resumes after being paused.
|
|
327
|
+
*/
|
|
328
|
+
onResume?: () => void
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Called after each successful heartbeat flush.
|
|
332
|
+
*
|
|
333
|
+
* @param elapsedMs - Active milliseconds reported in this flush
|
|
334
|
+
*/
|
|
335
|
+
onFlush?: (elapsedMs: number) => void
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Context passed to the `onError` callback.
|
|
340
|
+
*/
|
|
341
|
+
export interface ActivityErrorContext {
|
|
342
|
+
/** Which operation failed — aligns with Caliper event types. */
|
|
343
|
+
type: 'timeSpent' | 'completion'
|
|
344
|
+
/** The activity slug passed to `activity.start()`. */
|
|
345
|
+
activityId: string
|
|
346
|
+
/** The `runId` for this activity instance. */
|
|
347
|
+
runId: string
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Activity metrics (optional performance data).
|
|
352
|
+
*/
|
|
353
|
+
export interface ActivityMetrics {
|
|
354
|
+
/** Total questions attempted */
|
|
355
|
+
totalQuestions?: number
|
|
356
|
+
/** Number of correct answers */
|
|
357
|
+
correctQuestions?: number
|
|
358
|
+
/** XP earned from this activity */
|
|
359
|
+
xpEarned?: number
|
|
360
|
+
/** Number of units mastered */
|
|
361
|
+
masteredUnits?: number
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Question count metrics for activity completion.
|
|
366
|
+
*
|
|
367
|
+
* @example Basic usage
|
|
368
|
+
* ```typescript
|
|
369
|
+
* await activity.end({
|
|
370
|
+
* xpEarned: 100,
|
|
371
|
+
* totalQuestions: 10,
|
|
372
|
+
* correctQuestions: 8,
|
|
373
|
+
* })
|
|
374
|
+
* ```
|
|
375
|
+
*
|
|
376
|
+
* @example With time override
|
|
377
|
+
* ```typescript
|
|
378
|
+
* await activity.end({
|
|
379
|
+
* xpEarned: 100,
|
|
380
|
+
* totalQuestions: 10,
|
|
381
|
+
* correctQuestions: 8,
|
|
382
|
+
* time: { active: 42000, inactive: 3000 },
|
|
383
|
+
* })
|
|
384
|
+
* ```
|
|
385
|
+
*/
|
|
386
|
+
type QuestionCountMetrics =
|
|
387
|
+
| {
|
|
388
|
+
/**
|
|
389
|
+
* Total questions attempted.
|
|
390
|
+
*
|
|
391
|
+
* If provided, `correctQuestions` is required too.
|
|
392
|
+
*/
|
|
393
|
+
totalQuestions: number
|
|
394
|
+
/**
|
|
395
|
+
* Number of correct answers.
|
|
396
|
+
*
|
|
397
|
+
* Must be provided when `totalQuestions` is provided.
|
|
398
|
+
*/
|
|
399
|
+
correctQuestions: number
|
|
400
|
+
}
|
|
401
|
+
| {
|
|
402
|
+
/** Omit question counts entirely. */
|
|
403
|
+
totalQuestions?: undefined
|
|
404
|
+
/** Omit question counts entirely. */
|
|
405
|
+
correctQuestions?: undefined
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Optional time override for activity.end() */
|
|
409
|
+
interface ActivityEndTimeOverride {
|
|
410
|
+
/** Active time in milliseconds */
|
|
411
|
+
active: number
|
|
412
|
+
/** Inactive/paused time in milliseconds (defaults to 0) */
|
|
413
|
+
inactive?: number
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Time-only end: final flush without completion event.
|
|
418
|
+
*
|
|
419
|
+
* Call `activity.end()` with no args or just a time override to flush
|
|
420
|
+
* accumulated time without sending an ActivityCompletedEvent.
|
|
421
|
+
*/
|
|
422
|
+
type ActivityEndTimeOnly = {
|
|
423
|
+
totalQuestions?: undefined
|
|
424
|
+
correctQuestions?: undefined
|
|
425
|
+
xpEarned?: undefined
|
|
426
|
+
masteredUnits?: undefined
|
|
427
|
+
pctComplete?: undefined
|
|
428
|
+
time?: ActivityEndTimeOverride
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** Completion end: flush + ActivityCompletedEvent. */
|
|
432
|
+
type ActivityEndCompletion = QuestionCountMetrics & {
|
|
433
|
+
/** XP earned from this activity. */
|
|
434
|
+
xpEarned: number
|
|
435
|
+
/** Number of units mastered */
|
|
436
|
+
masteredUnits?: number
|
|
437
|
+
/**
|
|
438
|
+
* App-reported course progress (0–100). Values outside range are clamped.
|
|
439
|
+
*/
|
|
440
|
+
pctComplete?: number
|
|
441
|
+
/**
|
|
442
|
+
* Optional time override. When provided, the SDK uses these values instead
|
|
443
|
+
* of the internal timer. Values are clamped to >= 0 and rounded to integers.
|
|
444
|
+
*/
|
|
445
|
+
time?: ActivityEndTimeOverride
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Data for ending an activity.
|
|
450
|
+
*
|
|
451
|
+
* Two modes:
|
|
452
|
+
* - **Time-only**: `activity.end()` or `activity.end({ time: {...} })` — final
|
|
453
|
+
* flush only, no completion event
|
|
454
|
+
* - **Completion**: `activity.end({ xpEarned, ... })` — final flush + completion event
|
|
455
|
+
*/
|
|
456
|
+
export type ActivityEndData = ActivityEndTimeOnly | ActivityEndCompletion
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Activity state sent to the server when ending.
|
|
460
|
+
*
|
|
461
|
+
* @see {@link ActivityParams} for documentation on `id` and `name` semantics.
|
|
462
|
+
*/
|
|
463
|
+
export interface ActivityEndPayload {
|
|
464
|
+
/**
|
|
465
|
+
* Activity slug (stable identifier for the learning object).
|
|
466
|
+
*
|
|
467
|
+
* @see {@link ActivityParams.id}
|
|
468
|
+
*/
|
|
469
|
+
id: string
|
|
470
|
+
/**
|
|
471
|
+
* Human-readable display name of the activity.
|
|
472
|
+
*
|
|
473
|
+
* @see {@link ActivityParams.name}
|
|
474
|
+
*/
|
|
475
|
+
name: string
|
|
476
|
+
/** Course selector (must match a unique course in timeback.config.json) */
|
|
477
|
+
course: ActivityCourseRef
|
|
478
|
+
/** ISO 8601 timestamp when activity started */
|
|
479
|
+
startedAt: string
|
|
480
|
+
/** ISO 8601 timestamp when activity ended */
|
|
481
|
+
endedAt: string
|
|
482
|
+
/** Active time in milliseconds (excluding paused time) */
|
|
483
|
+
elapsedMs: number
|
|
484
|
+
/** Total paused time in milliseconds */
|
|
485
|
+
pausedMs: number
|
|
486
|
+
/** Activity metrics */
|
|
487
|
+
metrics: ActivityMetrics
|
|
488
|
+
/**
|
|
489
|
+
* App-reported course progress (per enrollment), as a percentage from 0–100.
|
|
490
|
+
*
|
|
491
|
+
* This is forwarded to Caliper events as `generated.extensions.pctCompleteApp`.
|
|
492
|
+
*
|
|
493
|
+
* @remarks
|
|
494
|
+
* - Scale: 0 to 100 (not 0 to 1)
|
|
495
|
+
* - Values outside 0–100 are clamped
|
|
496
|
+
*/
|
|
497
|
+
pctComplete?: number
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Activity heartbeat payload for time-spent tracking.
|
|
502
|
+
*
|
|
503
|
+
* Sent periodically to report accumulated active time for a time window.
|
|
504
|
+
* The server builds a `TimeSpentEvent` from this data.
|
|
505
|
+
*/
|
|
506
|
+
export interface ActivityHeartbeatPayload {
|
|
507
|
+
/**
|
|
508
|
+
* Activity slug (stable identifier for the learning object).
|
|
509
|
+
*/
|
|
510
|
+
id: string
|
|
511
|
+
/**
|
|
512
|
+
* Human-readable display name of the activity.
|
|
513
|
+
*/
|
|
514
|
+
name: string
|
|
515
|
+
/** Course selector (must match a unique course in timeback.config.json) */
|
|
516
|
+
course: ActivityCourseRef
|
|
517
|
+
/**
|
|
518
|
+
* Run identifier for correlating heartbeats with the completion event.
|
|
519
|
+
*/
|
|
520
|
+
runId: string
|
|
521
|
+
/**
|
|
522
|
+
* ISO 8601 timestamp when this time window started.
|
|
523
|
+
*/
|
|
524
|
+
startedAt: string
|
|
525
|
+
/**
|
|
526
|
+
* ISO 8601 timestamp when this time window ended.
|
|
527
|
+
*/
|
|
528
|
+
endedAt: string
|
|
529
|
+
/**
|
|
530
|
+
* Active time in this window in milliseconds.
|
|
531
|
+
*/
|
|
532
|
+
elapsedMs: number
|
|
533
|
+
/**
|
|
534
|
+
* Paused time in this window in milliseconds.
|
|
535
|
+
*/
|
|
536
|
+
pausedMs: number
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Activity submit payload for completion events.
|
|
541
|
+
*
|
|
542
|
+
* Sent when the activity completes with metrics.
|
|
543
|
+
* The server builds an `ActivityCompletedEvent` from this data.
|
|
544
|
+
*/
|
|
545
|
+
export interface ActivitySubmitPayload {
|
|
546
|
+
/**
|
|
547
|
+
* Activity slug (stable identifier for the learning object).
|
|
548
|
+
*/
|
|
549
|
+
id: string
|
|
550
|
+
/**
|
|
551
|
+
* Human-readable display name of the activity.
|
|
552
|
+
*/
|
|
553
|
+
name: string
|
|
554
|
+
/** Course selector (must match a unique course in timeback.config.json) */
|
|
555
|
+
course: ActivityCourseRef
|
|
556
|
+
/**
|
|
557
|
+
* Run identifier for correlating with previous heartbeats.
|
|
558
|
+
*/
|
|
559
|
+
runId: string
|
|
560
|
+
/**
|
|
561
|
+
* ISO 8601 timestamp when the activity ended.
|
|
562
|
+
*/
|
|
563
|
+
endedAt: string
|
|
564
|
+
/** Activity metrics */
|
|
565
|
+
metrics: ActivityMetrics
|
|
566
|
+
/**
|
|
567
|
+
* App-reported course progress (per enrollment), as a percentage from 0–100.
|
|
568
|
+
*/
|
|
569
|
+
pctComplete?: number
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Activity submission response.
|
|
574
|
+
*/
|
|
575
|
+
export interface ActivityResponse {
|
|
576
|
+
success: boolean
|
|
577
|
+
error?: string
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Result of verifying a user's Timeback status.
|
|
582
|
+
*
|
|
583
|
+
* Used by partner apps to check if a user exists in Timeback before
|
|
584
|
+
* granting access to Timeback-gated features (e.g., free tier for Timeback users).
|
|
585
|
+
*/
|
|
586
|
+
export type TimebackVerifyResult =
|
|
587
|
+
| {
|
|
588
|
+
/** User exists in Timeback */
|
|
589
|
+
verified: true
|
|
590
|
+
/** Timeback user ID */
|
|
591
|
+
timebackId: string
|
|
592
|
+
}
|
|
593
|
+
| {
|
|
594
|
+
/** User does not exist in Timeback */
|
|
595
|
+
verified: false
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Verification state for the current user.
|
|
600
|
+
*
|
|
601
|
+
* Used by framework adapters (React, Vue, Svelte, Solid) to expose
|
|
602
|
+
* verification status as a state machine for UI consumption.
|
|
603
|
+
*/
|
|
604
|
+
export type TimebackVerificationState =
|
|
605
|
+
| { status: 'loading' }
|
|
606
|
+
| { status: 'verified'; timebackId: string }
|
|
607
|
+
| { status: 'unverified' }
|
|
608
|
+
| { status: 'error'; message: string }
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Profile state for the current user.
|
|
612
|
+
*
|
|
613
|
+
* Used by framework adapters (React, Vue, Svelte, Solid) to expose
|
|
614
|
+
* profile fetching status as a state machine for UI consumption.
|
|
615
|
+
*/
|
|
616
|
+
export type TimebackProfileState =
|
|
617
|
+
| { status: 'idle' }
|
|
618
|
+
| { status: 'loading' }
|
|
619
|
+
| { status: 'loaded'; profile: TimebackProfile }
|
|
620
|
+
| { status: 'error'; message: string }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timeback/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Timeback SDK for frontend and backend integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"zod": "^4.2.1"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
|
-
"@timeback/caliper": "0.1.
|
|
87
|
+
"@timeback/caliper": "0.1.4",
|
|
88
88
|
"@timeback/edubridge": "0.1.3",
|
|
89
89
|
"@timeback/internal-cli-infra": "0.0.0",
|
|
90
90
|
"@timeback/internal-client-infra": "0.0.0",
|
package/dist/chunk-5171mkp2.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{C as F}from"./chunk-hnf0tart.js";function M(j){let g=j.trim();if(g==="")return"/";let A=g.indexOf("?");if(A===-1)return g;let L=g.slice(0,A);if(L==="")return"/";return L}function X(j){let g=M(j);if(g!==""&&!g.startsWith("/"))g=`/${g}`;if(g==="/"||g==="")return"";if(g.endsWith("/"))return g.slice(0,-1);return g}function Z(j){let g=j.method.toUpperCase(),A=M(j.pathname),L=j.callbackPath?M(j.callbackPath):void 0;if(L&&A===L)return g==="GET"?"identity.callback":null;let N=j.basePath,Q=N!==void 0,J=Q?X(N):void 0,V=(G)=>{if(g==="GET"){if(G===F.IDENTITY.SIGNIN)return"identity.signIn";if(G===F.IDENTITY.CALLBACK)return"identity.callback";if(G===F.IDENTITY.SIGNOUT)return"identity.signOut";if(G===F.USER.ME)return"user.me";if(G===F.USER.VERIFY)return"user.verify"}if(g==="POST"){if(G===F.ACTIVITY)return"activity"}return null};if(Q&&J!==void 0){if(J!==""&&A===J)return null;if(J!==""&&!A.startsWith(`${J}/`))return null;let G=J===""?A:A.slice(J.length),W=G.startsWith("/")?G:`/${G}`;return V(W)}if(g==="GET"){if(A.endsWith(F.IDENTITY.SIGNIN))return"identity.signIn";if(A.endsWith(F.IDENTITY.CALLBACK))return"identity.callback";if(A.endsWith(F.IDENTITY.SIGNOUT))return"identity.signOut";if(A.endsWith(F.USER.ME))return"user.me";if(A.endsWith(F.USER.VERIFY))return"user.verify"}if(g==="POST"){if(A.endsWith(F.ACTIVITY))return"activity"}return null}function _(j){return"handle"in j?j.handle:j}function $(j){return"activity"in j}function C(j){return"user"in j}
|
|
2
|
-
export{M as x,Z as y,_ as z,$ as A,C as B};
|
package/dist/chunk-8gg8n8v9.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
class H{params;sendActivity;_startedAt;_isPaused=!1;_pausedAt;_totalPausedMs=0;_ended=!1;constructor(q,z){this.params=q;this.sendActivity=z;this._startedAt=new Date}get startedAt(){return this._startedAt}get isPaused(){return this._isPaused}get elapsedMs(){if(this._ended)return 0;let q=new Date,z=q.getTime()-this._startedAt.getTime()-this._totalPausedMs;if(this._isPaused&&this._pausedAt)z-=q.getTime()-this._pausedAt.getTime();return Math.max(0,z)}_buildPayload(q){let z=new Date,J,Y;if(q.time)J=Math.max(0,Math.round(q.time.active)),Y=Math.max(0,Math.round(q.time.inactive??0));else Y=this._totalPausedMs+(this._isPaused&&this._pausedAt?z.getTime()-this._pausedAt.getTime():0),J=Math.max(0,z.getTime()-this._startedAt.getTime()-Y);let N=q.totalQuestions!==void 0,j=q.correctQuestions!==void 0;if(N!==j)throw Error("Invalid activity metrics: totalQuestions and correctQuestions must be provided together.");if(N&&j&&q.correctQuestions>q.totalQuestions)throw Error("Invalid activity metrics: correctQuestions cannot exceed totalQuestions.");let F={...N?{totalQuestions:q.totalQuestions}:{},...j?{correctQuestions:q.correctQuestions}:{},...q.xpEarned===void 0?{}:{xpEarned:q.xpEarned},...q.masteredUnits===void 0?{}:{masteredUnits:q.masteredUnits}};return{id:this.params.id,name:this.params.name,course:this.params.course,startedAt:this._startedAt.toISOString(),endedAt:z.toISOString(),elapsedMs:J,pausedMs:Y,metrics:F,...q.pctComplete===void 0?{}:{pctComplete:q.pctComplete}}}pause(){if(this._isPaused||this._ended)return;this._isPaused=!0,this._pausedAt=new Date}resume(){if(!this._isPaused||this._ended||!this._pausedAt)return;this._totalPausedMs+=new Date().getTime()-this._pausedAt.getTime(),this._isPaused=!1,this._pausedAt=void 0}async end(q){if(this._ended)return;if(this._ended=!0,this._isPaused&&this._pausedAt)this._totalPausedMs+=new Date().getTime()-this._pausedAt.getTime(),this._isPaused=!1,this._pausedAt=void 0;let z=this._buildPayload(q);await this.sendActivity(z)}}var Z="/api/timeback",X={ACTIVITY:"/activity",IDENTITY:{SIGNIN:"/identity/signin",SIGNOUT:"/identity/signout",CALLBACK:"/identity/callback"},USER:{ME:"/user/me",VERIFY:"/user/verify"}};var D=3,O=[100,300,1000];function _(){if(!(typeof globalThis>"u"?void 0:globalThis.fetch))return;return(z,J)=>globalThis.fetch(z,J)}function $(){return typeof window<"u"}function K(){if(!$())return;return`${window.location.origin}${Z}`}function B(q){return new Promise((z)=>{setTimeout(z,q)})}function C(q,z){if(typeof q==="number")return q;return q[Math.min(z,q.length-1)]??1000}class G{sendActivity;constructor(q){this.sendActivity=q}start(q){return new H(q,this.sendActivity)}}class Q{getBaseURL;constructor(q){this.getBaseURL=q}signIn(){if(!$())throw Error("signIn() requires a browser environment");window.location.href=`${this.getBaseURL()}${X.IDENTITY.SIGNIN}`}}class V{getBaseURL;fetchImpl;constructor(q,z){this.getBaseURL=q;this.fetchImpl=z}async fetch(){if(!$())throw Error("user.fetch() requires a browser environment");let q=await this.fetchImpl(`${this.getBaseURL()}${X.USER.ME}`,{method:"GET",credentials:"include"});if(!q.ok){let z=await q.json().catch(()=>({error:"Unknown error"}));throw Error(z.error??"Failed to fetch user profile")}return q.json()}async verify(){if(!$())throw Error("user.verify() requires a browser environment");let q=await this.fetchImpl(`${this.getBaseURL()}${X.USER.VERIFY}`,{method:"GET",credentials:"include"});if(!q.ok){let J=await q.json().catch(()=>({error:"Unknown error"}));throw Error(J.error??"Failed to verify Timeback user")}let z=await q.json();if(z.verified&&z.timebackId)return{verified:!0,timebackId:z.timebackId};return{verified:!1}}}class W{activity;auth;user;_baseURL;_fetch;constructor(q={}){this._baseURL=q.baseURL;let z=q.fetch??_();if(!z)throw Error("TimebackClient requires a fetch implementation. Provide `fetch` in the constructor config for non-browser runtimes.");let J=q.plugins,Y=Array.isArray(J)?J:J?[J]:[];this._fetch=Y.reduce((N,j)=>j.wrapFetch(N),z),this.activity=new G((N)=>this.sendActivity(N)),this.auth=new Q(()=>this.baseURL),this.user=new V(()=>this.baseURL,this._fetch)}get baseURL(){if(!this._baseURL){let q=K();if(!q)throw Error("Timeback client requires a browser environment for default baseURL. Provide an explicit baseURL for server-side usage.");this._baseURL=q}return this._baseURL}async sendActivity(q){let z=await this._fetch(`${this.baseURL}${X.ACTIVITY}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(q),credentials:"include"});if(!z.ok){let J=await z.json().catch(()=>({error:"Unknown error"}));throw Error(J.error??"Failed to send activity")}}}function n(q={}){let z=q.baseURL??K();return new W({baseURL:z,fetch:q.fetch,plugins:q.plugins})}
|
|
2
|
-
export{D as a,O as b,B as c,C as d,H as e,W as f,n as g};
|
package/dist/chunk-hnf0tart.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{createHash as B}from"node:crypto";function F(q){return{course:q,component:`${q}-component`,resource:`${q}-resource`,componentResource:`${q}-cr`}}function G(q){return B("sha256").update(q).digest("hex")}function J(q){if(q==="local"||q==="staging")return"staging";return"production"}function K(q){if(q==="production"||q==="local"||q==="staging")return q;return"staging"}function L(q,w=200,z){let A=new Headers(z);return A.set("Content-Type","application/json"),new Response(JSON.stringify(q),{status:w,headers:A})}function M(q,w){let z=new Headers(w);return z.set("Location",q),new Response(null,{status:302,headers:z})}function N(q){let w=JSON.stringify(q);return btoa(w).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function O(q){let w=q.replace(/-/g,"+").replace(/_/g,"/"),z=atob(w);return JSON.parse(z)}var Q={ACTIVITY:"/activity",IDENTITY:{SIGNIN:"/identity/signin",SIGNOUT:"/identity/signout",CALLBACK:"/identity/callback"},USER:{ME:"/user/me",VERIFY:"/user/verify"}},S=0.999999;
|
|
2
|
-
export{Q as C,S as D,F as E,G as F,J as G,K as H,L as I,M as J,N as K,O as L};
|