@timeback/sdk 0.1.7 → 0.1.9
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 +97 -8
- package/dist/chunk-07j8zre9.js +2 -0
- package/dist/chunk-5171mkp2.js +2 -0
- package/dist/chunk-63afdp3y.js +8 -0
- package/dist/chunk-8gg8n8v9.js +2 -0
- package/dist/chunk-9se82640.js +1 -0
- package/dist/chunk-agpf1x3g.js +16 -0
- package/dist/chunk-hnf0tart.js +2 -0
- package/dist/chunk-qr0bbnsr.js +1 -0
- package/dist/chunk-whc53e0y.js +11 -0
- package/dist/chunk-x9gvef7q.js +1 -0
- package/dist/client/adapters/react/hooks/types.d.ts +80 -0
- package/dist/client/adapters/react/hooks/types.d.ts.map +1 -1
- package/dist/client/adapters/react/hooks/useTimebackProfile.d.ts +42 -0
- package/dist/client/adapters/react/hooks/useTimebackProfile.d.ts.map +1 -0
- package/dist/client/adapters/react/hooks/useTimebackVerification.d.ts +17 -5
- package/dist/client/adapters/react/hooks/useTimebackVerification.d.ts.map +1 -1
- package/dist/client/adapters/react/index.d.ts +2 -1
- package/dist/client/adapters/react/index.d.ts.map +1 -1
- package/dist/client/adapters/react/index.js +2 -494
- package/dist/client/adapters/react/provider.d.ts.map +1 -1
- package/dist/client/adapters/solid/index.d.ts +3 -0
- package/dist/client/adapters/solid/index.d.ts.map +1 -1
- package/dist/client/adapters/solid/index.ts +12 -0
- package/dist/client/adapters/solid/primitives/createTimebackProfile.d.ts +58 -0
- package/dist/client/adapters/solid/primitives/createTimebackProfile.d.ts.map +1 -0
- package/dist/client/adapters/solid/primitives/createTimebackProfile.ts +209 -0
- package/dist/client/adapters/solid/primitives/createTimebackVerification.d.ts +38 -0
- package/dist/client/adapters/solid/primitives/createTimebackVerification.d.ts.map +1 -0
- package/dist/client/adapters/solid/primitives/createTimebackVerification.ts +173 -0
- package/dist/client/adapters/solid/types.d.ts +109 -0
- package/dist/client/adapters/solid/types.d.ts.map +1 -0
- package/dist/client/adapters/solid/types.ts +110 -0
- package/dist/client/adapters/svelte/index.d.ts +2 -1
- package/dist/client/adapters/svelte/index.d.ts.map +1 -1
- package/dist/client/adapters/svelte/index.ts +11 -2
- package/dist/client/adapters/svelte/{stores.d.ts → stores/client.d.ts} +11 -9
- package/dist/client/adapters/svelte/stores/client.d.ts.map +1 -0
- package/dist/client/adapters/svelte/{stores.ts → stores/client.ts} +24 -52
- package/dist/client/adapters/svelte/stores/index.d.ts +10 -0
- package/dist/client/adapters/svelte/stores/index.d.ts.map +1 -0
- package/dist/client/adapters/svelte/stores/index.ts +22 -0
- package/dist/client/adapters/svelte/stores/profile.d.ts +66 -0
- package/dist/client/adapters/svelte/stores/profile.d.ts.map +1 -0
- package/dist/client/adapters/svelte/stores/profile.ts +168 -0
- package/dist/client/adapters/svelte/stores/verification.d.ts +43 -0
- package/dist/client/adapters/svelte/stores/verification.d.ts.map +1 -0
- package/dist/client/adapters/svelte/stores/verification.ts +208 -0
- package/dist/client/adapters/svelte/types.d.ts +35 -0
- package/dist/client/adapters/svelte/types.d.ts.map +1 -0
- package/dist/client/adapters/vue/composables/useTimebackProfile.d.ts +51 -0
- package/dist/client/adapters/vue/composables/useTimebackProfile.d.ts.map +1 -0
- package/dist/client/adapters/vue/composables/useTimebackProfile.ts +186 -0
- package/dist/client/adapters/vue/composables/useTimebackVerification.d.ts +46 -0
- package/dist/client/adapters/vue/composables/useTimebackVerification.d.ts.map +1 -0
- package/dist/client/adapters/vue/composables/useTimebackVerification.ts +169 -0
- package/dist/client/adapters/vue/index.d.ts +3 -0
- package/dist/client/adapters/vue/index.d.ts.map +1 -1
- package/dist/client/adapters/vue/index.ts +12 -1
- package/dist/client/adapters/vue/types.d.ts +109 -0
- package/dist/client/adapters/vue/types.d.ts.map +1 -0
- package/dist/client/adapters/vue/types.ts +110 -0
- package/dist/client/lib/activity/activity.class.d.ts +5 -5
- package/dist/client/lib/activity/activity.class.d.ts.map +1 -1
- package/dist/client/lib/user-cache.d.ts +39 -0
- package/dist/client/lib/user-cache.d.ts.map +1 -0
- package/dist/client/lib/user-cache.ts +168 -0
- package/dist/client/lib/utils.d.ts +15 -0
- package/dist/client/lib/utils.d.ts.map +1 -1
- package/dist/client/namespaces/activity.d.ts +2 -3
- package/dist/client/namespaces/activity.d.ts.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -257
- package/dist/edge.js +1 -86271
- package/dist/identity.js +1 -86131
- package/dist/index.d.ts +2 -2
- package/dist/index.js +22 -104883
- package/dist/server/adapters/express.js +1 -85973
- package/dist/server/adapters/native.js +2 -221
- package/dist/server/adapters/nextjs.js +1 -233
- package/dist/server/adapters/nuxt.js +1 -86046
- package/dist/server/adapters/solid-start.js +1 -85945
- package/dist/server/adapters/svelte-kit.js +1 -279
- package/dist/server/adapters/tanstack-start.js +1 -85918
- package/dist/server/handlers/activity/attempts.d.ts +51 -0
- package/dist/server/handlers/activity/attempts.d.ts.map +1 -0
- package/dist/server/handlers/activity/caliper.d.ts +46 -5
- package/dist/server/handlers/activity/caliper.d.ts.map +1 -1
- package/dist/server/handlers/activity/completion.d.ts +43 -0
- package/dist/server/handlers/activity/completion.d.ts.map +1 -0
- package/dist/server/handlers/activity/handler.d.ts +18 -1
- package/dist/server/handlers/activity/handler.d.ts.map +1 -1
- package/dist/server/handlers/activity/progress.d.ts +47 -0
- package/dist/server/handlers/activity/progress.d.ts.map +1 -0
- package/dist/server/handlers/activity/schema.d.ts +1 -2
- package/dist/server/handlers/activity/schema.d.ts.map +1 -1
- package/dist/server/handlers/activity/types.d.ts +1 -2
- package/dist/server/handlers/activity/types.d.ts.map +1 -1
- package/dist/server/lib/index.d.ts +1 -1
- package/dist/server/lib/index.d.ts.map +1 -1
- package/dist/server/lib/utils.d.ts +61 -0
- package/dist/server/lib/utils.d.ts.map +1 -1
- package/dist/server/timeback.d.ts +2 -2
- package/dist/server/timeback.d.ts.map +1 -1
- package/dist/server/types.d.ts +7 -1
- package/dist/server/types.d.ts.map +1 -1
- package/dist/shared/constants.d.ts +19 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/types.d.ts +62 -8
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/xp-calculator.d.ts +25 -0
- package/dist/shared/xp-calculator.d.ts.map +1 -0
- package/package.json +6 -4
- package/dist/client/adapters/svelte/stores.d.ts.map +0 -1
- package/dist/server/handlers/activity/gradebook.d.ts +0 -56
- package/dist/server/handlers/activity/gradebook.d.ts.map +0 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue Types
|
|
3
|
+
*
|
|
4
|
+
* Types for Vue-specific composables.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { TimebackProfile } from '../../../shared/types'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Verification state for the current user.
|
|
11
|
+
*/
|
|
12
|
+
export type TimebackVerificationState =
|
|
13
|
+
| { status: 'loading' }
|
|
14
|
+
| { status: 'verified'; timebackId: string }
|
|
15
|
+
| { status: 'unverified' }
|
|
16
|
+
| { status: 'error'; message: string }
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Profile state for the current user.
|
|
20
|
+
*/
|
|
21
|
+
export type TimebackProfileState =
|
|
22
|
+
| { status: 'idle' }
|
|
23
|
+
| { status: 'loading' }
|
|
24
|
+
| { status: 'loaded'; profile: TimebackProfile }
|
|
25
|
+
| { status: 'error'; message: string }
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Options for the useTimebackVerification composable.
|
|
29
|
+
*/
|
|
30
|
+
export interface UseTimebackVerificationOptions {
|
|
31
|
+
/**
|
|
32
|
+
* If false, the composable does nothing and stays in loading state.
|
|
33
|
+
*
|
|
34
|
+
* Use this to delay verification until prerequisites are met
|
|
35
|
+
* (e.g., user exists in your database).
|
|
36
|
+
*
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
enabled?: boolean
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Number of retry attempts on failure.
|
|
43
|
+
*
|
|
44
|
+
* This helps handle race conditions where the user may not be
|
|
45
|
+
* fully set up in the backend when verification first runs.
|
|
46
|
+
*
|
|
47
|
+
* Set to 0 to disable retries.
|
|
48
|
+
*
|
|
49
|
+
* @default 3
|
|
50
|
+
*/
|
|
51
|
+
retryAttempts?: number
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Delay in ms before each retry attempt.
|
|
55
|
+
*
|
|
56
|
+
* Can be a single number (same delay for all retries) or an array
|
|
57
|
+
* of delays for each attempt (e.g., [100, 300, 1000] for exponential backoff).
|
|
58
|
+
*
|
|
59
|
+
* @default [100, 300, 1000]
|
|
60
|
+
*/
|
|
61
|
+
retryDelays?: number | readonly number[]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Return value of the useTimebackVerification composable.
|
|
66
|
+
*/
|
|
67
|
+
export interface UseTimebackVerificationResult {
|
|
68
|
+
/** Current verification state (reactive ref) */
|
|
69
|
+
state: TimebackVerificationState
|
|
70
|
+
|
|
71
|
+
/** Force a re-verification. No-op if not enabled. */
|
|
72
|
+
refresh: () => void
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Options for the useTimebackProfile composable.
|
|
77
|
+
*/
|
|
78
|
+
export interface UseTimebackProfileOptions {
|
|
79
|
+
/**
|
|
80
|
+
* If false, the composable does nothing and stays in idle state.
|
|
81
|
+
*
|
|
82
|
+
* @default true
|
|
83
|
+
*/
|
|
84
|
+
enabled?: boolean
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* If true, automatically fetch the profile once the user is verified.
|
|
88
|
+
* If false, you must call `fetchProfile()` manually.
|
|
89
|
+
*
|
|
90
|
+
* @default false
|
|
91
|
+
*/
|
|
92
|
+
auto?: boolean
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Return value of the useTimebackProfile composable.
|
|
97
|
+
*/
|
|
98
|
+
export interface UseTimebackProfileResult {
|
|
99
|
+
/** Current profile state (reactive ref) */
|
|
100
|
+
state: TimebackProfileState
|
|
101
|
+
|
|
102
|
+
/** Whether the profile can be fetched (user is verified and client is ready) */
|
|
103
|
+
canFetch: boolean
|
|
104
|
+
|
|
105
|
+
/** Manually trigger a profile fetch. No-op if canFetch is false. */
|
|
106
|
+
fetchProfile: () => void
|
|
107
|
+
|
|
108
|
+
/** Force a re-fetch even if already loaded. No-op if canFetch is false. */
|
|
109
|
+
refresh: () => void
|
|
110
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Client-side activity tracking logic.
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { ActivityEndData, ActivityEndPayload, ActivityParams } from '../../../shared/types';
|
|
7
7
|
/**
|
|
8
8
|
* Activity tracker that tracks time spent on an activity.
|
|
9
9
|
*
|
|
@@ -51,10 +51,10 @@ export declare class Activity {
|
|
|
51
51
|
* Useful for "preview" flows in examples where you want to inspect the payload
|
|
52
52
|
* that would be POSTed to the server without calling `end()`.
|
|
53
53
|
*
|
|
54
|
-
* @param data - Activity completion data (metrics + optional
|
|
54
|
+
* @param data - Activity completion data (metrics + optional time override)
|
|
55
55
|
* @returns Activity end payload
|
|
56
56
|
*/
|
|
57
|
-
_buildPayload(data:
|
|
57
|
+
_buildPayload(data: ActivityEndData): ActivityEndPayload;
|
|
58
58
|
/**
|
|
59
59
|
* Pause the activity timer.
|
|
60
60
|
*/
|
|
@@ -66,8 +66,8 @@ export declare class Activity {
|
|
|
66
66
|
/**
|
|
67
67
|
* End the activity and send to server.
|
|
68
68
|
*
|
|
69
|
-
* @param data - Activity completion data (metrics + optional
|
|
69
|
+
* @param data - Activity completion data (metrics + optional time override)
|
|
70
70
|
*/
|
|
71
|
-
end(data:
|
|
71
|
+
end(data: ActivityEndData): Promise<void>;
|
|
72
72
|
}
|
|
73
73
|
//# sourceMappingURL=activity.class.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity.class.d.ts","sourceRoot":"","sources":["../../../../src/client/lib/activity/activity.class.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"activity.class.d.ts","sourceRoot":"","sources":["../../../../src/client/lib/activity/activity.class.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEhG;;;;;GAKG;AACH,qBAAa,QAAQ;IAgBnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAhB9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAM;IACjC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,MAAM,CAAQ;IAEtB;;;;;;;OAOG;IACH,YACkB,MAAM,EAAE,cAAc,EACtB,YAAY,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,EAG7E;IAED;;;;OAIG;IACH,IAAI,SAAS,IAAI,IAAI,CAEpB;IAED;;;;OAIG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;;OAIG;IACH,IAAI,SAAS,IAAI,MAAM,CAatB;IAED;;;;;;;;OAQG;IACH,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,kBAAkB,CAiDvD;IAED;;OAEG;IACH,KAAK,IAAI,IAAI,CAIZ;IAED;;OAEG;IACH,MAAM,IAAI,IAAI,CAKb;IAED;;;;OAIG;IACG,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9C;CACD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared User Cache
|
|
3
|
+
*
|
|
4
|
+
* Internal module for in-flight deduplication and short-lived caching of
|
|
5
|
+
* verify and profile requests. Used by Solid, Svelte, and Vue adapters.
|
|
6
|
+
*/
|
|
7
|
+
import type { TimebackProfile, TimebackVerifyResult } from '../../shared/types';
|
|
8
|
+
import type { TimebackClient } from '../timeback-client.class';
|
|
9
|
+
/**
|
|
10
|
+
* Verify the current user with in-flight dedupe and short-lived caching.
|
|
11
|
+
*
|
|
12
|
+
* @param timeback - Timeback client instance
|
|
13
|
+
* @param force - If true, bypass cache and in-flight reuse
|
|
14
|
+
* @returns Verify result
|
|
15
|
+
*/
|
|
16
|
+
export declare function verifyOnce(timeback: TimebackClient, force: boolean): Promise<TimebackVerifyResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Get cached verification result if fresh.
|
|
19
|
+
*
|
|
20
|
+
* @param timeback - Timeback client instance
|
|
21
|
+
* @returns Cached result or undefined
|
|
22
|
+
*/
|
|
23
|
+
export declare function getVerifyCache(timeback: TimebackClient): TimebackVerifyResult | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Fetch the profile with in-flight dedupe and short-lived caching.
|
|
26
|
+
*
|
|
27
|
+
* @param timeback - Timeback client instance
|
|
28
|
+
* @param force - If true, bypass cache and in-flight reuse
|
|
29
|
+
* @returns The user's Timeback profile
|
|
30
|
+
*/
|
|
31
|
+
export declare function fetchProfileOnce(timeback: TimebackClient, force: boolean): Promise<TimebackProfile>;
|
|
32
|
+
/**
|
|
33
|
+
* Get cached profile result if fresh.
|
|
34
|
+
*
|
|
35
|
+
* @param timeback - Timeback client instance
|
|
36
|
+
* @returns Cached profile or undefined
|
|
37
|
+
*/
|
|
38
|
+
export declare function getProfileCache(timeback: TimebackClient): TimebackProfile | undefined;
|
|
39
|
+
//# sourceMappingURL=user-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-cache.d.ts","sourceRoot":"","sources":["../../../src/client/lib/user-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAkC9D;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC/B,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,OAAO,GACZ,OAAO,CAAC,oBAAoB,CAAC,CAyC/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,GAAG,oBAAoB,GAAG,SAAS,CAGzF;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACrC,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,OAAO,GACZ,OAAO,CAAC,eAAe,CAAC,CAwC1B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,eAAe,GAAG,SAAS,CAGrF"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared User Cache
|
|
3
|
+
*
|
|
4
|
+
* Internal module for in-flight deduplication and short-lived caching of
|
|
5
|
+
* verify and profile requests. Used by Solid, Svelte, and Vue adapters.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { TimebackProfile, TimebackVerifyResult } from '../../shared/types'
|
|
9
|
+
import type { TimebackClient } from '../timeback-client.class'
|
|
10
|
+
|
|
11
|
+
const VERIFY_CACHE_TTL_MS = 1500
|
|
12
|
+
const PROFILE_CACHE_TTL_MS = 5000
|
|
13
|
+
|
|
14
|
+
type VerifyCacheEntry = { atMs: number; result: TimebackVerifyResult }
|
|
15
|
+
type ProfileCacheEntry = { atMs: number; profile: TimebackProfile }
|
|
16
|
+
|
|
17
|
+
const verifyInFlight = new WeakMap<TimebackClient, Promise<TimebackVerifyResult>>()
|
|
18
|
+
const verifyCache = new WeakMap<TimebackClient, VerifyCacheEntry>()
|
|
19
|
+
|
|
20
|
+
const profileInFlight = new WeakMap<TimebackClient, Promise<TimebackProfile>>()
|
|
21
|
+
const profileCache = new WeakMap<TimebackClient, ProfileCacheEntry>()
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Check whether a cached verification result is still fresh.
|
|
25
|
+
*
|
|
26
|
+
* @param entry - Cached entry (if any)
|
|
27
|
+
* @returns True if the cache entry exists and is within TTL
|
|
28
|
+
*/
|
|
29
|
+
function isVerifyCacheFresh(entry: VerifyCacheEntry | undefined): entry is VerifyCacheEntry {
|
|
30
|
+
return !!entry && Date.now() - entry.atMs < VERIFY_CACHE_TTL_MS
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Check whether a cached profile result is still fresh.
|
|
35
|
+
*
|
|
36
|
+
* @param entry - Cached entry (if any)
|
|
37
|
+
* @returns True if the cache entry exists and is within TTL
|
|
38
|
+
*/
|
|
39
|
+
function isProfileCacheFresh(entry: ProfileCacheEntry | undefined): entry is ProfileCacheEntry {
|
|
40
|
+
return !!entry && Date.now() - entry.atMs < PROFILE_CACHE_TTL_MS
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Verify the current user with in-flight dedupe and short-lived caching.
|
|
45
|
+
*
|
|
46
|
+
* @param timeback - Timeback client instance
|
|
47
|
+
* @param force - If true, bypass cache and in-flight reuse
|
|
48
|
+
* @returns Verify result
|
|
49
|
+
*/
|
|
50
|
+
export async function verifyOnce(
|
|
51
|
+
timeback: TimebackClient,
|
|
52
|
+
force: boolean,
|
|
53
|
+
): Promise<TimebackVerifyResult> {
|
|
54
|
+
if (!force) {
|
|
55
|
+
const cached = verifyCache.get(timeback)
|
|
56
|
+
|
|
57
|
+
if (isVerifyCacheFresh(cached)) {
|
|
58
|
+
return cached.result
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const existing = verifyInFlight.get(timeback)
|
|
62
|
+
|
|
63
|
+
if (existing) {
|
|
64
|
+
return await existing
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const p = timeback.user.verify().then(result => {
|
|
69
|
+
/**
|
|
70
|
+
* Guard against stale overwrites:
|
|
71
|
+
*
|
|
72
|
+
* If `force=true` triggers a newer request while an older one is still
|
|
73
|
+
* in-flight, the older promise may resolve later. Only let the most
|
|
74
|
+
* recent in-flight promise update the cache.
|
|
75
|
+
*/
|
|
76
|
+
if (verifyInFlight.get(timeback) === p) {
|
|
77
|
+
verifyCache.set(timeback, { atMs: Date.now(), result })
|
|
78
|
+
}
|
|
79
|
+
return result
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
verifyInFlight.set(timeback, p)
|
|
83
|
+
try {
|
|
84
|
+
return await p
|
|
85
|
+
} finally {
|
|
86
|
+
/**
|
|
87
|
+
* Only remove the in-flight verification promise
|
|
88
|
+
* if it is still the most recent for this client instance.
|
|
89
|
+
*/
|
|
90
|
+
if (verifyInFlight.get(timeback) === p) {
|
|
91
|
+
verifyInFlight.delete(timeback)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get cached verification result if fresh.
|
|
98
|
+
*
|
|
99
|
+
* @param timeback - Timeback client instance
|
|
100
|
+
* @returns Cached result or undefined
|
|
101
|
+
*/
|
|
102
|
+
export function getVerifyCache(timeback: TimebackClient): TimebackVerifyResult | undefined {
|
|
103
|
+
const cached = verifyCache.get(timeback)
|
|
104
|
+
return isVerifyCacheFresh(cached) ? cached.result : undefined
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Fetch the profile with in-flight dedupe and short-lived caching.
|
|
109
|
+
*
|
|
110
|
+
* @param timeback - Timeback client instance
|
|
111
|
+
* @param force - If true, bypass cache and in-flight reuse
|
|
112
|
+
* @returns The user's Timeback profile
|
|
113
|
+
*/
|
|
114
|
+
export async function fetchProfileOnce(
|
|
115
|
+
timeback: TimebackClient,
|
|
116
|
+
force: boolean,
|
|
117
|
+
): Promise<TimebackProfile> {
|
|
118
|
+
if (!force) {
|
|
119
|
+
const cached = profileCache.get(timeback)
|
|
120
|
+
|
|
121
|
+
if (isProfileCacheFresh(cached)) {
|
|
122
|
+
return cached.profile
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const existing = profileInFlight.get(timeback)
|
|
126
|
+
|
|
127
|
+
if (existing) {
|
|
128
|
+
return await existing
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const p = timeback.user.fetch().then(profile => {
|
|
133
|
+
/**
|
|
134
|
+
* Guard against stale overwrites:
|
|
135
|
+
*
|
|
136
|
+
* If `force=true` triggers a newer request while an older one is still
|
|
137
|
+
* in-flight, the older promise may resolve later. Only let the most
|
|
138
|
+
* recent in-flight promise update the cache.
|
|
139
|
+
*/
|
|
140
|
+
if (profileInFlight.get(timeback) === p) {
|
|
141
|
+
profileCache.set(timeback, { atMs: Date.now(), profile })
|
|
142
|
+
}
|
|
143
|
+
return profile
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
profileInFlight.set(timeback, p)
|
|
147
|
+
try {
|
|
148
|
+
return await p
|
|
149
|
+
} finally {
|
|
150
|
+
/**
|
|
151
|
+
* Only remove the in-flight promise if it is still the most recent
|
|
152
|
+
*/
|
|
153
|
+
if (profileInFlight.get(timeback) === p) {
|
|
154
|
+
profileInFlight.delete(timeback)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get cached profile result if fresh.
|
|
161
|
+
*
|
|
162
|
+
* @param timeback - Timeback client instance
|
|
163
|
+
* @returns Cached profile or undefined
|
|
164
|
+
*/
|
|
165
|
+
export function getProfileCache(timeback: TimebackClient): TimebackProfile | undefined {
|
|
166
|
+
const cached = profileCache.get(timeback)
|
|
167
|
+
return isProfileCacheFresh(cached) ? cached.profile : undefined
|
|
168
|
+
}
|
|
@@ -17,4 +17,19 @@ export declare function isBrowser(): boolean;
|
|
|
17
17
|
* @returns The default base URL or undefined during SSR
|
|
18
18
|
*/
|
|
19
19
|
export declare function getDefaultBaseURL(): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Sleep for a given number of milliseconds.
|
|
22
|
+
*
|
|
23
|
+
* @param ms - Duration to sleep in milliseconds
|
|
24
|
+
* @returns Promise that resolves after the delay
|
|
25
|
+
*/
|
|
26
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Get retry delay for a given attempt from a delay configuration.
|
|
29
|
+
*
|
|
30
|
+
* @param delays - Single delay or array of delays per attempt
|
|
31
|
+
* @param attempt - Zero-based attempt index
|
|
32
|
+
* @returns Delay in milliseconds
|
|
33
|
+
*/
|
|
34
|
+
export declare function getRetryDelay(delays: number | readonly number[], attempt: number): number;
|
|
20
35
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/client/lib/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAMtD"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/client/lib/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAMtD;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAMzF"}
|
|
@@ -25,7 +25,7 @@ export declare class ActivityManager {
|
|
|
25
25
|
* @param params - Activity parameters
|
|
26
26
|
* @returns Started activity instance
|
|
27
27
|
*
|
|
28
|
-
* @example
|
|
28
|
+
* @example Basic usage
|
|
29
29
|
* ```typescript
|
|
30
30
|
* const activity = timeback.activity.start({
|
|
31
31
|
* id: 'lesson-1',
|
|
@@ -36,8 +36,7 @@ export declare class ActivityManager {
|
|
|
36
36
|
* await activity.end({
|
|
37
37
|
* totalQuestions: 10,
|
|
38
38
|
* correctQuestions: 8,
|
|
39
|
-
*
|
|
40
|
-
* pctCompleteApp: 67,
|
|
39
|
+
* pctComplete: 67,
|
|
41
40
|
* })
|
|
42
41
|
* ```
|
|
43
42
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../src/client/namespaces/activity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAE5E;;GAEG;AACH,qBAAa,eAAe;IAMf,OAAO,CAAC,QAAQ,CAAC,YAAY;IALzC;;;;OAIG;IACH,YAA6B,YAAY,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,EAAI;IAE7F
|
|
1
|
+
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../src/client/namespaces/activity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAE5E;;GAEG;AACH,qBAAa,eAAe;IAMf,OAAO,CAAC,QAAQ,CAAC,YAAY;IALzC;;;;OAIG;IACH,YAA6B,YAAY,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,EAAI;IAE7F;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CAEtC;CACD"}
|
package/dist/client.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* activity.resume()
|
|
22
22
|
*
|
|
23
23
|
* // End tracking with metrics
|
|
24
|
-
* await activity.end({ totalQuestions: 10, correctQuestions: 8
|
|
24
|
+
* await activity.end({ totalQuestions: 10, correctQuestions: 8 })
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
export { createClient, TimebackClient } from './client/index';
|
package/dist/client.js
CHANGED
|
@@ -1,257 +1 @@
|
|
|
1
|
-
|
|
2
|
-
var DEFAULT_BASE_PATH = "/api/timeback";
|
|
3
|
-
var ROUTES = {
|
|
4
|
-
ACTIVITY: "/activity",
|
|
5
|
-
IDENTITY: {
|
|
6
|
-
SIGNIN: "/identity/signin",
|
|
7
|
-
SIGNOUT: "/identity/signout",
|
|
8
|
-
CALLBACK: "/identity/callback"
|
|
9
|
-
},
|
|
10
|
-
USER: {
|
|
11
|
-
ME: "/user/me",
|
|
12
|
-
VERIFY: "/user/verify"
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// src/client/lib/utils.ts
|
|
17
|
-
function isBrowser() {
|
|
18
|
-
return typeof window !== "undefined";
|
|
19
|
-
}
|
|
20
|
-
function getDefaultBaseURL() {
|
|
21
|
-
if (!isBrowser()) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
return `${window.location.origin}${DEFAULT_BASE_PATH}`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// src/client/lib/fetch.ts
|
|
28
|
-
function getDefaultFetch() {
|
|
29
|
-
const globalFetch = typeof globalThis === "undefined" ? undefined : globalThis.fetch;
|
|
30
|
-
if (!globalFetch) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
return (input, init) => globalThis.fetch(input, init);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/client/lib/activity/activity.class.ts
|
|
37
|
-
class Activity {
|
|
38
|
-
params;
|
|
39
|
-
sendActivity;
|
|
40
|
-
_startedAt;
|
|
41
|
-
_isPaused = false;
|
|
42
|
-
_pausedAt;
|
|
43
|
-
_totalPausedMs = 0;
|
|
44
|
-
_ended = false;
|
|
45
|
-
constructor(params, sendActivity) {
|
|
46
|
-
this.params = params;
|
|
47
|
-
this.sendActivity = sendActivity;
|
|
48
|
-
this._startedAt = new Date;
|
|
49
|
-
}
|
|
50
|
-
get startedAt() {
|
|
51
|
-
return this._startedAt;
|
|
52
|
-
}
|
|
53
|
-
get isPaused() {
|
|
54
|
-
return this._isPaused;
|
|
55
|
-
}
|
|
56
|
-
get elapsedMs() {
|
|
57
|
-
if (this._ended) {
|
|
58
|
-
return 0;
|
|
59
|
-
}
|
|
60
|
-
const now = new Date;
|
|
61
|
-
let elapsed = now.getTime() - this._startedAt.getTime() - this._totalPausedMs;
|
|
62
|
-
if (this._isPaused && this._pausedAt) {
|
|
63
|
-
elapsed -= now.getTime() - this._pausedAt.getTime();
|
|
64
|
-
}
|
|
65
|
-
return Math.max(0, elapsed);
|
|
66
|
-
}
|
|
67
|
-
_buildPayload(data) {
|
|
68
|
-
const now = new Date;
|
|
69
|
-
const pausedMs = this._totalPausedMs + (this._isPaused && this._pausedAt ? now.getTime() - this._pausedAt.getTime() : 0);
|
|
70
|
-
const elapsedMs = now.getTime() - this._startedAt.getTime() - pausedMs;
|
|
71
|
-
return {
|
|
72
|
-
id: this.params.id,
|
|
73
|
-
name: this.params.name,
|
|
74
|
-
course: this.params.course,
|
|
75
|
-
startedAt: this._startedAt.toISOString(),
|
|
76
|
-
endedAt: now.toISOString(),
|
|
77
|
-
elapsedMs: Math.max(0, elapsedMs),
|
|
78
|
-
pausedMs,
|
|
79
|
-
metrics: {
|
|
80
|
-
totalQuestions: data.totalQuestions,
|
|
81
|
-
correctQuestions: data.correctQuestions,
|
|
82
|
-
...data.xpEarned === undefined ? {} : { xpEarned: data.xpEarned },
|
|
83
|
-
...data.masteredUnits === undefined ? {} : { masteredUnits: data.masteredUnits }
|
|
84
|
-
},
|
|
85
|
-
...data.attemptNumber === undefined ? {} : { attemptNumber: data.attemptNumber },
|
|
86
|
-
...data.pctCompleteApp === undefined ? {} : { pctCompleteApp: data.pctCompleteApp }
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
pause() {
|
|
90
|
-
if (this._isPaused || this._ended)
|
|
91
|
-
return;
|
|
92
|
-
this._isPaused = true;
|
|
93
|
-
this._pausedAt = new Date;
|
|
94
|
-
}
|
|
95
|
-
resume() {
|
|
96
|
-
if (!this._isPaused || this._ended || !this._pausedAt)
|
|
97
|
-
return;
|
|
98
|
-
this._totalPausedMs += new Date().getTime() - this._pausedAt.getTime();
|
|
99
|
-
this._isPaused = false;
|
|
100
|
-
this._pausedAt = undefined;
|
|
101
|
-
}
|
|
102
|
-
async end(data) {
|
|
103
|
-
if (this._ended)
|
|
104
|
-
return;
|
|
105
|
-
this._ended = true;
|
|
106
|
-
if (this._isPaused && this._pausedAt) {
|
|
107
|
-
this._totalPausedMs += new Date().getTime() - this._pausedAt.getTime();
|
|
108
|
-
this._isPaused = false;
|
|
109
|
-
this._pausedAt = undefined;
|
|
110
|
-
}
|
|
111
|
-
const payload = this._buildPayload(data);
|
|
112
|
-
await this.sendActivity(payload);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// src/client/namespaces/activity.ts
|
|
116
|
-
class ActivityManager {
|
|
117
|
-
sendActivity;
|
|
118
|
-
constructor(sendActivity) {
|
|
119
|
-
this.sendActivity = sendActivity;
|
|
120
|
-
}
|
|
121
|
-
start(params) {
|
|
122
|
-
return new Activity(params, this.sendActivity);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// src/client/namespaces/auth.ts
|
|
126
|
-
class Auth {
|
|
127
|
-
getBaseURL;
|
|
128
|
-
constructor(getBaseURL) {
|
|
129
|
-
this.getBaseURL = getBaseURL;
|
|
130
|
-
}
|
|
131
|
-
signIn() {
|
|
132
|
-
if (!isBrowser()) {
|
|
133
|
-
throw new Error("signIn() requires a browser environment");
|
|
134
|
-
}
|
|
135
|
-
window.location.href = `${this.getBaseURL()}${ROUTES.IDENTITY.SIGNIN}`;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
// src/client/namespaces/user.ts
|
|
139
|
-
class User {
|
|
140
|
-
getBaseURL;
|
|
141
|
-
fetchImpl;
|
|
142
|
-
constructor(getBaseURL, fetchImpl) {
|
|
143
|
-
this.getBaseURL = getBaseURL;
|
|
144
|
-
this.fetchImpl = fetchImpl;
|
|
145
|
-
}
|
|
146
|
-
async fetch() {
|
|
147
|
-
if (!isBrowser()) {
|
|
148
|
-
throw new Error("user.fetch() requires a browser environment");
|
|
149
|
-
}
|
|
150
|
-
const response = await this.fetchImpl(`${this.getBaseURL()}${ROUTES.USER.ME}`, {
|
|
151
|
-
method: "GET",
|
|
152
|
-
credentials: "include"
|
|
153
|
-
});
|
|
154
|
-
if (!response.ok) {
|
|
155
|
-
const errorResponse = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
156
|
-
throw new Error(errorResponse.error ?? "Failed to fetch user profile");
|
|
157
|
-
}
|
|
158
|
-
return response.json();
|
|
159
|
-
}
|
|
160
|
-
async verify() {
|
|
161
|
-
if (!isBrowser()) {
|
|
162
|
-
throw new Error("user.verify() requires a browser environment");
|
|
163
|
-
}
|
|
164
|
-
const response = await this.fetchImpl(`${this.getBaseURL()}${ROUTES.USER.VERIFY}`, {
|
|
165
|
-
method: "GET",
|
|
166
|
-
credentials: "include"
|
|
167
|
-
});
|
|
168
|
-
if (!response.ok) {
|
|
169
|
-
const errorResponse = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
170
|
-
throw new Error(errorResponse.error ?? "Failed to verify Timeback user");
|
|
171
|
-
}
|
|
172
|
-
const data = await response.json();
|
|
173
|
-
if (data.verified && data.timebackId) {
|
|
174
|
-
return { verified: true, timebackId: data.timebackId };
|
|
175
|
-
}
|
|
176
|
-
return { verified: false };
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// src/client/timeback-client.class.ts
|
|
180
|
-
class TimebackClient {
|
|
181
|
-
activity;
|
|
182
|
-
auth;
|
|
183
|
-
user;
|
|
184
|
-
_baseURL;
|
|
185
|
-
_fetch;
|
|
186
|
-
constructor(config = {}) {
|
|
187
|
-
this._baseURL = config.baseURL;
|
|
188
|
-
const baseFetch = config.fetch ?? getDefaultFetch();
|
|
189
|
-
if (!baseFetch) {
|
|
190
|
-
throw new Error("TimebackClient requires a fetch implementation. " + "Provide `fetch` in the constructor config for non-browser runtimes.");
|
|
191
|
-
}
|
|
192
|
-
const rawPlugins = config.plugins;
|
|
193
|
-
const plugins = Array.isArray(rawPlugins) ? rawPlugins : rawPlugins ? [rawPlugins] : [];
|
|
194
|
-
this._fetch = plugins.reduce((f, p) => p.wrapFetch(f), baseFetch);
|
|
195
|
-
this.activity = new ActivityManager((payload) => this.sendActivity(payload));
|
|
196
|
-
this.auth = new Auth(() => this.baseURL);
|
|
197
|
-
this.user = new User(() => this.baseURL, this._fetch);
|
|
198
|
-
}
|
|
199
|
-
get baseURL() {
|
|
200
|
-
if (!this._baseURL) {
|
|
201
|
-
const resolved = getDefaultBaseURL();
|
|
202
|
-
if (!resolved) {
|
|
203
|
-
throw new Error("Timeback client requires a browser environment for default baseURL. " + "Provide an explicit baseURL for server-side usage.");
|
|
204
|
-
}
|
|
205
|
-
this._baseURL = resolved;
|
|
206
|
-
}
|
|
207
|
-
return this._baseURL;
|
|
208
|
-
}
|
|
209
|
-
async sendActivity(payload) {
|
|
210
|
-
const response = await this._fetch(`${this.baseURL}${ROUTES.ACTIVITY}`, {
|
|
211
|
-
method: "POST",
|
|
212
|
-
headers: { "Content-Type": "application/json" },
|
|
213
|
-
body: JSON.stringify(payload),
|
|
214
|
-
credentials: "include"
|
|
215
|
-
});
|
|
216
|
-
if (!response.ok) {
|
|
217
|
-
const errorResponse = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
218
|
-
throw new Error(errorResponse.error ?? "Failed to send activity");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// src/client/timeback-client.ts
|
|
224
|
-
function createClient(config = {}) {
|
|
225
|
-
const baseURL = config.baseURL ?? getDefaultBaseURL();
|
|
226
|
-
return new TimebackClient({
|
|
227
|
-
baseURL,
|
|
228
|
-
fetch: config.fetch,
|
|
229
|
-
plugins: config.plugins
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
// src/client/auth/bearer.ts
|
|
233
|
-
function bearer(options) {
|
|
234
|
-
const headerName = options.headerName ?? "Authorization";
|
|
235
|
-
const prefix = options.prefix ?? "Bearer ";
|
|
236
|
-
return {
|
|
237
|
-
wrapFetch(fetchImpl) {
|
|
238
|
-
return async (input, init) => {
|
|
239
|
-
const token = await options.getToken();
|
|
240
|
-
if (!token) {
|
|
241
|
-
throw new Error("Missing bearer token (are you authenticated yet?)");
|
|
242
|
-
}
|
|
243
|
-
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
244
|
-
if (!headers.has(headerName)) {
|
|
245
|
-
headers.set(headerName, `${prefix}${token}`);
|
|
246
|
-
}
|
|
247
|
-
return fetchImpl(input, { ...init, headers });
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
export {
|
|
253
|
-
createClient,
|
|
254
|
-
bearer,
|
|
255
|
-
TimebackClient,
|
|
256
|
-
Activity
|
|
257
|
-
};
|
|
1
|
+
import{e as o,f as y,g as b}from"./chunk-8gg8n8v9.js";function r(e){let i=e.headerName??"Authorization",k=e.prefix??"Bearer ";return{wrapFetch(s){return async(t,m)=>{let a=await e.getToken();if(!a)throw Error("Missing bearer token (are you authenticated yet?)");let c=new Headers(m?.headers??(t instanceof Request?t.headers:void 0));if(!c.has(i))c.set(i,`${k}${a}`);return s(t,{...m,headers:c})}}}}export{b as createClient,r as bearer,y as TimebackClient,o as Activity};
|