@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.
Files changed (116) hide show
  1. package/README.md +97 -8
  2. package/dist/chunk-07j8zre9.js +2 -0
  3. package/dist/chunk-5171mkp2.js +2 -0
  4. package/dist/chunk-63afdp3y.js +8 -0
  5. package/dist/chunk-8gg8n8v9.js +2 -0
  6. package/dist/chunk-9se82640.js +1 -0
  7. package/dist/chunk-agpf1x3g.js +16 -0
  8. package/dist/chunk-hnf0tart.js +2 -0
  9. package/dist/chunk-qr0bbnsr.js +1 -0
  10. package/dist/chunk-whc53e0y.js +11 -0
  11. package/dist/chunk-x9gvef7q.js +1 -0
  12. package/dist/client/adapters/react/hooks/types.d.ts +80 -0
  13. package/dist/client/adapters/react/hooks/types.d.ts.map +1 -1
  14. package/dist/client/adapters/react/hooks/useTimebackProfile.d.ts +42 -0
  15. package/dist/client/adapters/react/hooks/useTimebackProfile.d.ts.map +1 -0
  16. package/dist/client/adapters/react/hooks/useTimebackVerification.d.ts +17 -5
  17. package/dist/client/adapters/react/hooks/useTimebackVerification.d.ts.map +1 -1
  18. package/dist/client/adapters/react/index.d.ts +2 -1
  19. package/dist/client/adapters/react/index.d.ts.map +1 -1
  20. package/dist/client/adapters/react/index.js +2 -494
  21. package/dist/client/adapters/react/provider.d.ts.map +1 -1
  22. package/dist/client/adapters/solid/index.d.ts +3 -0
  23. package/dist/client/adapters/solid/index.d.ts.map +1 -1
  24. package/dist/client/adapters/solid/index.ts +12 -0
  25. package/dist/client/adapters/solid/primitives/createTimebackProfile.d.ts +58 -0
  26. package/dist/client/adapters/solid/primitives/createTimebackProfile.d.ts.map +1 -0
  27. package/dist/client/adapters/solid/primitives/createTimebackProfile.ts +209 -0
  28. package/dist/client/adapters/solid/primitives/createTimebackVerification.d.ts +38 -0
  29. package/dist/client/adapters/solid/primitives/createTimebackVerification.d.ts.map +1 -0
  30. package/dist/client/adapters/solid/primitives/createTimebackVerification.ts +173 -0
  31. package/dist/client/adapters/solid/types.d.ts +109 -0
  32. package/dist/client/adapters/solid/types.d.ts.map +1 -0
  33. package/dist/client/adapters/solid/types.ts +110 -0
  34. package/dist/client/adapters/svelte/index.d.ts +2 -1
  35. package/dist/client/adapters/svelte/index.d.ts.map +1 -1
  36. package/dist/client/adapters/svelte/index.ts +11 -2
  37. package/dist/client/adapters/svelte/{stores.d.ts → stores/client.d.ts} +11 -9
  38. package/dist/client/adapters/svelte/stores/client.d.ts.map +1 -0
  39. package/dist/client/adapters/svelte/{stores.ts → stores/client.ts} +24 -52
  40. package/dist/client/adapters/svelte/stores/index.d.ts +10 -0
  41. package/dist/client/adapters/svelte/stores/index.d.ts.map +1 -0
  42. package/dist/client/adapters/svelte/stores/index.ts +22 -0
  43. package/dist/client/adapters/svelte/stores/profile.d.ts +66 -0
  44. package/dist/client/adapters/svelte/stores/profile.d.ts.map +1 -0
  45. package/dist/client/adapters/svelte/stores/profile.ts +168 -0
  46. package/dist/client/adapters/svelte/stores/verification.d.ts +43 -0
  47. package/dist/client/adapters/svelte/stores/verification.d.ts.map +1 -0
  48. package/dist/client/adapters/svelte/stores/verification.ts +208 -0
  49. package/dist/client/adapters/svelte/types.d.ts +35 -0
  50. package/dist/client/adapters/svelte/types.d.ts.map +1 -0
  51. package/dist/client/adapters/vue/composables/useTimebackProfile.d.ts +51 -0
  52. package/dist/client/adapters/vue/composables/useTimebackProfile.d.ts.map +1 -0
  53. package/dist/client/adapters/vue/composables/useTimebackProfile.ts +186 -0
  54. package/dist/client/adapters/vue/composables/useTimebackVerification.d.ts +46 -0
  55. package/dist/client/adapters/vue/composables/useTimebackVerification.d.ts.map +1 -0
  56. package/dist/client/adapters/vue/composables/useTimebackVerification.ts +169 -0
  57. package/dist/client/adapters/vue/index.d.ts +3 -0
  58. package/dist/client/adapters/vue/index.d.ts.map +1 -1
  59. package/dist/client/adapters/vue/index.ts +12 -1
  60. package/dist/client/adapters/vue/types.d.ts +109 -0
  61. package/dist/client/adapters/vue/types.d.ts.map +1 -0
  62. package/dist/client/adapters/vue/types.ts +110 -0
  63. package/dist/client/lib/activity/activity.class.d.ts +5 -5
  64. package/dist/client/lib/activity/activity.class.d.ts.map +1 -1
  65. package/dist/client/lib/user-cache.d.ts +39 -0
  66. package/dist/client/lib/user-cache.d.ts.map +1 -0
  67. package/dist/client/lib/user-cache.ts +168 -0
  68. package/dist/client/lib/utils.d.ts +15 -0
  69. package/dist/client/lib/utils.d.ts.map +1 -1
  70. package/dist/client/namespaces/activity.d.ts +2 -3
  71. package/dist/client/namespaces/activity.d.ts.map +1 -1
  72. package/dist/client.d.ts +1 -1
  73. package/dist/client.js +1 -257
  74. package/dist/edge.js +1 -86271
  75. package/dist/identity.js +1 -86131
  76. package/dist/index.d.ts +2 -2
  77. package/dist/index.js +22 -104883
  78. package/dist/server/adapters/express.js +1 -85973
  79. package/dist/server/adapters/native.js +2 -221
  80. package/dist/server/adapters/nextjs.js +1 -233
  81. package/dist/server/adapters/nuxt.js +1 -86046
  82. package/dist/server/adapters/solid-start.js +1 -85945
  83. package/dist/server/adapters/svelte-kit.js +1 -279
  84. package/dist/server/adapters/tanstack-start.js +1 -85918
  85. package/dist/server/handlers/activity/attempts.d.ts +51 -0
  86. package/dist/server/handlers/activity/attempts.d.ts.map +1 -0
  87. package/dist/server/handlers/activity/caliper.d.ts +46 -5
  88. package/dist/server/handlers/activity/caliper.d.ts.map +1 -1
  89. package/dist/server/handlers/activity/completion.d.ts +43 -0
  90. package/dist/server/handlers/activity/completion.d.ts.map +1 -0
  91. package/dist/server/handlers/activity/handler.d.ts +18 -1
  92. package/dist/server/handlers/activity/handler.d.ts.map +1 -1
  93. package/dist/server/handlers/activity/progress.d.ts +47 -0
  94. package/dist/server/handlers/activity/progress.d.ts.map +1 -0
  95. package/dist/server/handlers/activity/schema.d.ts +1 -2
  96. package/dist/server/handlers/activity/schema.d.ts.map +1 -1
  97. package/dist/server/handlers/activity/types.d.ts +1 -2
  98. package/dist/server/handlers/activity/types.d.ts.map +1 -1
  99. package/dist/server/lib/index.d.ts +1 -1
  100. package/dist/server/lib/index.d.ts.map +1 -1
  101. package/dist/server/lib/utils.d.ts +61 -0
  102. package/dist/server/lib/utils.d.ts.map +1 -1
  103. package/dist/server/timeback.d.ts +2 -2
  104. package/dist/server/timeback.d.ts.map +1 -1
  105. package/dist/server/types.d.ts +7 -1
  106. package/dist/server/types.d.ts.map +1 -1
  107. package/dist/shared/constants.d.ts +19 -0
  108. package/dist/shared/constants.d.ts.map +1 -1
  109. package/dist/shared/types.d.ts +62 -8
  110. package/dist/shared/types.d.ts.map +1 -1
  111. package/dist/shared/xp-calculator.d.ts +25 -0
  112. package/dist/shared/xp-calculator.d.ts.map +1 -0
  113. package/package.json +6 -4
  114. package/dist/client/adapters/svelte/stores.d.ts.map +0 -1
  115. package/dist/server/handlers/activity/gradebook.d.ts +0 -56
  116. package/dist/server/handlers/activity/gradebook.d.ts.map +0 -1
