sunsama-api 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/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/cjs/client/index.js +347 -0
- package/dist/cjs/client/index.js.map +1 -0
- package/dist/cjs/errors/index.js +110 -0
- package/dist/cjs/errors/index.js.map +1 -0
- package/dist/cjs/index.js +21 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/queries/fragments/index.js +9 -0
- package/dist/cjs/queries/fragments/index.js.map +1 -0
- package/dist/cjs/queries/fragments/stream.js +74 -0
- package/dist/cjs/queries/fragments/stream.js.map +1 -0
- package/dist/cjs/queries/fragments/task.js +500 -0
- package/dist/cjs/queries/fragments/task.js.map +1 -0
- package/dist/cjs/queries/index.js +11 -0
- package/dist/cjs/queries/index.js.map +1 -0
- package/dist/cjs/queries/streams.js +19 -0
- package/dist/cjs/queries/streams.js.map +1 -0
- package/dist/cjs/queries/tasks.js +41 -0
- package/dist/cjs/queries/tasks.js.map +1 -0
- package/dist/cjs/queries/user.js +472 -0
- package/dist/cjs/queries/user.js.map +1 -0
- package/dist/cjs/types/api.js +9 -0
- package/dist/cjs/types/api.js.map +1 -0
- package/dist/cjs/types/client.js +6 -0
- package/dist/cjs/types/client.js.map +1 -0
- package/dist/cjs/types/common.js +6 -0
- package/dist/cjs/types/common.js.map +1 -0
- package/dist/cjs/types/index.js +8 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/utils/index.js +63 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/esm/client/index.js +348 -0
- package/dist/esm/client/index.js.map +1 -0
- package/dist/esm/errors/index.js +105 -0
- package/dist/esm/errors/index.js.map +1 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/queries/fragments/index.js +6 -0
- package/dist/esm/queries/fragments/index.js.map +1 -0
- package/dist/esm/queries/fragments/stream.js +71 -0
- package/dist/esm/queries/fragments/stream.js.map +1 -0
- package/dist/esm/queries/fragments/task.js +497 -0
- package/dist/esm/queries/fragments/task.js.map +1 -0
- package/dist/esm/queries/index.js +8 -0
- package/dist/esm/queries/index.js.map +1 -0
- package/dist/esm/queries/streams.js +16 -0
- package/dist/esm/queries/streams.js.map +1 -0
- package/dist/esm/queries/tasks.js +38 -0
- package/dist/esm/queries/tasks.js.map +1 -0
- package/dist/esm/queries/user.js +469 -0
- package/dist/esm/queries/user.js.map +1 -0
- package/dist/esm/types/api.js +8 -0
- package/dist/esm/types/api.js.map +1 -0
- package/dist/esm/types/client.js +5 -0
- package/dist/esm/types/client.js.map +1 -0
- package/dist/esm/types/common.js +5 -0
- package/dist/esm/types/common.js.map +1 -0
- package/dist/esm/types/index.js +7 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/esm/utils/index.js +57 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/types/client/index.d.ts +109 -0
- package/dist/types/client/index.d.ts.map +1 -0
- package/dist/types/errors/index.d.ts +67 -0
- package/dist/types/errors/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/queries/fragments/index.d.ts +6 -0
- package/dist/types/queries/fragments/index.d.ts.map +1 -0
- package/dist/types/queries/fragments/stream.d.ts +5 -0
- package/dist/types/queries/fragments/stream.d.ts.map +1 -0
- package/dist/types/queries/fragments/task.d.ts +8 -0
- package/dist/types/queries/fragments/task.d.ts.map +1 -0
- package/dist/types/queries/index.d.ts +8 -0
- package/dist/types/queries/index.d.ts.map +1 -0
- package/dist/types/queries/streams.d.ts +5 -0
- package/dist/types/queries/streams.d.ts.map +1 -0
- package/dist/types/queries/tasks.d.ts +6 -0
- package/dist/types/queries/tasks.d.ts.map +1 -0
- package/dist/types/queries/user.d.ts +5 -0
- package/dist/types/queries/user.d.ts.map +1 -0
- package/dist/types/types/api.d.ts +838 -0
- package/dist/types/types/api.d.ts.map +1 -0
- package/dist/types/types/client.d.ts +30 -0
- package/dist/types/types/client.d.ts.map +1 -0
- package/dist/types/types/common.d.ts +58 -0
- package/dist/types/types/common.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +9 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +35 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/package.json +90 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Robert Niimi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Sunsama API TypeScript Wrapper
|
|
2
|
+
|
|
3
|
+
A comprehensive TypeScript wrapper for the Sunsama API, providing type-safe access to daily planning and task management functionality.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/sunsama-api)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](http://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- 🔒 **Type Safety**: Full TypeScript support with comprehensive type definitions
|
|
12
|
+
- 🚀 **Modern**: Built with modern JavaScript/TypeScript practices
|
|
13
|
+
- 📦 **Lightweight**: Minimal dependencies and optimized bundle size
|
|
14
|
+
- 🔧 **Developer Friendly**: Intuitive API design with excellent IDE support
|
|
15
|
+
- ✅ **Well Tested**: Comprehensive test coverage with Vitest
|
|
16
|
+
- 📚 **Documented**: Complete API documentation and examples
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install sunsama-api
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
yarn add sunsama-api
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm add sunsama-api
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { SunsamaClient } from 'sunsama-api';
|
|
36
|
+
|
|
37
|
+
// Initialize the client
|
|
38
|
+
const client = new SunsamaClient();
|
|
39
|
+
|
|
40
|
+
// Example usage
|
|
41
|
+
async function example() {
|
|
42
|
+
try {
|
|
43
|
+
// Authenticate with email/password
|
|
44
|
+
await client.login('your-email@example.com', 'your-password');
|
|
45
|
+
|
|
46
|
+
// Get current user information
|
|
47
|
+
const user = await client.getUser();
|
|
48
|
+
console.log('User:', user.profile.firstname, user.profile.lastname);
|
|
49
|
+
|
|
50
|
+
// Get tasks for today
|
|
51
|
+
const today = new Date().toISOString().split('T')[0];
|
|
52
|
+
const tasks = await client.getTasksByDay(today);
|
|
53
|
+
console.log('Today\'s tasks:', tasks.length);
|
|
54
|
+
|
|
55
|
+
// Get backlog tasks
|
|
56
|
+
const backlog = await client.getTasksBacklog();
|
|
57
|
+
console.log('Backlog tasks:', backlog.length);
|
|
58
|
+
|
|
59
|
+
// Get streams/projects
|
|
60
|
+
const streams = await client.getStreamsByGroupId();
|
|
61
|
+
console.log('Streams:', streams.length);
|
|
62
|
+
|
|
63
|
+
// Get user's timezone
|
|
64
|
+
const timezone = await client.getUserTimezone();
|
|
65
|
+
console.log('Timezone:', timezone);
|
|
66
|
+
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error('Error:', error);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API Documentation
|
|
74
|
+
|
|
75
|
+
Full API documentation is available at [docs link - to be added].
|
|
76
|
+
|
|
77
|
+
## Authentication
|
|
78
|
+
|
|
79
|
+
The client uses email/password authentication or session tokens:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Method 1: Email/Password authentication
|
|
83
|
+
const client = new SunsamaClient();
|
|
84
|
+
await client.login('your-email@example.com', 'your-password');
|
|
85
|
+
|
|
86
|
+
// Method 2: Session token (if you have one)
|
|
87
|
+
const client = new SunsamaClient({
|
|
88
|
+
sessionToken: 'your-session-token'
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Check authentication status
|
|
92
|
+
const isAuth = await client.isAuthenticated();
|
|
93
|
+
console.log('Authenticated:', isAuth);
|
|
94
|
+
|
|
95
|
+
// Logout
|
|
96
|
+
client.logout();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## API Methods
|
|
100
|
+
|
|
101
|
+
The client provides the following methods:
|
|
102
|
+
|
|
103
|
+
### User Information
|
|
104
|
+
```typescript
|
|
105
|
+
// Get current user details
|
|
106
|
+
const user = await client.getUser();
|
|
107
|
+
console.log(user.profile.firstname, user.profile.lastname);
|
|
108
|
+
|
|
109
|
+
// Get user's timezone
|
|
110
|
+
const timezone = await client.getUserTimezone();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Tasks
|
|
114
|
+
```typescript
|
|
115
|
+
// Get tasks for a specific day
|
|
116
|
+
const tasks = await client.getTasksByDay('2025-01-15');
|
|
117
|
+
const tasksWithTz = await client.getTasksByDay('2025-01-15', 'America/New_York');
|
|
118
|
+
|
|
119
|
+
// Get backlog tasks
|
|
120
|
+
const backlog = await client.getTasksBacklog();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Streams (Channels)
|
|
124
|
+
```typescript
|
|
125
|
+
// Get all streams for the user's group
|
|
126
|
+
const streams = await client.getStreamsByGroupId();
|
|
127
|
+
streams.forEach(stream => {
|
|
128
|
+
console.log(stream.streamName, stream.color);
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Error Handling
|
|
133
|
+
|
|
134
|
+
The wrapper provides structured error handling:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { SunsamaError, SunsamaAuthError, SunsamaApiError } from 'sunsama-api';
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
await client.login('email@example.com', 'password');
|
|
141
|
+
const user = await client.getUser();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
if (error instanceof SunsamaAuthError) {
|
|
144
|
+
console.error('Authentication Error:', error.message);
|
|
145
|
+
} else if (error instanceof SunsamaApiError) {
|
|
146
|
+
console.error('API Error:', error.message, error.status);
|
|
147
|
+
} else if (error instanceof SunsamaError) {
|
|
148
|
+
console.error('Client Error:', error.message);
|
|
149
|
+
} else {
|
|
150
|
+
console.error('Unknown Error:', error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Development
|
|
156
|
+
|
|
157
|
+
This project uses modern development tools:
|
|
158
|
+
|
|
159
|
+
- **TypeScript** for type safety
|
|
160
|
+
- **Vitest** for testing
|
|
161
|
+
- **ESLint + Prettier** for code quality
|
|
162
|
+
- **pnpm** for package management
|
|
163
|
+
- **Changesets** for version management
|
|
164
|
+
|
|
165
|
+
### Setup
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Clone the repository
|
|
169
|
+
git clone https://github.com/robertn702/sunsama-api.git
|
|
170
|
+
cd sunsama-api
|
|
171
|
+
|
|
172
|
+
# Install dependencies
|
|
173
|
+
pnpm install
|
|
174
|
+
|
|
175
|
+
# Run tests
|
|
176
|
+
pnpm test
|
|
177
|
+
|
|
178
|
+
# Build the package
|
|
179
|
+
pnpm build
|
|
180
|
+
|
|
181
|
+
# Run linting
|
|
182
|
+
pnpm lint
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Scripts
|
|
186
|
+
|
|
187
|
+
- `pnpm build` - Build the package for distribution
|
|
188
|
+
- `pnpm dev` - Start development mode with watch
|
|
189
|
+
- `pnpm test` - Run the test suite
|
|
190
|
+
- `pnpm test:coverage` - Run tests with coverage report
|
|
191
|
+
- `pnpm lint` - Lint the codebase
|
|
192
|
+
- `pnpm format` - Format code with Prettier
|
|
193
|
+
|
|
194
|
+
## Contributing
|
|
195
|
+
|
|
196
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
201
|
+
|
|
202
|
+
## Disclaimer
|
|
203
|
+
|
|
204
|
+
This is an unofficial wrapper for the Sunsama API. It is not affiliated with or endorsed by Sunsama.
|
|
205
|
+
|
|
206
|
+
## Support
|
|
207
|
+
|
|
208
|
+
If you encounter any issues or have questions:
|
|
209
|
+
|
|
210
|
+
1. Search [existing issues](https://github.com/robertn702/sunsama-api/issues)
|
|
211
|
+
2. Create a [new issue](https://github.com/robertn702/sunsama-api/issues/new)
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
Made with ❤️ for the Sunsama community
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Main Sunsama API client
|
|
4
|
+
*
|
|
5
|
+
* Provides a type-safe interface to interact with all Sunsama API endpoints.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.SunsamaClient = void 0;
|
|
9
|
+
const graphql_1 = require("graphql");
|
|
10
|
+
const tough_cookie_1 = require("tough-cookie");
|
|
11
|
+
const errors_1 = require("../errors");
|
|
12
|
+
const queries_1 = require("../queries");
|
|
13
|
+
/**
|
|
14
|
+
* Main Sunsama API client class
|
|
15
|
+
*
|
|
16
|
+
* Provides a type-safe interface to interact with all Sunsama API endpoints.
|
|
17
|
+
*/
|
|
18
|
+
class SunsamaClient {
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new Sunsama client instance
|
|
21
|
+
*
|
|
22
|
+
* @param config - Client configuration options (optional)
|
|
23
|
+
*/
|
|
24
|
+
constructor(config = {}) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.cookieJar = new tough_cookie_1.CookieJar();
|
|
27
|
+
// If a session token is provided, set it as a cookie
|
|
28
|
+
if (config.sessionToken) {
|
|
29
|
+
this.setSessionTokenAsCookie(config.sessionToken);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Gets the current client configuration
|
|
34
|
+
*/
|
|
35
|
+
getConfig() {
|
|
36
|
+
return { ...this.config };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checks if the client is authenticated
|
|
40
|
+
*
|
|
41
|
+
* @returns True if cookies are present in the jar
|
|
42
|
+
*/
|
|
43
|
+
async isAuthenticated() {
|
|
44
|
+
const cookies = await this.cookieJar.getCookies(SunsamaClient.BASE_URL);
|
|
45
|
+
return cookies.some(cookie => cookie.key === 'sunsamaSession');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Authenticates with email and password
|
|
49
|
+
*
|
|
50
|
+
* @param email - User email address
|
|
51
|
+
* @param password - User password
|
|
52
|
+
* @throws SunsamaAuthError if login fails
|
|
53
|
+
*/
|
|
54
|
+
async login(email, password) {
|
|
55
|
+
// Prepare form data
|
|
56
|
+
const formData = new URLSearchParams();
|
|
57
|
+
formData.append('email', email);
|
|
58
|
+
formData.append('password', password);
|
|
59
|
+
try {
|
|
60
|
+
// For login, we need to handle redirects manually to capture the session cookie
|
|
61
|
+
const loginUrl = `${SunsamaClient.BASE_URL}/account/login/email`;
|
|
62
|
+
// Get cookies from jar for this URL
|
|
63
|
+
const cookies = await this.cookieJar.getCookies(loginUrl);
|
|
64
|
+
const headers = {
|
|
65
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
66
|
+
Origin: 'https://app.sunsama.com',
|
|
67
|
+
};
|
|
68
|
+
if (cookies.length > 0) {
|
|
69
|
+
headers['Cookie'] = cookies.map(cookie => cookie.cookieString()).join('; ');
|
|
70
|
+
}
|
|
71
|
+
const response = await fetch(loginUrl, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers,
|
|
74
|
+
body: formData.toString(),
|
|
75
|
+
redirect: 'manual', // Don't follow redirects automatically
|
|
76
|
+
});
|
|
77
|
+
// For login, we expect a 302 redirect on success
|
|
78
|
+
if (response.status !== 302) {
|
|
79
|
+
const responseText = await response.text();
|
|
80
|
+
throw new errors_1.SunsamaAuthError(`Login failed: ${response.status} ${response.statusText}. Response: ${responseText}`);
|
|
81
|
+
}
|
|
82
|
+
// Extract and store cookies from response
|
|
83
|
+
const setCookieHeader = response.headers.get('set-cookie');
|
|
84
|
+
if (!setCookieHeader) {
|
|
85
|
+
// Debug: print all response headers
|
|
86
|
+
const allHeaders = {};
|
|
87
|
+
response.headers.forEach((value, key) => {
|
|
88
|
+
allHeaders[key] = value;
|
|
89
|
+
});
|
|
90
|
+
throw new errors_1.SunsamaAuthError(`No session cookie received from login. Response headers: ${JSON.stringify(allHeaders, null, 2)}`);
|
|
91
|
+
}
|
|
92
|
+
// Store the cookie in the jar
|
|
93
|
+
try {
|
|
94
|
+
const loginUrl = `${SunsamaClient.BASE_URL}/account/login/email`;
|
|
95
|
+
await this.cookieJar.setCookie(setCookieHeader, loginUrl);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
throw new errors_1.SunsamaAuthError(`Failed to store session cookie: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (error instanceof errors_1.SunsamaAuthError) {
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
throw new errors_1.SunsamaAuthError(`Login request failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Clears all cookies from the jar and cached user data
|
|
110
|
+
*/
|
|
111
|
+
logout() {
|
|
112
|
+
this.cookieJar.removeAllCookiesSync();
|
|
113
|
+
this.userId = undefined;
|
|
114
|
+
this.groupId = undefined;
|
|
115
|
+
this.timezone = undefined;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Makes an authenticated request to the Sunsama API
|
|
119
|
+
*
|
|
120
|
+
* @param path - The API endpoint path (e.g., '/tasks')
|
|
121
|
+
* @param options - Request options
|
|
122
|
+
* @returns The response from the API
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
async request(path, options) {
|
|
126
|
+
const url = `${SunsamaClient.BASE_URL}${path}`;
|
|
127
|
+
// Build headers
|
|
128
|
+
const headers = {
|
|
129
|
+
Origin: 'https://app.sunsama.com',
|
|
130
|
+
...options.headers,
|
|
131
|
+
};
|
|
132
|
+
// Get cookies from jar for this URL
|
|
133
|
+
const cookies = await this.cookieJar.getCookies(url);
|
|
134
|
+
if (cookies.length > 0) {
|
|
135
|
+
headers['Cookie'] = cookies.map(cookie => cookie.cookieString()).join('; ');
|
|
136
|
+
}
|
|
137
|
+
// Build query string if params provided
|
|
138
|
+
let fullUrl = url;
|
|
139
|
+
if (options.params) {
|
|
140
|
+
const params = new URLSearchParams();
|
|
141
|
+
Object.entries(options.params).forEach(([key, value]) => {
|
|
142
|
+
params.append(key, String(value));
|
|
143
|
+
});
|
|
144
|
+
fullUrl = `${url}?${params.toString()}`;
|
|
145
|
+
}
|
|
146
|
+
// Process request body
|
|
147
|
+
let body;
|
|
148
|
+
if (options.body instanceof URLSearchParams) {
|
|
149
|
+
body = options.body.toString();
|
|
150
|
+
}
|
|
151
|
+
else if (options.body) {
|
|
152
|
+
body = JSON.stringify(options.body);
|
|
153
|
+
}
|
|
154
|
+
// Make the request
|
|
155
|
+
return await fetch(fullUrl, {
|
|
156
|
+
method: options.method,
|
|
157
|
+
headers,
|
|
158
|
+
body,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Makes a GraphQL request to the Sunsama API
|
|
163
|
+
*
|
|
164
|
+
* @param request - The GraphQL request
|
|
165
|
+
* @returns The GraphQL response
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
async graphqlRequest(request) {
|
|
169
|
+
// Convert DocumentNode to string if needed
|
|
170
|
+
const queryString = typeof request.query === 'string' ? request.query : (0, graphql_1.print)(request.query);
|
|
171
|
+
const requestBody = {
|
|
172
|
+
...request,
|
|
173
|
+
query: queryString,
|
|
174
|
+
};
|
|
175
|
+
const response = await this.request('/graphql', {
|
|
176
|
+
method: 'POST',
|
|
177
|
+
headers: {
|
|
178
|
+
'Content-Type': 'application/json',
|
|
179
|
+
Accept: 'application/json',
|
|
180
|
+
...(request.operationName && { 'x-gql-operation-name': request.operationName }),
|
|
181
|
+
},
|
|
182
|
+
body: requestBody,
|
|
183
|
+
});
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
const responseText = await response.text();
|
|
186
|
+
throw new errors_1.SunsamaAuthError(`GraphQL request failed: ${response.status} ${response.statusText}. Response: ${responseText}`);
|
|
187
|
+
}
|
|
188
|
+
const result = (await response.json());
|
|
189
|
+
if (result.errors && result.errors.length > 0) {
|
|
190
|
+
throw new errors_1.SunsamaAuthError(`GraphQL errors: ${result.errors.map(e => e.message).join(', ')}`);
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Gets the current user information
|
|
196
|
+
*
|
|
197
|
+
* @returns The current user data
|
|
198
|
+
* @throws SunsamaAuthError if not authenticated or request fails
|
|
199
|
+
*/
|
|
200
|
+
async getUser() {
|
|
201
|
+
const request = {
|
|
202
|
+
operationName: 'getUser',
|
|
203
|
+
variables: {},
|
|
204
|
+
query: queries_1.GET_USER_QUERY,
|
|
205
|
+
};
|
|
206
|
+
const response = await this.graphqlRequest(request);
|
|
207
|
+
if (!response.data) {
|
|
208
|
+
throw new errors_1.SunsamaAuthError('No user data received');
|
|
209
|
+
}
|
|
210
|
+
const user = response.data.currentUser;
|
|
211
|
+
// Cache user ID, group ID, and timezone for future requests
|
|
212
|
+
this.userId = user._id;
|
|
213
|
+
this.groupId = user.primaryGroup?.groupId;
|
|
214
|
+
this.timezone = user.profile.timezone;
|
|
215
|
+
return user;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Gets tasks for a specific day
|
|
219
|
+
*
|
|
220
|
+
* @param day - ISO date string (e.g., "2025-05-31")
|
|
221
|
+
* @param timezone - Timezone string (e.g., "America/New_York", defaults to user's timezone)
|
|
222
|
+
* @returns Array of tasks for the specified day
|
|
223
|
+
* @throws SunsamaAuthError if not authenticated or request fails
|
|
224
|
+
*/
|
|
225
|
+
async getTasksByDay(day, timezone) {
|
|
226
|
+
// Use cached values if available, otherwise fetch user data
|
|
227
|
+
if (!this.userId || !this.groupId) {
|
|
228
|
+
await this.getUser();
|
|
229
|
+
}
|
|
230
|
+
const userTimezone = timezone || this.timezone || 'UTC';
|
|
231
|
+
if (!this.groupId) {
|
|
232
|
+
throw new errors_1.SunsamaAuthError('Unable to determine group ID from user data. User primaryGroup is required.');
|
|
233
|
+
}
|
|
234
|
+
const variables = {
|
|
235
|
+
day,
|
|
236
|
+
timezone: userTimezone,
|
|
237
|
+
userId: this.userId,
|
|
238
|
+
groupId: this.groupId,
|
|
239
|
+
};
|
|
240
|
+
const request = {
|
|
241
|
+
operationName: 'getTasksByDay',
|
|
242
|
+
variables: { input: variables },
|
|
243
|
+
query: queries_1.GET_TASKS_BY_DAY_QUERY,
|
|
244
|
+
};
|
|
245
|
+
const response = await this.graphqlRequest(request);
|
|
246
|
+
if (!response.data) {
|
|
247
|
+
throw new errors_1.SunsamaAuthError('No task data received');
|
|
248
|
+
}
|
|
249
|
+
return response.data.tasksByDayV2;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Gets tasks from the backlog
|
|
253
|
+
*
|
|
254
|
+
* @returns Array of backlog tasks
|
|
255
|
+
* @throws SunsamaAuthError if not authenticated or request fails
|
|
256
|
+
*/
|
|
257
|
+
async getTasksBacklog() {
|
|
258
|
+
// Use cached values if available, otherwise fetch user data
|
|
259
|
+
if (!this.userId || !this.groupId) {
|
|
260
|
+
await this.getUser();
|
|
261
|
+
}
|
|
262
|
+
if (!this.groupId) {
|
|
263
|
+
throw new errors_1.SunsamaAuthError('Unable to determine group ID from user data. User primaryGroup is required.');
|
|
264
|
+
}
|
|
265
|
+
const variables = {
|
|
266
|
+
userId: this.userId,
|
|
267
|
+
groupId: this.groupId,
|
|
268
|
+
};
|
|
269
|
+
const request = {
|
|
270
|
+
operationName: 'getTasksBacklog',
|
|
271
|
+
variables,
|
|
272
|
+
query: queries_1.GET_TASKS_BACKLOG_QUERY,
|
|
273
|
+
};
|
|
274
|
+
const response = await this.graphqlRequest(request);
|
|
275
|
+
if (!response.data) {
|
|
276
|
+
throw new errors_1.SunsamaAuthError('No backlog data received');
|
|
277
|
+
}
|
|
278
|
+
return response.data.tasksBacklog;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Gets streams for the user's group
|
|
282
|
+
*
|
|
283
|
+
* @returns Array of streams for the user's group
|
|
284
|
+
* @throws SunsamaAuthError if not authenticated or request fails
|
|
285
|
+
*/
|
|
286
|
+
async getStreamsByGroupId() {
|
|
287
|
+
// Use cached values if available, otherwise fetch user data
|
|
288
|
+
if (!this.groupId) {
|
|
289
|
+
await this.getUser();
|
|
290
|
+
}
|
|
291
|
+
if (!this.groupId) {
|
|
292
|
+
throw new errors_1.SunsamaAuthError('Unable to determine group ID from user data. User primaryGroup is required.');
|
|
293
|
+
}
|
|
294
|
+
const request = {
|
|
295
|
+
operationName: 'getStreamsByGroupId',
|
|
296
|
+
variables: { groupId: this.groupId },
|
|
297
|
+
query: queries_1.GET_STREAMS_BY_GROUP_ID_QUERY,
|
|
298
|
+
};
|
|
299
|
+
const response = await this.graphqlRequest(request);
|
|
300
|
+
if (!response.data) {
|
|
301
|
+
throw new errors_1.SunsamaAuthError('No stream data received');
|
|
302
|
+
}
|
|
303
|
+
return response.data.streamsByGroupId;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Gets the user's timezone
|
|
307
|
+
*
|
|
308
|
+
* @returns The user's timezone string (e.g., "America/New_York")
|
|
309
|
+
* @throws SunsamaAuthError if not authenticated or request fails
|
|
310
|
+
*/
|
|
311
|
+
async getUserTimezone() {
|
|
312
|
+
// Use cached timezone if available, otherwise fetch user data
|
|
313
|
+
if (!this.timezone) {
|
|
314
|
+
await this.getUser();
|
|
315
|
+
}
|
|
316
|
+
if (!this.timezone) {
|
|
317
|
+
throw new errors_1.SunsamaAuthError('Unable to determine timezone from user data. User profile.timezone is required.');
|
|
318
|
+
}
|
|
319
|
+
return this.timezone;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Sets a session token as a cookie in the jar
|
|
323
|
+
*
|
|
324
|
+
* @param token - The session token to set
|
|
325
|
+
* @internal
|
|
326
|
+
*/
|
|
327
|
+
setSessionTokenAsCookie(token) {
|
|
328
|
+
try {
|
|
329
|
+
const cookie = new tough_cookie_1.Cookie({
|
|
330
|
+
key: 'sunsamaSession',
|
|
331
|
+
value: token,
|
|
332
|
+
domain: 'api.sunsama.com',
|
|
333
|
+
path: '/',
|
|
334
|
+
httpOnly: true,
|
|
335
|
+
secure: true,
|
|
336
|
+
});
|
|
337
|
+
this.cookieJar.setCookieSync(cookie, SunsamaClient.BASE_URL);
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
// Silently fail if cookie cannot be set
|
|
341
|
+
// Note: Error intentionally ignored to avoid breaking authentication flow
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
exports.SunsamaClient = SunsamaClient;
|
|
346
|
+
SunsamaClient.BASE_URL = 'https://api.sunsama.com';
|
|
347
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|