timeback 0.0.0-alpha.2 → 0.1.0
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 +211 -7
- package/dist/client/adapters/react/SignInButton.d.ts +60 -0
- package/dist/client/adapters/react/SignInButton.d.ts.map +1 -0
- package/dist/client/adapters/react/index.d.ts +43 -0
- package/dist/client/adapters/react/index.d.ts.map +1 -0
- package/dist/client/adapters/react/index.js +478 -0
- package/dist/client/adapters/react/provider.d.ts +74 -0
- package/dist/client/adapters/react/provider.d.ts.map +1 -0
- package/dist/client/adapters/solid/SignInButton.d.ts +52 -0
- package/dist/client/adapters/solid/SignInButton.d.ts.map +1 -0
- package/dist/client/adapters/solid/SignInButton.tsx +321 -0
- package/dist/client/adapters/solid/context.d.ts +73 -0
- package/dist/client/adapters/solid/context.d.ts.map +1 -0
- package/dist/client/adapters/solid/context.tsx +91 -0
- package/dist/client/adapters/solid/index.d.ts +42 -0
- package/dist/client/adapters/solid/index.d.ts.map +1 -0
- package/dist/client/adapters/solid/index.ts +46 -0
- package/dist/client/adapters/svelte/SignInButton.svelte +234 -0
- package/dist/client/adapters/svelte/SignInButton.svelte.d.ts +24 -0
- package/dist/client/adapters/svelte/index.d.ts +33 -0
- package/dist/client/adapters/svelte/index.d.ts.map +1 -0
- package/dist/client/adapters/svelte/index.ts +38 -0
- package/dist/client/adapters/svelte/stores.d.ts +62 -0
- package/dist/client/adapters/svelte/stores.d.ts.map +1 -0
- package/dist/client/adapters/svelte/stores.ts +139 -0
- package/dist/client/index.d.ts +9 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/lib/activity/activity.class.d.ts +73 -0
- package/dist/client/lib/activity/activity.class.d.ts.map +1 -0
- package/dist/client/lib/activity/activity.d.ts +16 -0
- package/dist/client/lib/activity/activity.d.ts.map +1 -0
- package/dist/client/lib/activity/index.d.ts +6 -0
- package/dist/client/lib/activity/index.d.ts.map +1 -0
- package/dist/client/lib/utils.d.ts +20 -0
- package/dist/client/lib/utils.d.ts.map +1 -0
- package/dist/client/namespaces/activity.d.ts +37 -0
- package/dist/client/namespaces/activity.d.ts.map +1 -0
- package/dist/client/namespaces/auth.d.ts +33 -0
- package/dist/client/namespaces/auth.d.ts.map +1 -0
- package/dist/client/namespaces/index.d.ts +7 -0
- package/dist/client/namespaces/index.d.ts.map +1 -0
- package/dist/client/namespaces/user.d.ts +29 -0
- package/dist/client/namespaces/user.d.ts.map +1 -0
- package/dist/client/timeback-client.class.d.ts +37 -0
- package/dist/client/timeback-client.class.d.ts.map +1 -0
- package/dist/client/timeback-client.d.ts +29 -0
- package/dist/client/timeback-client.d.ts.map +1 -0
- package/dist/client.d.ts +30 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +198 -0
- package/dist/index.d.ts +27 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1137 -11
- package/dist/server/adapters/express.d.ts +62 -0
- package/dist/server/adapters/express.d.ts.map +1 -0
- package/dist/server/adapters/express.js +565 -0
- package/dist/server/adapters/native.d.ts +45 -0
- package/dist/server/adapters/native.d.ts.map +1 -0
- package/dist/server/adapters/native.js +509 -0
- package/dist/server/adapters/nextjs.d.ts +30 -0
- package/dist/server/adapters/nextjs.d.ts.map +1 -0
- package/dist/server/adapters/nextjs.js +521 -0
- package/dist/server/adapters/solid-start.d.ts +61 -0
- package/dist/server/adapters/solid-start.d.ts.map +1 -0
- package/dist/server/adapters/solid-start.js +551 -0
- package/dist/server/adapters/svelte-kit.d.ts +82 -0
- package/dist/server/adapters/svelte-kit.d.ts.map +1 -0
- package/dist/server/adapters/svelte-kit.js +572 -0
- package/dist/server/adapters/tanstack-start.js +522 -0
- package/dist/server/adapters/types.d.ts +212 -0
- package/dist/server/adapters/types.d.ts.map +1 -0
- package/dist/server/adapters/utils.d.ts +15 -0
- package/dist/server/adapters/utils.d.ts.map +1 -0
- package/dist/server/handlers/activity.d.ts +28 -0
- package/dist/server/handlers/activity.d.ts.map +1 -0
- package/dist/server/handlers/identity.d.ts +24 -0
- package/dist/server/handlers/identity.d.ts.map +1 -0
- package/dist/server/handlers/index.d.ts +9 -0
- package/dist/server/handlers/index.d.ts.map +1 -0
- package/dist/server/handlers/user.d.ts +30 -0
- package/dist/server/handlers/user.d.ts.map +1 -0
- package/dist/server/index.d.ts +10 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/lib/index.d.ts +9 -0
- package/dist/server/lib/index.d.ts.map +1 -0
- package/dist/server/lib/logger.d.ts +21 -0
- package/dist/server/lib/logger.d.ts.map +1 -0
- package/dist/server/lib/oidc.d.ts +76 -0
- package/dist/server/lib/oidc.d.ts.map +1 -0
- package/dist/server/lib/utils.d.ts +39 -0
- package/dist/server/lib/utils.d.ts.map +1 -0
- package/dist/server/timeback.d.ts +48 -0
- package/dist/server/timeback.d.ts.map +1 -0
- package/dist/server/types.d.ts +300 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/shared/constants.d.ts +18 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/types.d.ts +100 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/package.json +92 -28
package/README.md
CHANGED
|
@@ -1,15 +1,219 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Timeback SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TypeScript SDK for integrating with Timeback, providing both server-side BFF logic and client-side React components.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
|
|
8
|
+
npm install timeback
|
|
9
|
+
# or
|
|
10
|
+
bun add timeback
|
|
7
11
|
```
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
## Server-Side Setup
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
The server SDK auto-discovers your `timeback.config.ts` file and provides route handlers for Next.js.
|
|
16
|
+
|
|
17
|
+
### Configuration
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// app/lib/timeback.ts
|
|
21
|
+
import { createTimeback } from 'timeback'
|
|
22
|
+
|
|
23
|
+
export const timeback = await createTimeback({
|
|
24
|
+
env: 'production', // 'development' | 'staging' | 'production'
|
|
25
|
+
|
|
26
|
+
// API credentials for Timeback API calls
|
|
27
|
+
api: {
|
|
28
|
+
clientId: process.env.TIMEBACK_API_CLIENT_ID!,
|
|
29
|
+
clientSecret: process.env.TIMEBACK_API_CLIENT_SECRET!,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// Identity configuration
|
|
33
|
+
identity: {
|
|
34
|
+
// Option A: Timeback SSO
|
|
35
|
+
mode: 'sso',
|
|
36
|
+
clientId: process.env.TIMEBACK_SSO_CLIENT_ID!,
|
|
37
|
+
clientSecret: process.env.TIMEBACK_SSO_CLIENT_SECRET!,
|
|
38
|
+
|
|
39
|
+
// Option B: Custom identity provider (Clerk, Auth0, Supabase, etc.)
|
|
40
|
+
mode: 'custom',
|
|
41
|
+
getUser: async req => {
|
|
42
|
+
const session = await getSession(req)
|
|
43
|
+
return {
|
|
44
|
+
id: session.userId,
|
|
45
|
+
email: session.user.email,
|
|
46
|
+
name: session.user.name,
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Next.js Route Handlers
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// app/api/timeback/[...timeback]/route.ts
|
|
57
|
+
import { timeback } from '@/lib/timeback'
|
|
58
|
+
|
|
59
|
+
export const { GET, POST } = timeback.handlers()
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This exposes:
|
|
63
|
+
|
|
64
|
+
- `POST /api/timeback/activity` - Receives activity events from client
|
|
65
|
+
- `GET /api/timeback/identity/session` - Returns current user
|
|
66
|
+
- `GET /api/timeback/identity/signin` - Initiates SSO flow (SSO mode only)
|
|
67
|
+
- `GET /api/timeback/identity/callback` - SSO callback (SSO mode only)
|
|
68
|
+
|
|
69
|
+
## Client-Side Setup
|
|
70
|
+
|
|
71
|
+
### Configuration
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// app/lib/timeback-client.ts
|
|
75
|
+
import { createTimebackClient } from 'timeback/client/react'
|
|
76
|
+
|
|
77
|
+
// Zero config - baseURL defaults to window.location.origin + '/api/timeback'
|
|
78
|
+
export const timebackClient = createTimebackClient()
|
|
79
|
+
|
|
80
|
+
// Or with explicit URL
|
|
81
|
+
export const timebackClient = createTimebackClient({
|
|
82
|
+
baseURL: 'https://myapp.com/api/timeback',
|
|
83
|
+
})
|
|
13
84
|
```
|
|
14
85
|
|
|
15
|
-
|
|
86
|
+
### React Provider
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// app/providers.tsx
|
|
90
|
+
import { TimebackProvider } from 'timeback/client/react'
|
|
91
|
+
|
|
92
|
+
import { timebackClient } from '@/lib/timeback-client'
|
|
93
|
+
|
|
94
|
+
export function Providers({ children }) {
|
|
95
|
+
return <TimebackProvider client={timebackClient}>{children}</TimebackProvider>
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Hooks
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { useActivity, useTimeback } from 'timeback/client/react'
|
|
103
|
+
|
|
104
|
+
function UserMenu() {
|
|
105
|
+
const { user, isLoading, identityMode, signIn, signOut } = useTimeback()
|
|
106
|
+
|
|
107
|
+
if (isLoading) return <Spinner />
|
|
108
|
+
|
|
109
|
+
if (!user) {
|
|
110
|
+
return <button onClick={signIn}>Sign In</button>
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div>
|
|
115
|
+
<span>{user.name}</span>
|
|
116
|
+
<button onClick={signOut}>Sign Out</button>
|
|
117
|
+
</div>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Activity Tracking
|
|
123
|
+
|
|
124
|
+
#### React Hook
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
function LessonPlayer({ lessonId, courseCode }) {
|
|
128
|
+
// Starts on mount, ends on unmount, restarts if deps change
|
|
129
|
+
const activity = useActivity({
|
|
130
|
+
type: 'lesson',
|
|
131
|
+
objectId: lessonId,
|
|
132
|
+
courseCode,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<>
|
|
137
|
+
<button onClick={() => activity.pause()}>Pause</button>
|
|
138
|
+
<button onClick={() => activity.resume()}>Resume</button>
|
|
139
|
+
<span>Time: {activity.elapsedMs}ms</span>
|
|
140
|
+
</>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Vanilla API
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { createTimebackClient } from 'timeback/client'
|
|
149
|
+
|
|
150
|
+
const client = createTimebackClient()
|
|
151
|
+
|
|
152
|
+
// Start tracking
|
|
153
|
+
const activity = client.startActivity({
|
|
154
|
+
type: 'lesson',
|
|
155
|
+
objectId: 'lesson-123',
|
|
156
|
+
courseCode: 'FASTMATH-1',
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
// Pause/resume as needed
|
|
160
|
+
activity.pause()
|
|
161
|
+
activity.resume()
|
|
162
|
+
|
|
163
|
+
// End tracking - sends ActivityCompletedEvent + TimeSpentEvent to server
|
|
164
|
+
await activity.end()
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Identity Modes
|
|
168
|
+
|
|
169
|
+
### Timeback SSO
|
|
170
|
+
|
|
171
|
+
Uses Timeback as the identity provider via OIDC. Users sign in through Timeback's authentication flow.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
identity: {
|
|
175
|
+
mode: 'sso',
|
|
176
|
+
clientId: process.env.TIMEBACK_SSO_CLIENT_ID!,
|
|
177
|
+
clientSecret: process.env.TIMEBACK_SSO_CLIENT_SECRET!,
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Custom Identity
|
|
182
|
+
|
|
183
|
+
For apps with existing authentication (Clerk, Auth0, Supabase, etc.), provide a `getUser` function that returns the current user.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
identity: {
|
|
187
|
+
mode: 'custom',
|
|
188
|
+
getUser: async (req) => {
|
|
189
|
+
// Use your existing auth system
|
|
190
|
+
const session = await clerk.getSession(req)
|
|
191
|
+
return {
|
|
192
|
+
id: session.userId,
|
|
193
|
+
email: session.user.email,
|
|
194
|
+
name: session.user.name,
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## API Reference
|
|
201
|
+
|
|
202
|
+
### Server
|
|
203
|
+
|
|
204
|
+
- `createTimeback(config)` - Create a Timeback server instance
|
|
205
|
+
- `timeback.handlers()` - Get Next.js route handlers
|
|
206
|
+
|
|
207
|
+
### Client
|
|
208
|
+
|
|
209
|
+
- `createTimebackClient(config?)` - Create a Timeback client
|
|
210
|
+
- `client.startActivity(params)` - Start tracking an activity
|
|
211
|
+
- `client.signIn()` - Initiate SSO sign-in
|
|
212
|
+
- `client.signOut()` - Sign out
|
|
213
|
+
- `client.fetchSession()` - Fetch current session
|
|
214
|
+
|
|
215
|
+
### React
|
|
216
|
+
|
|
217
|
+
- `TimebackProvider` - Context provider
|
|
218
|
+
- `useTimeback()` - Hook for identity state and actions
|
|
219
|
+
- `useActivity(params)` - Hook for activity tracking with lifecycle management
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sign In with Timeback Button
|
|
3
|
+
*
|
|
4
|
+
* A pre-styled button for Timeback SSO authentication.
|
|
5
|
+
* Fully customizable via CSS variables.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
/**
|
|
9
|
+
* Props for SignInButton component.
|
|
10
|
+
*/
|
|
11
|
+
export interface SignInButtonProps {
|
|
12
|
+
/** Button text (default: "Sign in with Timeback") */
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
/** Additional CSS class names */
|
|
15
|
+
className?: string;
|
|
16
|
+
/** Inline styles */
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
/** Disabled state */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
/** Show loading spinner when clicked */
|
|
21
|
+
showLoading?: boolean;
|
|
22
|
+
/** Called before redirect (can prevent with e.preventDefault()) */
|
|
23
|
+
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
24
|
+
/** Button variant */
|
|
25
|
+
variant?: 'default' | 'outline' | 'minimal';
|
|
26
|
+
/** Button size */
|
|
27
|
+
size?: 'sm' | 'md' | 'lg';
|
|
28
|
+
/** Show Timeback logo */
|
|
29
|
+
showLogo?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Sign In with Timeback button component.
|
|
33
|
+
*
|
|
34
|
+
* Triggers SSO authentication flow when clicked.
|
|
35
|
+
*
|
|
36
|
+
* @param props - Component props
|
|
37
|
+
* @returns Button element
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* // Basic usage
|
|
42
|
+
* <SignInButton />
|
|
43
|
+
*
|
|
44
|
+
* // Custom text
|
|
45
|
+
* <SignInButton>Continue with Timeback</SignInButton>
|
|
46
|
+
*
|
|
47
|
+
* // Outline variant
|
|
48
|
+
* <SignInButton variant="outline" />
|
|
49
|
+
*
|
|
50
|
+
* // Custom styling via CSS variables
|
|
51
|
+
* <SignInButton
|
|
52
|
+
* style={{
|
|
53
|
+
* '--tb-btn-bg': '#6366f1',
|
|
54
|
+
* '--tb-btn-bg-hover': '#4f46e5',
|
|
55
|
+
* } as React.CSSProperties}
|
|
56
|
+
* />
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function SignInButton(props: SignInButtonProps): React.ReactElement;
|
|
60
|
+
//# sourceMappingURL=SignInButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignInButton.d.ts","sourceRoot":"","sources":["../../../../src/client/adapters/react/SignInButton.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAC3B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,wCAAwC;IACxC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mEAAmE;IACnE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IAC1D,qBAAqB;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;IAC3C,kBAAkB;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB;AA8MD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CA4DzE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Client Module
|
|
3
|
+
*
|
|
4
|
+
* React-specific exports for Timeback SDK.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { TimebackProvider, useTimeback, SignInButton } from 'timeback/react'
|
|
9
|
+
*
|
|
10
|
+
* function App() {
|
|
11
|
+
* return (
|
|
12
|
+
* <TimebackProvider>
|
|
13
|
+
* <MyComponent />
|
|
14
|
+
* </TimebackProvider>
|
|
15
|
+
* )
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* function MyComponent() {
|
|
19
|
+
* const timeback = useTimeback()
|
|
20
|
+
*
|
|
21
|
+
* const handleSignIn = () => timeback?.auth.signIn()
|
|
22
|
+
*
|
|
23
|
+
* const handleFetchProfile = async () => {
|
|
24
|
+
* const profile = await timeback?.user.fetch()
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* const handleStartActivity = () => {
|
|
28
|
+
* const activity = timeback?.activity.new({ id: 'lesson-1', name: 'Intro', courseCode: 'MATH' })
|
|
29
|
+
* activity?.start()
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* return <SignInButton />
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export { createClient } from '../../timeback-client';
|
|
37
|
+
export { TimebackClient } from '../../timeback-client.class';
|
|
38
|
+
export { Activity } from '../../lib/activity';
|
|
39
|
+
export { TimebackProvider, useTimeback } from './provider';
|
|
40
|
+
export { SignInButton } from './SignInButton';
|
|
41
|
+
export type { SignInButtonProps } from './SignInButton';
|
|
42
|
+
export type { TimebackUser, ActivityParams, ActivityMetrics } from '../../../shared/types';
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/client/adapters/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAG5D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAG7C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAGvD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA"}
|