@@ -1,17 +1,20 @@
1
1
  /**
2
- * Svelte Stores
2
+ * Timeback Client Store
3
3
  *
4
- * Svelte stores for Timeback SDK reactivity.
4
+ * Core Svelte store for the Timeback client singleton.
5
5
  */
6
6
  import { TimebackClient } from '@timeback/sdk/client';
7
+ import type { Readable } from 'svelte/store';
7
8
  /**
8
- * Minimal Svelte-compatible store interface.
9
+ * Internal client store.
10
+ */
11
+ export declare const clientStore: import("svelte/store").Writable<TimebackClient | undefined>;
12
+ /**
13
+ * Get the current client instance (for internal use by other stores).
9
14
  *
10
- * This allows the SDK to work without a direct Svelte dependency.
15
+ * @returns Current client instance or undefined
11
16
  */
12
- interface Readable<T> {
13
- subscribe: (run: (value: T) => void) => () => void;
14
- }
17
+ export declare function getClientInstance(): TimebackClient | undefined;
15
18
  /**
16
19
  * Initialize the Timeback client.
17
20
  *
@@ -61,5 +64,4 @@ export declare function initTimeback(client?: TimebackClient): void;
61
64
  * ```
62
65
  */
63
66
  export declare const timeback: Readable<TimebackClient | undefined>;
