@bmhall2/skylight-mcp 1.1.7
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 +265 -0
- package/dist/api/auth.d.ts +38 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +62 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/client.d.ts +84 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +228 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/endpoints/calendar.d.ts +33 -0
- package/dist/api/endpoints/calendar.d.ts.map +1 -0
- package/dist/api/endpoints/calendar.js +60 -0
- package/dist/api/endpoints/calendar.js.map +1 -0
- package/dist/api/endpoints/categories.d.ts +23 -0
- package/dist/api/endpoints/categories.d.ts.map +1 -0
- package/dist/api/endpoints/categories.js +48 -0
- package/dist/api/endpoints/categories.js.map +1 -0
- package/dist/api/endpoints/chores.d.ts +50 -0
- package/dist/api/endpoints/chores.d.ts.map +1 -0
- package/dist/api/endpoints/chores.js +106 -0
- package/dist/api/endpoints/chores.js.map +1 -0
- package/dist/api/endpoints/devices.d.ts +6 -0
- package/dist/api/endpoints/devices.d.ts.map +1 -0
- package/dist/api/endpoints/devices.js +10 -0
- package/dist/api/endpoints/devices.js.map +1 -0
- package/dist/api/endpoints/frames.d.ts +6 -0
- package/dist/api/endpoints/frames.d.ts.map +1 -0
- package/dist/api/endpoints/frames.js +10 -0
- package/dist/api/endpoints/frames.js.map +1 -0
- package/dist/api/endpoints/lists.d.ts +55 -0
- package/dist/api/endpoints/lists.d.ts.map +1 -0
- package/dist/api/endpoints/lists.js +125 -0
- package/dist/api/endpoints/lists.js.map +1 -0
- package/dist/api/endpoints/meals.d.ts +102 -0
- package/dist/api/endpoints/meals.d.ts.map +1 -0
- package/dist/api/endpoints/meals.js +100 -0
- package/dist/api/endpoints/meals.js.map +1 -0
- package/dist/api/endpoints/misc.d.ts +27 -0
- package/dist/api/endpoints/misc.d.ts.map +1 -0
- package/dist/api/endpoints/misc.js +18 -0
- package/dist/api/endpoints/misc.js.map +1 -0
- package/dist/api/endpoints/photos.d.ts +13 -0
- package/dist/api/endpoints/photos.d.ts.map +1 -0
- package/dist/api/endpoints/photos.js +10 -0
- package/dist/api/endpoints/photos.js.map +1 -0
- package/dist/api/endpoints/rewards.d.ts +49 -0
- package/dist/api/endpoints/rewards.d.ts.map +1 -0
- package/dist/api/endpoints/rewards.js +105 -0
- package/dist/api/endpoints/rewards.js.map +1 -0
- package/dist/api/endpoints/taskbox.d.ts +13 -0
- package/dist/api/endpoints/taskbox.d.ts.map +1 -0
- package/dist/api/endpoints/taskbox.js +22 -0
- package/dist/api/endpoints/taskbox.js.map +1 -0
- package/dist/api/generated-types.d.ts +18967 -0
- package/dist/api/generated-types.d.ts.map +1 -0
- package/dist/api/generated-types.js +6 -0
- package/dist/api/generated-types.js.map +1 -0
- package/dist/api/types.d.ts +283 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +5 -0
- package/dist/api/types.js.map +1 -0
- package/dist/config.d.ts +52 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +80 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +48 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/calendar.d.ts +3 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +297 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/chores.d.ts +3 -0
- package/dist/tools/chores.d.ts.map +1 -0
- package/dist/tools/chores.js +349 -0
- package/dist/tools/chores.js.map +1 -0
- package/dist/tools/family.d.ts +3 -0
- package/dist/tools/family.d.ts.map +1 -0
- package/dist/tools/family.js +182 -0
- package/dist/tools/family.js.map +1 -0
- package/dist/tools/lists.d.ts +3 -0
- package/dist/tools/lists.d.ts.map +1 -0
- package/dist/tools/lists.js +481 -0
- package/dist/tools/lists.js.map +1 -0
- package/dist/tools/meals.d.ts +3 -0
- package/dist/tools/meals.d.ts.map +1 -0
- package/dist/tools/meals.js +319 -0
- package/dist/tools/meals.js.map +1 -0
- package/dist/tools/misc.d.ts +3 -0
- package/dist/tools/misc.d.ts.map +1 -0
- package/dist/tools/misc.js +101 -0
- package/dist/tools/misc.js.map +1 -0
- package/dist/tools/photos.d.ts +3 -0
- package/dist/tools/photos.d.ts.map +1 -0
- package/dist/tools/photos.js +42 -0
- package/dist/tools/photos.js.map +1 -0
- package/dist/tools/rewards.d.ts +3 -0
- package/dist/tools/rewards.d.ts.map +1 -0
- package/dist/tools/rewards.js +338 -0
- package/dist/tools/rewards.js.map +1 -0
- package/dist/tools/tasks.d.ts +3 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +68 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/utils/dates.d.ts +26 -0
- package/dist/utils/dates.d.ts.map +1 -0
- package/dist/utils/dates.js +109 -0
- package/dist/utils/dates.js.map +1 -0
- package/dist/utils/errors.d.ts +45 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +102 -0
- package/dist/utils/errors.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { getConfig, usesEmailAuth } from "../config.js";
|
|
2
|
+
import { login } from "./auth.js";
|
|
3
|
+
import { AuthenticationError, NotFoundError, RateLimitError, SkylightError, } from "../utils/errors.js";
|
|
4
|
+
const BASE_URL = "https://app.ourskylight.com";
|
|
5
|
+
/**
|
|
6
|
+
* Skylight API Client
|
|
7
|
+
* Handles authentication and HTTP requests to the Skylight API
|
|
8
|
+
*/
|
|
9
|
+
export class SkylightClient {
|
|
10
|
+
config;
|
|
11
|
+
resolvedToken = null;
|
|
12
|
+
resolvedUserId = null;
|
|
13
|
+
loginPromise = null;
|
|
14
|
+
subscriptionStatus = null;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config ?? getConfig();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the authentication credentials
|
|
20
|
+
* If using email/password auth, will login first
|
|
21
|
+
*/
|
|
22
|
+
async getCredentials() {
|
|
23
|
+
// If we already have a resolved token, use it
|
|
24
|
+
if (this.resolvedToken) {
|
|
25
|
+
return { token: this.resolvedToken, userId: this.resolvedUserId };
|
|
26
|
+
}
|
|
27
|
+
// If using token-based auth, use the configured token
|
|
28
|
+
if (!usesEmailAuth(this.config)) {
|
|
29
|
+
return { token: this.config.token, userId: null };
|
|
30
|
+
}
|
|
31
|
+
// If already logging in, wait for that to complete
|
|
32
|
+
if (this.loginPromise) {
|
|
33
|
+
const result = await this.loginPromise;
|
|
34
|
+
return { token: result.token, userId: result.userId };
|
|
35
|
+
}
|
|
36
|
+
// Login with email/password
|
|
37
|
+
this.loginPromise = this.performLogin();
|
|
38
|
+
try {
|
|
39
|
+
const result = await this.loginPromise;
|
|
40
|
+
this.resolvedToken = result.token;
|
|
41
|
+
this.resolvedUserId = result.userId;
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
this.loginPromise = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Perform login and return token and userId
|
|
50
|
+
*/
|
|
51
|
+
async performLogin() {
|
|
52
|
+
const { email, password } = this.config;
|
|
53
|
+
if (!email || !password) {
|
|
54
|
+
throw new AuthenticationError("Email and password are required for login");
|
|
55
|
+
}
|
|
56
|
+
console.error("Logging in to Skylight...");
|
|
57
|
+
const result = await login(email, password);
|
|
58
|
+
this.subscriptionStatus = result.subscriptionStatus;
|
|
59
|
+
console.error(`Logged in as ${result.email} (${result.subscriptionStatus})`);
|
|
60
|
+
return { token: result.token, userId: result.userId };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the Authorization header
|
|
64
|
+
* For email/password auth: Basic base64(userId:token)
|
|
65
|
+
* For manual token auth: Bearer or Basic based on config
|
|
66
|
+
*/
|
|
67
|
+
async getAuthHeader() {
|
|
68
|
+
const { token, userId } = await this.getCredentials();
|
|
69
|
+
// If using email/password auth, use Basic auth with userId:token
|
|
70
|
+
if (usesEmailAuth(this.config) && userId) {
|
|
71
|
+
const credentials = Buffer.from(`${userId}:${token}`).toString("base64");
|
|
72
|
+
return `Basic ${credentials}`;
|
|
73
|
+
}
|
|
74
|
+
// For manual token config, respect the authType setting
|
|
75
|
+
if (this.config.authType === "basic") {
|
|
76
|
+
return `Basic ${token}`;
|
|
77
|
+
}
|
|
78
|
+
return `Bearer ${token}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build URL with query parameters
|
|
82
|
+
*/
|
|
83
|
+
buildUrl(endpoint, params) {
|
|
84
|
+
const url = new URL(endpoint, BASE_URL);
|
|
85
|
+
if (params) {
|
|
86
|
+
for (const [key, value] of Object.entries(params)) {
|
|
87
|
+
if (value !== undefined) {
|
|
88
|
+
url.searchParams.set(key, String(value));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return url.toString();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Handle API response errors
|
|
96
|
+
*/
|
|
97
|
+
async handleResponseError(response, url) {
|
|
98
|
+
const status = response.status;
|
|
99
|
+
if (status === 401) {
|
|
100
|
+
// Clear cached credentials on auth failure
|
|
101
|
+
this.resolvedToken = null;
|
|
102
|
+
this.resolvedUserId = null;
|
|
103
|
+
console.error(`[client] 401 Unauthorized for ${url}`);
|
|
104
|
+
if (usesEmailAuth(this.config)) {
|
|
105
|
+
throw new AuthenticationError("API request returned 401. This may indicate your frame ID is incorrect or doesn't belong to this account. " +
|
|
106
|
+
"Please verify your SKYLIGHT_FRAME_ID environment variable.");
|
|
107
|
+
}
|
|
108
|
+
throw new AuthenticationError();
|
|
109
|
+
}
|
|
110
|
+
if (status === 404) {
|
|
111
|
+
throw new NotFoundError("Resource");
|
|
112
|
+
}
|
|
113
|
+
if (status === 429) {
|
|
114
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
115
|
+
throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : undefined);
|
|
116
|
+
}
|
|
117
|
+
// Try to get error details from response
|
|
118
|
+
let errorMessage = `HTTP ${status}`;
|
|
119
|
+
try {
|
|
120
|
+
const errorBody = await response.text();
|
|
121
|
+
if (errorBody) {
|
|
122
|
+
errorMessage += `: ${errorBody.slice(0, 200)}`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Ignore parse errors
|
|
127
|
+
}
|
|
128
|
+
throw new SkylightError(errorMessage, "HTTP_ERROR", status, status >= 500);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Make an authenticated request to the Skylight API
|
|
132
|
+
*/
|
|
133
|
+
async request(endpoint, options = {}, isRetry = false) {
|
|
134
|
+
const { method = "GET", params, body } = options;
|
|
135
|
+
// Replace {frameId} placeholder with actual frame ID
|
|
136
|
+
const resolvedEndpoint = endpoint.replace("{frameId}", this.config.frameId);
|
|
137
|
+
const url = this.buildUrl(resolvedEndpoint, params);
|
|
138
|
+
console.error(`[client] ${method} ${url}`);
|
|
139
|
+
const headers = {
|
|
140
|
+
Authorization: await this.getAuthHeader(),
|
|
141
|
+
Accept: "application/json",
|
|
142
|
+
};
|
|
143
|
+
if (body) {
|
|
144
|
+
headers["Content-Type"] = "application/json";
|
|
145
|
+
}
|
|
146
|
+
const response = await fetch(url, {
|
|
147
|
+
method,
|
|
148
|
+
headers,
|
|
149
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
150
|
+
});
|
|
151
|
+
console.error(`[client] Response: ${response.status}`);
|
|
152
|
+
if (!response.ok) {
|
|
153
|
+
// For email/password auth, try re-login once on 401
|
|
154
|
+
if (response.status === 401 && usesEmailAuth(this.config) && !isRetry) {
|
|
155
|
+
console.error("[client] Got 401, attempting re-login...");
|
|
156
|
+
this.resolvedToken = null;
|
|
157
|
+
this.resolvedUserId = null;
|
|
158
|
+
return this.request(endpoint, options, true);
|
|
159
|
+
}
|
|
160
|
+
await this.handleResponseError(response, url);
|
|
161
|
+
}
|
|
162
|
+
// Handle 304 Not Modified
|
|
163
|
+
if (response.status === 304) {
|
|
164
|
+
return {};
|
|
165
|
+
}
|
|
166
|
+
return response.json();
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* GET request helper
|
|
170
|
+
*/
|
|
171
|
+
async get(endpoint, params) {
|
|
172
|
+
return this.request(endpoint, { method: "GET", params });
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* POST request helper
|
|
176
|
+
*/
|
|
177
|
+
async post(endpoint, body) {
|
|
178
|
+
return this.request(endpoint, { method: "POST", body });
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get the frame ID from config
|
|
182
|
+
*/
|
|
183
|
+
get frameId() {
|
|
184
|
+
return this.config.frameId;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get the timezone from config
|
|
188
|
+
*/
|
|
189
|
+
get timezone() {
|
|
190
|
+
return this.config.timezone;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check if user has Plus subscription
|
|
194
|
+
*/
|
|
195
|
+
hasPlus() {
|
|
196
|
+
return this.subscriptionStatus === "plus";
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get the subscription status
|
|
200
|
+
*/
|
|
201
|
+
getSubscriptionStatus() {
|
|
202
|
+
return this.subscriptionStatus;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Initialize the client (triggers login if using email/password auth)
|
|
206
|
+
*/
|
|
207
|
+
async initialize() {
|
|
208
|
+
await this.getCredentials();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Singleton instance
|
|
212
|
+
let clientInstance = null;
|
|
213
|
+
export function getClient() {
|
|
214
|
+
if (!clientInstance) {
|
|
215
|
+
clientInstance = new SkylightClient();
|
|
216
|
+
}
|
|
217
|
+
return clientInstance;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Initialize the client singleton and return it
|
|
221
|
+
* This triggers login if using email/password auth
|
|
222
|
+
*/
|
|
223
|
+
export async function initializeClient() {
|
|
224
|
+
const client = getClient();
|
|
225
|
+
await client.initialize();
|
|
226
|
+
return client;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CalendarEventResource, SourceCalendarResource, CategoryResource, CreateCalendarEventRequest, UpdateCalendarEventRequest } from "../types.js";
|
|
2
|
+
export interface GetCalendarEventsOptions {
|
|
3
|
+
dateMin: string;
|
|
4
|
+
dateMax: string;
|
|
5
|
+
timezone?: string;
|
|
6
|
+
include?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CalendarEventsResult {
|
|
9
|
+
events: CalendarEventResource[];
|
|
10
|
+
categories: CategoryResource[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get calendar events for a date range
|
|
14
|
+
* Note: The API treats date_max as exclusive, so we add 1 day to include events on the end date
|
|
15
|
+
*/
|
|
16
|
+
export declare function getCalendarEvents(options: GetCalendarEventsOptions): Promise<CalendarEventsResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Get source calendars (connected calendar accounts)
|
|
19
|
+
*/
|
|
20
|
+
export declare function getSourceCalendars(): Promise<SourceCalendarResource[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a calendar event
|
|
23
|
+
*/
|
|
24
|
+
export declare function createCalendarEvent(data: CreateCalendarEventRequest): Promise<CalendarEventResource>;
|
|
25
|
+
/**
|
|
26
|
+
* Update a calendar event
|
|
27
|
+
*/
|
|
28
|
+
export declare function updateCalendarEvent(eventId: string, data: UpdateCalendarEventRequest): Promise<CalendarEventResource>;
|
|
29
|
+
/**
|
|
30
|
+
* Delete a calendar event
|
|
31
|
+
*/
|
|
32
|
+
export declare function deleteCalendarEvent(eventId: string): Promise<void>;
|
|
33
|
+
//# sourceMappingURL=calendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/calendar.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,qBAAqB,EAGrB,sBAAsB,EACtB,gBAAgB,EAChB,0BAA0B,EAC1B,0BAA0B,EAC3B,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAWD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,oBAAoB,CAAC,CAqB/B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAM5E;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAOhC;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAOhC;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Add days to a date string in YYYY-MM-DD format
|
|
4
|
+
*/
|
|
5
|
+
function addDays(dateStr, days) {
|
|
6
|
+
const date = new Date(dateStr + "T00:00:00");
|
|
7
|
+
date.setDate(date.getDate() + days);
|
|
8
|
+
return date.toISOString().split("T")[0];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get calendar events for a date range
|
|
12
|
+
* Note: The API treats date_max as exclusive, so we add 1 day to include events on the end date
|
|
13
|
+
*/
|
|
14
|
+
export async function getCalendarEvents(options) {
|
|
15
|
+
const client = getClient();
|
|
16
|
+
// API treats date_max as exclusive, so add 1 day to include events on the end date
|
|
17
|
+
const adjustedDateMax = addDays(options.dateMax, 1);
|
|
18
|
+
const response = await client.get("/api/frames/{frameId}/calendar_events", {
|
|
19
|
+
date_min: options.dateMin,
|
|
20
|
+
date_max: adjustedDateMax,
|
|
21
|
+
timezone: options.timezone ?? client.timezone,
|
|
22
|
+
include: options.include,
|
|
23
|
+
});
|
|
24
|
+
const categories = (response.included ?? []).filter((item) => item.type === "category");
|
|
25
|
+
return { events: response.data, categories };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get source calendars (connected calendar accounts)
|
|
29
|
+
*/
|
|
30
|
+
export async function getSourceCalendars() {
|
|
31
|
+
const client = getClient();
|
|
32
|
+
const response = await client.get("/api/frames/{frameId}/source_calendars");
|
|
33
|
+
return response.data;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a calendar event
|
|
37
|
+
*/
|
|
38
|
+
export async function createCalendarEvent(data) {
|
|
39
|
+
const client = getClient();
|
|
40
|
+
const response = await client.post("/api/frames/{frameId}/calendar_events", data);
|
|
41
|
+
return response.data;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Update a calendar event
|
|
45
|
+
*/
|
|
46
|
+
export async function updateCalendarEvent(eventId, data) {
|
|
47
|
+
const client = getClient();
|
|
48
|
+
const response = await client.request(`/api/frames/{frameId}/calendar_events/${eventId}`, { method: "PUT", body: data });
|
|
49
|
+
return response.data;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Delete a calendar event
|
|
53
|
+
*/
|
|
54
|
+
export async function deleteCalendarEvent(eventId) {
|
|
55
|
+
const client = getClient();
|
|
56
|
+
await client.request(`/api/frames/{frameId}/calendar_events/${eventId}`, {
|
|
57
|
+
method: "DELETE",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.js","sourceRoot":"","sources":["../../../src/api/endpoints/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAwBzC;;GAEG;AACH,SAAS,OAAO,CAAC,OAAe,EAAE,IAAY;IAC5C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAiC;IAEjC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,mFAAmF;IACnF,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAEpD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAC/B,uCAAuC,EACvC;QACE,QAAQ,EAAE,OAAO,CAAC,OAAO;QACzB,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;QAC7C,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CACF,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CACjD,CAAC,IAAI,EAA4B,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAC7D,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAC/B,wCAAwC,CACzC,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAgC;IAEhC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAChC,uCAAuC,EACvC,IAAI,CACL,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAe,EACf,IAAgC;IAEhC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CACnC,yCAAyC,OAAO,EAAE,EAClD,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAC9B,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe;IACvD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,CAAC,OAAO,CAAC,yCAAyC,OAAO,EAAE,EAAE;QACvE,MAAM,EAAE,QAAQ;KACjB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CategoryResource } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get all categories (family members/profiles)
|
|
4
|
+
*/
|
|
5
|
+
export declare function getCategories(useCache?: boolean): Promise<CategoryResource[]>;
|
|
6
|
+
/**
|
|
7
|
+
* Clear the categories cache
|
|
8
|
+
*/
|
|
9
|
+
export declare function clearCategoriesCache(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Find a category by name (case-insensitive partial match)
|
|
12
|
+
* Categories represent family members like "Dad", "Mom", "Kids", etc.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findCategoryByName(name: string): Promise<CategoryResource | undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* Get categories that are linked to profiles (actual family members)
|
|
17
|
+
*/
|
|
18
|
+
export declare function getFamilyMembers(): Promise<CategoryResource[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Get categories selected for the chore chart
|
|
21
|
+
*/
|
|
22
|
+
export declare function getChoreChartCategories(): Promise<CategoryResource[]>;
|
|
23
|
+
//# sourceMappingURL=categories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/categories.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAKxE;;GAEG;AACH,wBAAsB,aAAa,CAAC,QAAQ,UAAO,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAShF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAQ5F;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAGpE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAG3E"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
// Cache for categories (family members)
|
|
3
|
+
let categoriesCache = null;
|
|
4
|
+
/**
|
|
5
|
+
* Get all categories (family members/profiles)
|
|
6
|
+
*/
|
|
7
|
+
export async function getCategories(useCache = true) {
|
|
8
|
+
if (useCache && categoriesCache) {
|
|
9
|
+
return categoriesCache;
|
|
10
|
+
}
|
|
11
|
+
const client = getClient();
|
|
12
|
+
const response = await client.get("/api/frames/{frameId}/categories");
|
|
13
|
+
categoriesCache = response.data;
|
|
14
|
+
return response.data;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Clear the categories cache
|
|
18
|
+
*/
|
|
19
|
+
export function clearCategoriesCache() {
|
|
20
|
+
categoriesCache = null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Find a category by name (case-insensitive partial match)
|
|
24
|
+
* Categories represent family members like "Dad", "Mom", "Kids", etc.
|
|
25
|
+
*/
|
|
26
|
+
export async function findCategoryByName(name) {
|
|
27
|
+
const categories = await getCategories();
|
|
28
|
+
const lowerName = name.toLowerCase();
|
|
29
|
+
return categories.find((cat) => {
|
|
30
|
+
const label = cat.attributes.label?.toLowerCase();
|
|
31
|
+
return label && (label === lowerName || label.includes(lowerName));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get categories that are linked to profiles (actual family members)
|
|
36
|
+
*/
|
|
37
|
+
export async function getFamilyMembers() {
|
|
38
|
+
const categories = await getCategories();
|
|
39
|
+
return categories.filter((cat) => cat.attributes.linked_to_profile);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get categories selected for the chore chart
|
|
43
|
+
*/
|
|
44
|
+
export async function getChoreChartCategories() {
|
|
45
|
+
const categories = await getCategories();
|
|
46
|
+
return categories.filter((cat) => cat.attributes.selected_for_chore_chart);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=categories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.js","sourceRoot":"","sources":["../../../src/api/endpoints/categories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,wCAAwC;AACxC,IAAI,eAAe,GAA8B,IAAI,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAQ,GAAG,IAAI;IACjD,IAAI,QAAQ,IAAI,eAAe,EAAE,CAAC;QAChC,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAqB,kCAAkC,CAAC,CAAC;IAC1F,eAAe,GAAG,QAAQ,CAAC,IAAI,CAAC;IAChC,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,eAAe,GAAG,IAAI,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY;IACnD,MAAM,UAAU,GAAG,MAAM,aAAa,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAErC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;QAClD,OAAO,KAAK,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,UAAU,GAAG,MAAM,aAAa,EAAE,CAAC;IACzC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACtE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,MAAM,UAAU,GAAG,MAAM,aAAa,EAAE,CAAC;IACzC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,wBAAwB,CAAC,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ChoreResource, CategoryResource } from "../types.js";
|
|
2
|
+
export interface GetChoresOptions {
|
|
3
|
+
after?: string;
|
|
4
|
+
before?: string;
|
|
5
|
+
includeLate?: boolean;
|
|
6
|
+
filterLinkedToProfile?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface GetChoresResult {
|
|
9
|
+
chores: ChoreResource[];
|
|
10
|
+
categories: CategoryResource[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get chores for a date range
|
|
14
|
+
*/
|
|
15
|
+
export declare function getChores(options?: GetChoresOptions): Promise<GetChoresResult>;
|
|
16
|
+
export interface CreateChoreOptions {
|
|
17
|
+
summary: string;
|
|
18
|
+
start: string;
|
|
19
|
+
startTime?: string;
|
|
20
|
+
status?: string;
|
|
21
|
+
recurring?: boolean;
|
|
22
|
+
recurrenceSet?: string;
|
|
23
|
+
categoryId?: string;
|
|
24
|
+
rewardPoints?: number;
|
|
25
|
+
emojiIcon?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a new chore
|
|
29
|
+
*/
|
|
30
|
+
export declare function createChore(options: CreateChoreOptions): Promise<ChoreResource>;
|
|
31
|
+
export interface UpdateChoreOptions {
|
|
32
|
+
summary?: string;
|
|
33
|
+
start?: string;
|
|
34
|
+
startTime?: string | null;
|
|
35
|
+
status?: string;
|
|
36
|
+
recurring?: boolean;
|
|
37
|
+
recurrenceSet?: string | null;
|
|
38
|
+
categoryId?: string | null;
|
|
39
|
+
rewardPoints?: number | null;
|
|
40
|
+
emojiIcon?: string | null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Update an existing chore
|
|
44
|
+
*/
|
|
45
|
+
export declare function updateChore(choreId: string, options: UpdateChoreOptions): Promise<ChoreResource>;
|
|
46
|
+
/**
|
|
47
|
+
* Delete a chore
|
|
48
|
+
*/
|
|
49
|
+
export declare function deleteChore(choreId: string): Promise<void>;
|
|
50
|
+
//# sourceMappingURL=chores.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chores.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/chores.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,aAAa,EACb,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAqBxF;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAqCrF;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAqCxB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhE"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get chores for a date range
|
|
4
|
+
*/
|
|
5
|
+
export async function getChores(options = {}) {
|
|
6
|
+
const client = getClient();
|
|
7
|
+
const params = {
|
|
8
|
+
after: options.after,
|
|
9
|
+
before: options.before,
|
|
10
|
+
include_late: options.includeLate,
|
|
11
|
+
};
|
|
12
|
+
if (options.filterLinkedToProfile) {
|
|
13
|
+
params.filter = "linked_to_profile";
|
|
14
|
+
}
|
|
15
|
+
const response = await client.get("/api/frames/{frameId}/chores", params);
|
|
16
|
+
return {
|
|
17
|
+
chores: response.data,
|
|
18
|
+
categories: response.included ?? [],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a new chore
|
|
23
|
+
*/
|
|
24
|
+
export async function createChore(options) {
|
|
25
|
+
const client = getClient();
|
|
26
|
+
const request = {
|
|
27
|
+
data: {
|
|
28
|
+
type: "chore",
|
|
29
|
+
attributes: {
|
|
30
|
+
summary: options.summary,
|
|
31
|
+
start: options.start,
|
|
32
|
+
start_time: options.startTime ?? null,
|
|
33
|
+
status: options.status ?? "pending",
|
|
34
|
+
recurring: options.recurring ?? false,
|
|
35
|
+
recurrence_set: options.recurrenceSet ?? null,
|
|
36
|
+
reward_points: options.rewardPoints ?? null,
|
|
37
|
+
emoji_icon: options.emojiIcon ?? null,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
// Add category relationship if provided
|
|
42
|
+
if (options.categoryId) {
|
|
43
|
+
request.data.relationships = {
|
|
44
|
+
category: {
|
|
45
|
+
data: {
|
|
46
|
+
type: "category",
|
|
47
|
+
id: options.categoryId,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const response = await client.post("/api/frames/{frameId}/chores", request);
|
|
53
|
+
return response.data;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Update an existing chore
|
|
57
|
+
*/
|
|
58
|
+
export async function updateChore(choreId, options) {
|
|
59
|
+
const client = getClient();
|
|
60
|
+
const request = {
|
|
61
|
+
data: {
|
|
62
|
+
type: "chore",
|
|
63
|
+
attributes: {},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
// Map options to attributes
|
|
67
|
+
if (options.summary !== undefined)
|
|
68
|
+
request.data.attributes.summary = options.summary;
|
|
69
|
+
if (options.start !== undefined)
|
|
70
|
+
request.data.attributes.start = options.start;
|
|
71
|
+
if (options.startTime !== undefined)
|
|
72
|
+
request.data.attributes.start_time = options.startTime;
|
|
73
|
+
if (options.status !== undefined)
|
|
74
|
+
request.data.attributes.status = options.status;
|
|
75
|
+
if (options.recurring !== undefined)
|
|
76
|
+
request.data.attributes.recurring = options.recurring;
|
|
77
|
+
if (options.recurrenceSet !== undefined)
|
|
78
|
+
request.data.attributes.recurrence_set = options.recurrenceSet;
|
|
79
|
+
if (options.rewardPoints !== undefined)
|
|
80
|
+
request.data.attributes.reward_points = options.rewardPoints;
|
|
81
|
+
if (options.emojiIcon !== undefined)
|
|
82
|
+
request.data.attributes.emoji_icon = options.emojiIcon;
|
|
83
|
+
// Handle category relationship
|
|
84
|
+
if (options.categoryId !== undefined) {
|
|
85
|
+
if (options.categoryId === null) {
|
|
86
|
+
request.data.relationships = { category: { data: null } };
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
request.data.relationships = {
|
|
90
|
+
category: { data: { type: "category", id: options.categoryId } },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const response = await client.request(`/api/frames/{frameId}/chores/${choreId}`, { method: "PUT", body: request });
|
|
95
|
+
return response.data;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Delete a chore
|
|
99
|
+
*/
|
|
100
|
+
export async function deleteChore(choreId) {
|
|
101
|
+
const client = getClient();
|
|
102
|
+
await client.request(`/api/frames/{frameId}/chores/${choreId}`, {
|
|
103
|
+
method: "DELETE",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=chores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chores.js","sourceRoot":"","sources":["../../../src/api/endpoints/chores.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/devices.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,aAAa,CAAC;AAEnE;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAI5D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get all Skylight devices in the household
|
|
4
|
+
*/
|
|
5
|
+
export async function getDevices() {
|
|
6
|
+
const client = getClient();
|
|
7
|
+
const response = await client.get("/api/frames/{frameId}/devices");
|
|
8
|
+
return response.data;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=devices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.js","sourceRoot":"","sources":["../../../src/api/endpoints/devices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAkB,+BAA+B,CAAC,CAAC;IACpF,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/frames.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhE;;GAEG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,CAIvD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get frame (household) information
|
|
4
|
+
*/
|
|
5
|
+
export async function getFrame() {
|
|
6
|
+
const client = getClient();
|
|
7
|
+
const response = await client.get("/api/frames/{frameId}");
|
|
8
|
+
return response.data;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../../../src/api/endpoints/frames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAgB,uBAAuB,CAAC,CAAC;IAC1E,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC"}
|