64
- export {};
65
- //# sourceMappingURL=stores.d.ts.map
67
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../../src/client/adapters/svelte/stores/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAyB5C;;GAEG;AACH,eAAO,MAAM,WAAW,6DAAkD,CAAA;AAE1E;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAQ1D;AASD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,cAAc,GAAG,SAAS,CAAe,CAAA"}
@@ -1,51 +1,14 @@
1
1
  /**
2
- * Svelte Stores
2
+ * Timeback Client Store
3
3
  *
4
- * Svelte stores for Timeback SDK reactivity.
4
+ * Core Svelte store for the Timeback client singleton.
5
5
  */
6
6
 
7
- import { TimebackClient } from '@timeback/sdk/client'
8
-
9
- /**
10
- * Minimal Svelte-compatible store interface.
11
- *
12
- * This allows the SDK to work without a direct Svelte dependency.
13
- */
14
- interface Readable<T> {
15
- subscribe: (run: (value: T) => void) => () => void
16
- }
17
-
18
- interface Writable<T> extends Readable<T> {
19
- set: (value: T) => void
20
- update: (updater: (value: T) => T) => void
21
- }
7
+ import { writable } from 'svelte/store'
22
8
 
23
- /**
24
- * Create a minimal writable store implementation.
25
- *
26
- * @param initialValue - Initial store value
27
- * @returns Writable store
28
- */
29
- function writable<T>(initialValue: T): Writable<T> {
30
- let value = initialValue
31
- const subscribers = new Set<(value: T) => void>()
9
+ import { TimebackClient } from '@timeback/sdk/client'
32
10
 
33
- return {
34
- subscribe(run) {
35
- subscribers.add(run)
36
- run(value)
37
- return () => subscribers.delete(run)
38
- },
39
- set(newValue) {
40
- value = newValue
41
- subscribers.forEach(fn => fn(value))
42
- },
43
- update(updater) {
44
- value = updater(value)
45
- subscribers.forEach(fn => fn(value))
46
- },
47
- }
48
- }
11
+ import type { Readable } from 'svelte/store'
49
12
 
50
13
  let clientInstance: TimebackClient | undefined
51
14
 
@@ -61,10 +24,28 @@ function getOrCreateClient(): TimebackClient {
61
24
  return clientInstance
62
25
  }
63
26
 
27
+ /**
28
+ * Check if we're running in the browser.
29
+ *
30
+ * @returns True if in browser
31
+ */
32
+ function isBrowser(): boolean {
33
+ return typeof window !== 'undefined'
34
+ }
35
+
64
36
  /**
65
37
  * Internal client store.
66
38
  */
67
- const clientStore = writable<TimebackClient | undefined>(undefined)
39
+ export const clientStore = writable<TimebackClient | undefined>(undefined)
40
+
41
+ /**
42
+ * Get the current client instance (for internal use by other stores).
43
+ *
44
+ * @returns Current client instance or undefined
45
+ */
46
+ export function getClientInstance(): TimebackClient | undefined {
47
+ return clientInstance
48
+ }
68
49
 
69
50
  /**
70
51
  * Initialize the Timeback client.
@@ -95,15 +76,6 @@ export function initTimeback(client?: TimebackClient): void {
95
76
  clientStore.set(getOrCreateClient())
96
77
  }
97
78
 
98
- /**
99
- * Check if we're running in the browser.
100
- *
101
- * @returns True if in browser
102
- */
103
- function isBrowser(): boolean {
104
- return typeof window !== 'undefined'
105
- }
106
-
107
79
  /**
108
80
  * Auto-initialize on first access in browser.
109
81
  */
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Svelte Stores
3
+ *
4
+ * Svelte stores for Timeback SDK reactivity.
5
+ */
6
+ export { initTimeback, timeback } from './client';
7
+ export { refreshTimebackVerification, timebackVerification } from './verification';
8
+ export { fetchTimebackProfile, refreshTimebackProfile, timebackProfile, timebackProfileCanFetch, } from './profile';
9
+ export type { TimebackProfileState, TimebackVerificationState } from '../types';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/client/adapters/svelte/stores/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGjD,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAGlF,OAAO,EACN,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,uBAAuB,GACvB,MAAM,WAAW,CAAA;AAGlB,YAAY,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Svelte Stores
3
+ *
4
+ * Svelte stores for Timeback SDK reactivity.
5
+ */
6
+
7
+ // Client
8
+ export { initTimeback, timeback } from './client'
9
+
10
+ // Verification
11
+ export { refreshTimebackVerification, timebackVerification } from './verification'
12
+
13
+ // Profile
14
+ export {
15
+ fetchTimebackProfile,
16
+ refreshTimebackProfile,
17
+ timebackProfile,
18
+ timebackProfileCanFetch,
19
+ } from './profile'
20
+
21
+ // Types re-exported for convenience
22
+ export type { TimebackProfileState, TimebackVerificationState } from '../types'
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Timeback Profile Store
3
+ *
4
+ * Svelte store for user profile state.
5
+ */
6
+ import type { TimebackProfileState } from '../types';
7
+ import type { Readable } from 'svelte/store';
8
+ /**
9
+ * Store containing the Timeback profile state.
10
+ *
11
+ * Use this to access the current user's Timeback profile.
12
+ * Call `fetchTimebackProfile()` to manually fetch, or `refreshTimebackProfile()` to force re-fetch.
13
+ *
14
+ * @example
15
+ * ```svelte
16
+ * <script>
17
+ * import { timebackProfile, timebackProfileCanFetch, fetchTimebackProfile } from '@timeback/sdk/svelte'
18
+ * </script>
19
+ *
20
+ * <button on:click={fetchTimebackProfile} disabled={!$timebackProfileCanFetch}>
21
+ * {$timebackProfile.status === 'loading' ? 'Loading...' : 'Fetch Profile'}
22
+ * </button>
23
+ *
24
+ * {#if $timebackProfile.status === 'loaded'}
25
+ * <pre>{JSON.stringify($timebackProfile.profile, null, 2)}</pre>
26
+ * {/if}
27
+ * ```
28
+ */
29
+ export declare const timebackProfile: Readable<TimebackProfileState>;
30
+ /**
31
+ * Store indicating whether the profile can be fetched.
32
+ *
33
+ * True when the user is verified and the client is ready.
34
+ */
35
+ export declare const timebackProfileCanFetch: Readable<boolean>;
36
+ /**
37
+ * Manually fetch the Timeback profile.
38
+ *
39
+ * No-op if the user is not verified or client is not ready.
40
+ *
41
+ * @example
42
+ * ```svelte
43
+ * <script>
44
+ * import { fetchTimebackProfile } from '@timeback/sdk/svelte'
45
+ * </script>
46
+ *
47
+ * <button on:click={fetchTimebackProfile}>Fetch Profile</button>
48
+ * ```
49
+ */
50
+ export declare function fetchTimebackProfile(): void;
51
+ /**
52
+ * Force a re-fetch of the Timeback profile.
53
+ *
54
+ * No-op if the user is not verified or client is not ready.
55
+ *
56
+ * @example
57
+ * ```svelte
58
+ * <script>
59
+ * import { refreshTimebackProfile } from '@timeback/sdk/svelte'
60
+ * </script>
61
+ *
62
+ * <button on:click={refreshTimebackProfile}>Refresh Profile</button>
63
+ * ```
64
+ */
65
+ export declare function refreshTimebackProfile(): void;
66
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../../../src/client/adapters/svelte/stores/profile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,oBAAoB,EAA6B,MAAM,UAAU,CAAA;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AA6E5C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,oBAAoB,CAAgB,CAAA;AAE3E;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,OAAO,CAAiB,CAAA;AAEvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAS3C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAS7C"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Timeback Profile Store
3
+ *
4
+ * Svelte store for user profile state.
5
+ */
6
+
7
+ import { fetchProfileOnce, getProfileCache } from '../../../lib/user-cache'
8
+ import { getClientInstance } from './client'
9
+ import { writable } from 'svelte/store'
10
+ import { verificationStore } from './verification'
11
+
12
+ import type { TimebackProfileState, TimebackVerificationState } from '../types'
13
+ import type { Readable } from 'svelte/store'
14
+
15
+ const profileStore = writable<TimebackProfileState>({ status: 'idle' })
16
+ const canFetchStore = writable<boolean>(false)
17
+ let profileInitialized = false
18
+
19
+ /**
20
+ * Check if we're running in the browser.
21
+ *
22
+ * @returns True if in browser
23
+ */
24
+ function isBrowser(): boolean {
25
+ return typeof window !== 'undefined'
26
+ }
27
+
28
+ /**
29
+ * Run the profile fetch.
30
+ *
31
+ * @param force - If true, bypass cache and force a fresh fetch
32
+ */
33
+ async function runProfileFetch(force: boolean): Promise<void> {
34
+ const client = getClientInstance()
35
+ if (!client) return
36
+
37
+ if (!force) {
38
+ const cached = getProfileCache(client)
39
+ if (cached) {
40
+ profileStore.set({ status: 'loaded', profile: cached })
41
+ return
42
+ }
43
+ }
44
+
45
+ profileStore.set({ status: 'loading' })
46
+
47
+ try {
48
+ const profile = await fetchProfileOnce(client, force)
49
+ profileStore.set({ status: 'loaded', profile })
50
+ } catch (err) {
51
+ profileStore.set({
52
+ status: 'error',
53
+ message: err instanceof Error ? err.message : 'Failed to fetch profile',
54
+ })
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Update canFetch based on verification state.
60
+ *
61
+ * @param verification - Current verification state
62
+ */
63
+ function updateCanFetch(verification: TimebackVerificationState): void {
64
+ const can = verification.status === 'verified' && !!getClientInstance()
65
+ canFetchStore.set(can)
66
+ }
67
+
68
+ /**
69
+ * Initialize profile store subscriptions.
70
+ */
71
+ function initProfile(): void {
72
+ if (profileInitialized) return
73
+ profileInitialized = true
74
+
75
+ verificationStore.subscribe(verification => {
76
+ updateCanFetch(verification)
77
+
78
+ // Reset to idle if not verified
79
+ if (verification.status !== 'verified') {
80
+ profileStore.set({ status: 'idle' })
81
+ }
82
+ })
83
+ }
84
+
85
+ // Auto-init in browser
86
+ if (isBrowser()) {
87
+ initProfile()
88
+ }
89
+
90
+ /**
91
+ * Store containing the Timeback profile state.
92
+ *
93
+ * Use this to access the current user's Timeback profile.
94
+ * Call `fetchTimebackProfile()` to manually fetch, or `refreshTimebackProfile()` to force re-fetch.
95
+ *
96
+ * @example
97
+ * ```svelte
98
+ * <script>
99
+ * import { timebackProfile, timebackProfileCanFetch, fetchTimebackProfile } from '@timeback/sdk/svelte'
100
+ * </script>
101
+ *
102
+ * <button on:click={fetchTimebackProfile} disabled={!$timebackProfileCanFetch}>
103
+ * {$timebackProfile.status === 'loading' ? 'Loading...' : 'Fetch Profile'}
104
+ * </button>
105
+ *
106
+ * {#if $timebackProfile.status === 'loaded'}
107
+ * <pre>{JSON.stringify($timebackProfile.profile, null, 2)}</pre>
108
+ * {/if}
109
+ * ```
110
+ */
111
+ export const timebackProfile: Readable<TimebackProfileState> = profileStore
112
+
113
+ /**
114
+ * Store indicating whether the profile can be fetched.
115
+ *
116
+ * True when the user is verified and the client is ready.
117
+ */
118
+ export const timebackProfileCanFetch: Readable<boolean> = canFetchStore
119
+
120
+ /**
121
+ * Manually fetch the Timeback profile.
122
+ *
123
+ * No-op if the user is not verified or client is not ready.
124
+ *
125
+ * @example
126
+ * ```svelte
127
+ * <script>
128
+ * import { fetchTimebackProfile } from '@timeback/sdk/svelte'
129
+ * </script>
130
+ *
131
+ * <button on:click={fetchTimebackProfile}>Fetch Profile</button>
132
+ * ```
133
+ */
134
+ export function fetchTimebackProfile(): void {
135
+ if (!isBrowser()) return
136
+
137
+ let canFetch = false
138
+ canFetchStore.subscribe(v => (canFetch = v))()
139
+
140
+ if (!canFetch) return
141
+
142
+ void runProfileFetch(false)
143
+ }
144
+
145
+ /**
146
+ * Force a re-fetch of the Timeback profile.
147
+ *
148
+ * No-op if the user is not verified or client is not ready.
149
+ *
150
+ * @example
151
+ * ```svelte
152
+ * <script>
153
+ * import { refreshTimebackProfile } from '@timeback/sdk/svelte'
154
+ * </script>
155
+ *
156
+ * <button on:click={refreshTimebackProfile}>Refresh Profile</button>
157
+ * ```
158
+ */
159
+ export function refreshTimebackProfile(): void {
160
+ if (!isBrowser()) return
161
+
162
+ let canFetch = false
163
+ canFetchStore.subscribe(v => (canFetch = v))()
164
+
165
+ if (!canFetch) return
166
+
167
+ void runProfileFetch(true)
168
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Timeback Verification Store
3
+ *
4
+ * Svelte store for user verification state.
5
+ */
6
+ import type { Readable } from 'svelte/store';
7
+ import type { TimebackVerificationState } from '../types';
8
+ export declare const verificationStore: import("svelte/store").Writable<TimebackVerificationState>;
9
+ /**
10
+ * Store containing the Timeback verification state.
11
+ *
12
+ * Use this to check if the current user is verified in Timeback.
13
+ *
14
+ * @example
15
+ * ```svelte
16
+ * <script>
17
+ * import { timebackVerification, refreshTimebackVerification } from '@timeback/sdk/svelte'
18
+ * </script>
19
+ *
20
+ * {#if $timebackVerification.status === 'verified'}
21
+ * <p>Verified! Timeback ID: {$timebackVerification.timebackId}</p>
22
+ * {:else if $timebackVerification.status === 'loading'}
23
+ * <p>Verifying...</p>
24
+ * {:else}
25
+ * <p>Not verified</p>
26
+ * {/if}
27
+ * ```
28
+ */
29
+ export declare const timebackVerification: Readable<TimebackVerificationState>;
30
+ /**
31
+ * Force a re-verification of the current user.
32
+ *
33
+ * @example
34
+ * ```svelte
35
+ * <script>
36
+ * import { refreshTimebackVerification } from '@timeback/sdk/svelte'
37
+ * </script>
38
+ *
39
+ * <button on:click={refreshTimebackVerification}>Refresh Verification</button>
40
+ * ```
41
+ */
42
+ export declare function refreshTimebackVerification(): void;
43
+ //# sourceMappingURL=verification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../../../../src/client/adapters/svelte/stores/verification.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAE5C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AAczD,eAAO,MAAM,iBAAiB,4DAA6D,CAAA;AA6I3F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,yBAAyB,CAAqB,CAAA;AAE1F;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Timeback Verification Store
3
+ *
4
+ * Svelte store for user verification state.
5
+ */
6
+
7
+ import { writable } from 'svelte/store'
8
+
9
+ import { DEFAULT_RETRY_ATTEMPTS, DEFAULT_RETRY_DELAYS_MS } from '../../../../shared/constants'
10
+ import { getVerifyCache, verifyOnce } from '../../../lib/user-cache'
11
+ import { getRetryDelay, sleep } from '../../../lib/utils'
12
+ import { clientStore, getClientInstance } from './client'
13
+
14
+ import type { Readable } from 'svelte/store'
15
+ import type { TimebackVerifyResult } from '../../../../shared/types'
16
+ import type { TimebackVerificationState } from '../types'
17
+
18
+ /**
19
+ * Convert a verify result into a store-friendly state machine.
20
+ *
21
+ * @param result - Raw verify result from the SDK client
22
+ * @returns Mapped verification state
23
+ */
24
+ function toVerificationState(result: TimebackVerifyResult): TimebackVerificationState {
25
+ return result.verified
26
+ ? { status: 'verified', timebackId: result.timebackId }
27
+ : { status: 'unverified' }
28
+ }
29
+
30
+ export const verificationStore = writable<TimebackVerificationState>({ status: 'loading' })
31
+ let verificationInitialized = false
32
+
33
+ /**
34
+ * Counter tracking the current verification run.
35
+ *
36
+ * Each call to `runVerification` increments this counter and captures
37
+ * its value. Before updating state, the run checks if it's still current.
38
+ * This prevents stale results from overwriting fresh ones when multiple
39
+ * verification attempts overlap (e.g., initial retry + user refresh).
40
+ */
41
+ let currentRunId = 0
42
+
43
+ /**
44
+ * Check if we're running in the browser.
45
+ *
46
+ * @returns True if in browser
47
+ */
48
+ function isBrowser(): boolean {
49
+ return typeof window !== 'undefined'
50
+ }
51
+
52
+ /**
53
+ * Run the verification check with retry logic.
54
+ *
55
+ * Uses a run ID to prevent race conditions when multiple verification
56
+ * attempts overlap. Each run captures the current ID and only updates
57
+ * state if it's still the active run.
58
+ *
59
+ * @param force - If true, bypass cache and force a fresh verification
60
+ */
61
+ async function runVerification(force: boolean): Promise<void> {
62
+ const client = getClientInstance()
63
+ if (!client) return
64
+
65
+ /**
66
+ * Capture this run's ID. Any subsequent call to runVerification
67
+ * will increment currentRunId, making this run "cancelled".
68
+ */
69
+ const runId = ++currentRunId
70
+
71
+ /**
72
+ * Check if this run is still the active one.
73
+ *
74
+ * @returns False if a newer verification run has started
75
+ */
76
+ const isCurrentRun = () => runId === currentRunId
77
+
78
+ if (!force) {
79
+ const cached = getVerifyCache(client)
80
+ if (cached) {
81
+ if (isCurrentRun()) {
82
+ verificationStore.set(toVerificationState(cached))
83
+ }
84
+ return
85
+ }
86
+ }
87
+
88
+ if (isCurrentRun()) {
89
+ verificationStore.set({ status: 'loading' })
90
+ }
91
+
92
+ let lastError: Error | undefined
93
+
94
+ for (let attempt = 0; attempt <= DEFAULT_RETRY_ATTEMPTS; attempt++) {
95
+ if (!isCurrentRun()) return
96
+
97
+ /**
98
+ * Wait for a calculated delay before retrying the verification request.
99
+ *
100
+ * This occurs only on subsequent attempts (not the initial try),
101
+ * introducing a backoff based on the configured retry delays.
102
+ */
103
+ if (attempt > 0) {
104
+ const delay = getRetryDelay(DEFAULT_RETRY_DELAYS_MS, attempt - 1)
105
+ await sleep(delay)
106
+ if (!isCurrentRun()) return
107
+ }
108
+
109
+ try {
110
+ const result = await verifyOnce(client, force || attempt > 0)
111
+
112
+ if (!isCurrentRun()) return
113
+
114
+ verificationStore.set(toVerificationState(result))
115
+
116
+ return
117
+ } catch (err) {
118
+ lastError = err instanceof Error ? err : new Error('Failed to verify Timeback user')
119
+ /**
120
+ * An error occurred during this verification attempt.
121
+ * Proceeding to the next retry attempt if any remain.
122
+ *
123
+ * The last encountered error is saved for potential error state handling.
124
+ */
125
+ }
126
+ }
127
+
128
+ /**
129
+ * All verification attempts have failed after exhausting
130
+ * the configured retry policy. The verification state will
131
+ * transition to "error" if this run is still current, and the last
132
+ * encountered error message (if available) will be presented to the consumer.
133
+ */
134
+ if (isCurrentRun() && lastError) {
135
+ verificationStore.set({
136
+ status: 'error',
137
+ message: lastError.message,
138
+ })
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Initialize verification when client becomes available.
144
+ */
145
+ function initVerification(): void {
146
+ if (verificationInitialized) return
147
+ verificationInitialized = true
148
+
149
+ /**
150
+ * Subscribes to changes in the Timeback client store.
151
+ *
152
+ * Any time the client instance becomes available or changes,
153
+ * automatically triggers a verification attempt to ensure the
154
+ * user's Timeback verification status is kept up-to-date.
155
+ *
156
+ * This enables responsive status updates when authentication
157
+ * state changes or when the client instance is re-initialized,
158
+ * providing a seamless verification experience in Svelte apps.
159
+ */
160
+ clientStore.subscribe(client => {
161
+ if (client && isBrowser()) {
162
+ void runVerification(false)
163
+ }
164
+ })
165
+ }
166
+
167
+ if (isBrowser()) {
168
+ initVerification()
169
+ }
170
+
171
+ /**
172
+ * Store containing the Timeback verification state.
173
+ *
174
+ * Use this to check if the current user is verified in Timeback.
175
+ *
176
+ * @example
177
+ * ```svelte
178
+ * <script>
179
+ * import { timebackVerification, refreshTimebackVerification } from '@timeback/sdk/svelte'
180
+ * </script>
181
+ *
182
+ * {#if $timebackVerification.status === 'verified'}
183
+ * <p>Verified! Timeback ID: {$timebackVerification.timebackId}</p>
184
+ * {:else if $timebackVerification.status === 'loading'}
185
+ * <p>Verifying...</p>
186
+ * {:else}
187
+ * <p>Not verified</p>
188
+ * {/if}
189
+ * ```
190
+ */
191
+ export const timebackVerification: Readable<TimebackVerificationState> = verificationStore
192
+
193
+ /**
194
+ * Force a re-verification of the current user.
195
+ *
196
+ * @example
197
+ * ```svelte
198
+ * <script>
199
+ * import { refreshTimebackVerification } from '@timeback/sdk/svelte'
200
+ * </script>
201
+ *
202
+ * <button on:click={refreshTimebackVerification}>Refresh Verification</button>
203
+ * ```
204
+ */
205
+ export function refreshTimebackVerification(): void {
206
+ if (!isBrowser()) return
207
+ void runVerification(true)
208
+ }