@davidwoods/skylight-mcp 0.0.0-stage → 1.8.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 +22 -0
- package/README.md +633 -3
- package/THIRD_PARTY_NOTICES.md +38 -0
- package/dist/api/auth.d.ts +34 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +328 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/client.d.ts +103 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +324 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/constants.d.ts +4 -0
- package/dist/api/constants.d.ts.map +1 -0
- package/dist/api/constants.js +4 -0
- package/dist/api/constants.js.map +1 -0
- package/dist/api/credential-store.d.ts +38 -0
- package/dist/api/credential-store.d.ts.map +1 -0
- package/dist/api/credential-store.js +274 -0
- package/dist/api/credential-store.js.map +1 -0
- package/dist/api/credential-types.d.ts +15 -0
- package/dist/api/credential-types.d.ts.map +1 -0
- package/dist/api/credential-types.js +11 -0
- package/dist/api/credential-types.js.map +1 -0
- package/dist/api/endpoints/calendar.d.ts +36 -0
- package/dist/api/endpoints/calendar.d.ts.map +1 -0
- package/dist/api/endpoints/calendar.js +74 -0
- package/dist/api/endpoints/calendar.js.map +1 -0
- package/dist/api/endpoints/categories.d.ts +32 -0
- package/dist/api/endpoints/categories.d.ts.map +1 -0
- package/dist/api/endpoints/categories.js +70 -0
- package/dist/api/endpoints/categories.js.map +1 -0
- package/dist/api/endpoints/chores.d.ts +58 -0
- package/dist/api/endpoints/chores.d.ts.map +1 -0
- package/dist/api/endpoints/chores.js +115 -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 +154 -0
- package/dist/api/endpoints/meals.d.ts.map +1 -0
- package/dist/api/endpoints/meals.js +194 -0
- package/dist/api/endpoints/meals.js.map +1 -0
- package/dist/api/endpoints/messages.d.ts +98 -0
- package/dist/api/endpoints/messages.d.ts.map +1 -0
- package/dist/api/endpoints/messages.js +116 -0
- package/dist/api/endpoints/messages.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 +19 -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 +106 -0
- package/dist/api/endpoints/rewards.js.map +1 -0
- package/dist/api/endpoints/shape.d.ts +11 -0
- package/dist/api/endpoints/shape.d.ts.map +1 -0
- package/dist/api/endpoints/shape.js +34 -0
- package/dist/api/endpoints/shape.js.map +1 -0
- package/dist/api/endpoints/taskbox.d.ts +21 -0
- package/dist/api/endpoints/taskbox.d.ts.map +1 -0
- package/dist/api/endpoints/taskbox.js +39 -0
- package/dist/api/endpoints/taskbox.js.map +1 -0
- package/dist/api/oauth.d.ts +62 -0
- package/dist/api/oauth.d.ts.map +1 -0
- package/dist/api/oauth.js +206 -0
- package/dist/api/oauth.js.map +1 -0
- package/dist/api/types.d.ts +291 -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/cli.d.ts +23 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +106 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +27 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +17 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +17 -0
- package/dist/context.js.map +1 -0
- package/dist/doctor.d.ts +29 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +125 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -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 +29 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/calendar.d.ts +8 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +334 -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 +321 -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 +491 -0
- package/dist/tools/meals.js.map +1 -0
- package/dist/tools/messages.d.ts +3 -0
- package/dist/tools/messages.d.ts.map +1 -0
- package/dist/tools/messages.js +183 -0
- package/dist/tools/messages.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 +102 -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/planning.d.ts +15 -0
- package/dist/tools/planning.d.ts.map +1 -0
- package/dist/tools/planning.js +304 -0
- package/dist/tools/planning.js.map +1 -0
- package/dist/tools/registry.d.ts +39 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +143 -0
- package/dist/tools/registry.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 +323 -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 +103 -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/dist/utils/schedule.d.ts +86 -0
- package/dist/utils/schedule.d.ts.map +1 -0
- package/dist/utils/schedule.js +189 -0
- package/dist/utils/schedule.js.map +1 -0
- package/package.json +78 -6
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
import { addDays, offsetAt, zonedToEpoch } from "../../utils/schedule.js";
|
|
3
|
+
/**
|
|
4
|
+
* Messages need the API version the web app sends. Under the repo-wide older
|
|
5
|
+
* version the responses omit all_profiles / all_devices / voice_kind, which
|
|
6
|
+
* made get_messages misreport recipients and the edit guard refuse everything.
|
|
7
|
+
*/
|
|
8
|
+
export const NUDGES_API_VERSION = "2026-10-15";
|
|
9
|
+
/** ISO-8601 with the zone's numeric offset, e.g. 2026-10-01T00:00:00.000-07:00. */
|
|
10
|
+
export function isoWithOffset(epochMs, timeZone) {
|
|
11
|
+
const offsetMin = Math.round(offsetAt(epochMs, timeZone) / 60_000);
|
|
12
|
+
const sign = offsetMin < 0 ? "-" : "+";
|
|
13
|
+
const abs = Math.abs(offsetMin);
|
|
14
|
+
const hh = String(Math.floor(abs / 60)).padStart(2, "0");
|
|
15
|
+
const mm = String(abs % 60).padStart(2, "0");
|
|
16
|
+
const local = new Date(epochMs + offsetMin * 60_000).toISOString().slice(0, 23);
|
|
17
|
+
return `${local}${sign}${hh}:${mm}`;
|
|
18
|
+
}
|
|
19
|
+
/** Messages delivered between two local dates, inclusive. */
|
|
20
|
+
export async function getNudges(startDate, endDate, timeZone) {
|
|
21
|
+
const after = isoWithOffset(zonedToEpoch(startDate, "00:00", timeZone), timeZone);
|
|
22
|
+
const before = isoWithOffset(zonedToEpoch(addDays(endDate, 1), "00:00", timeZone) - 1, timeZone);
|
|
23
|
+
const response = await getClient().request("/api/frames/{frameId}/nudges", {
|
|
24
|
+
method: "GET",
|
|
25
|
+
params: { after, before },
|
|
26
|
+
apiVersion: NUDGES_API_VERSION,
|
|
27
|
+
});
|
|
28
|
+
return response.data ?? [];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Send a message to every profile and every device, delivered now.
|
|
32
|
+
* Payload shape is from the web app's "Send Now" call. Targeting specific
|
|
33
|
+
* profiles is inferred from how Skylight stores a message sent to one profile
|
|
34
|
+
* (all_profiles false plus that profile in categories) and from another open
|
|
35
|
+
* source client that sends category_ids; the POST itself has not been captured.
|
|
36
|
+
* Targeting devices and scheduling are not offered.
|
|
37
|
+
*/
|
|
38
|
+
export async function createNudge(options) {
|
|
39
|
+
const payload = {
|
|
40
|
+
body: options.body,
|
|
41
|
+
deliver_at: isoWithOffset(Date.now(), options.timeZone),
|
|
42
|
+
all_profiles: !options.recipientCategoryIds?.length,
|
|
43
|
+
all_devices: true,
|
|
44
|
+
voice_kind: options.readAloud ? "kirk_voice" : "silent",
|
|
45
|
+
};
|
|
46
|
+
if (options.recipientCategoryIds?.length)
|
|
47
|
+
payload.category_ids = options.recipientCategoryIds;
|
|
48
|
+
if (options.senderCategoryId)
|
|
49
|
+
payload.sender_category_id = options.senderCategoryId;
|
|
50
|
+
const response = await getClient().request("/api/frames/{frameId}/nudges", {
|
|
51
|
+
method: "POST",
|
|
52
|
+
body: payload,
|
|
53
|
+
apiVersion: NUDGES_API_VERSION,
|
|
54
|
+
});
|
|
55
|
+
const data = response?.data;
|
|
56
|
+
return Array.isArray(data) ? (data[0] ?? null) : (data ?? null);
|
|
57
|
+
}
|
|
58
|
+
/** Message ids are numeric. Validate before one ever reaches a URL path. */
|
|
59
|
+
export function assertNudgeId(id) {
|
|
60
|
+
if (!/^\d{1,12}$/.test(id))
|
|
61
|
+
throw new Error("Message ID must be numeric (see get_messages).");
|
|
62
|
+
return id;
|
|
63
|
+
}
|
|
64
|
+
/** Find one message by id within +/- 31 days of today. */
|
|
65
|
+
export async function findNudge(id, timeZone) {
|
|
66
|
+
const today = new Date();
|
|
67
|
+
const day = (offset) => {
|
|
68
|
+
const d = new Date(today.getTime() + offset * 86_400_000);
|
|
69
|
+
return d.toLocaleDateString("en-CA", { timeZone });
|
|
70
|
+
};
|
|
71
|
+
const nudges = await getNudges(day(-31), day(31), timeZone);
|
|
72
|
+
return nudges.find((n) => n.id === id) ?? null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Edit a message the way the web app does: PATCH with the whole form.
|
|
76
|
+
* Only messages sent to everyone on all devices and not repeating are
|
|
77
|
+
* supported, because those are the only shapes captured.
|
|
78
|
+
*/
|
|
79
|
+
export async function updateNudge(options) {
|
|
80
|
+
const { existing } = options;
|
|
81
|
+
const a = existing.attributes;
|
|
82
|
+
if (a.all_profiles !== true || a.all_devices !== true || a.recurring === true || a.rrule) {
|
|
83
|
+
throw new Error("Only messages sent to everyone on all devices, and not repeating, can be edited here. Edit this one in the Skylight app.");
|
|
84
|
+
}
|
|
85
|
+
const deliverAt = Date.parse(a.deliver_at ?? "");
|
|
86
|
+
if (Number.isNaN(deliverAt))
|
|
87
|
+
throw new Error("Message has no delivery time; edit it in the Skylight app.");
|
|
88
|
+
const sender = options.senderCategoryId ?? existing.relationships?.sender_category?.data?.id;
|
|
89
|
+
const payload = {
|
|
90
|
+
body: options.body,
|
|
91
|
+
deliver_at: isoWithOffset(deliverAt, options.timeZone),
|
|
92
|
+
all_profiles: true,
|
|
93
|
+
all_devices: true,
|
|
94
|
+
voice_kind: a.voice_kind ?? "silent",
|
|
95
|
+
};
|
|
96
|
+
if (sender)
|
|
97
|
+
payload.sender_category_id = sender;
|
|
98
|
+
await getClient().request(`/api/frames/{frameId}/nudges/${assertNudgeId(existing.id)}`, {
|
|
99
|
+
method: "PATCH",
|
|
100
|
+
body: payload,
|
|
101
|
+
apiVersion: NUDGES_API_VERSION,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Delete a message: DELETE /nudges/{id}. The Skylight web app offers no delete
|
|
106
|
+
* button, so this call is taken from two other open-source clients and has not
|
|
107
|
+
* been confirmed against this account's API version until a live run says so.
|
|
108
|
+
* Returns the HTTP outcome only; callers must read back to confirm removal.
|
|
109
|
+
*/
|
|
110
|
+
export async function deleteNudge(existing) {
|
|
111
|
+
await getClient().request(`/api/frames/{frameId}/nudges/${assertNudgeId(existing.id)}`, {
|
|
112
|
+
method: "DELETE",
|
|
113
|
+
apiVersion: NUDGES_API_VERSION,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/api/endpoints/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface AvatarResource {
|
|
2
|
+
type: "avatar";
|
|
3
|
+
id: string;
|
|
4
|
+
attributes: {
|
|
5
|
+
name?: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface ColorResource {
|
|
11
|
+
type: "color";
|
|
12
|
+
id: string;
|
|
13
|
+
attributes: {
|
|
14
|
+
name?: string;
|
|
15
|
+
hex?: string;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get available avatar options
|
|
21
|
+
*/
|
|
22
|
+
export declare function getAvatars(): Promise<AvatarResource[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Get available color options
|
|
25
|
+
*/
|
|
26
|
+
export declare function getColors(): Promise<ColorResource[]>;
|
|
27
|
+
//# sourceMappingURL=misc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/misc.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAUD;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAI5D;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAI1D"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
import { resourceList } from "./shape.js";
|
|
3
|
+
/**
|
|
4
|
+
* Get available avatar options
|
|
5
|
+
*/
|
|
6
|
+
export async function getAvatars() {
|
|
7
|
+
const client = getClient();
|
|
8
|
+
const response = await client.get("/api/avatars");
|
|
9
|
+
return response.data;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get available color options
|
|
13
|
+
*/
|
|
14
|
+
export async function getColors() {
|
|
15
|
+
const client = getClient();
|
|
16
|
+
const response = await client.get("/api/colors");
|
|
17
|
+
return resourceList(response, "colors");
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=misc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../../src/api/endpoints/misc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA8B1C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAkB,cAAc,CAAC,CAAC;IACnE,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAiB,aAAa,CAAC,CAAC;IACjE,OAAO,YAAY,CAAgB,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface AlbumResource {
|
|
2
|
+
type: "album";
|
|
3
|
+
id: string;
|
|
4
|
+
attributes: {
|
|
5
|
+
name?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get photo albums
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAlbums(): Promise<AlbumResource[]>;
|
|
13
|
+
//# sourceMappingURL=photos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photos.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/photos.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAMD;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAI1D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get photo albums
|
|
4
|
+
*/
|
|
5
|
+
export async function getAlbums() {
|
|
6
|
+
const client = getClient();
|
|
7
|
+
const response = await client.get("/api/frames/{frameId}/albums");
|
|
8
|
+
return response.data;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=photos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photos.js","sourceRoot":"","sources":["../../../src/api/endpoints/photos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAezC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAiB,8BAA8B,CAAC,CAAC;IAClF,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RewardResource, RewardPointResource } from "../types.js";
|
|
2
|
+
export interface GetRewardsOptions {
|
|
3
|
+
redeemedAtMin?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Get rewards (items that can be redeemed with points)
|
|
7
|
+
*/
|
|
8
|
+
export declare function getRewards(options?: GetRewardsOptions): Promise<RewardResource[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Get reward points for family members
|
|
11
|
+
*/
|
|
12
|
+
export declare function getRewardPoints(): Promise<RewardPointResource[]>;
|
|
13
|
+
export interface CreateRewardOptions {
|
|
14
|
+
name: string;
|
|
15
|
+
pointValue: number;
|
|
16
|
+
description?: string;
|
|
17
|
+
emojiIcon?: string;
|
|
18
|
+
categoryIds?: string[];
|
|
19
|
+
respawnOnRedemption?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a new reward
|
|
23
|
+
*/
|
|
24
|
+
export declare function createReward(options: CreateRewardOptions): Promise<RewardResource>;
|
|
25
|
+
export interface UpdateRewardOptions {
|
|
26
|
+
name?: string;
|
|
27
|
+
pointValue?: number;
|
|
28
|
+
description?: string | null;
|
|
29
|
+
emojiIcon?: string | null;
|
|
30
|
+
categoryIds?: string[];
|
|
31
|
+
respawnOnRedemption?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Update an existing reward
|
|
35
|
+
*/
|
|
36
|
+
export declare function updateReward(rewardId: string, options: UpdateRewardOptions): Promise<RewardResource>;
|
|
37
|
+
/**
|
|
38
|
+
* Delete a reward
|
|
39
|
+
*/
|
|
40
|
+
export declare function deleteReward(rewardId: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Redeem a reward (spend points)
|
|
43
|
+
*/
|
|
44
|
+
export declare function redeemReward(rewardId: string, categoryId?: string): Promise<RewardResource>;
|
|
45
|
+
/**
|
|
46
|
+
* Unredeem a reward (cancel redemption)
|
|
47
|
+
*/
|
|
48
|
+
export declare function unredeemReward(rewardId: string): Promise<RewardResource>;
|
|
49
|
+
//# sourceMappingURL=rewards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewards.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/rewards.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EAGd,mBAAmB,EAGpB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAS3F;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAMtE;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyBxF;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CA8BzB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKlE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAQzB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAO9E"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { resourceList } from "./shape.js";
|
|
2
|
+
import { getClient } from "../client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Get rewards (items that can be redeemed with points)
|
|
5
|
+
*/
|
|
6
|
+
export async function getRewards(options = {}) {
|
|
7
|
+
const client = getClient();
|
|
8
|
+
const response = await client.get("/api/frames/{frameId}/rewards", {
|
|
9
|
+
redeemed_at_min: options.redeemedAtMin,
|
|
10
|
+
});
|
|
11
|
+
return response.data;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get reward points for family members
|
|
15
|
+
*/
|
|
16
|
+
export async function getRewardPoints() {
|
|
17
|
+
const client = getClient();
|
|
18
|
+
const response = await client.get("/api/frames/{frameId}/reward_points");
|
|
19
|
+
return resourceList(response, "reward points");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a new reward
|
|
23
|
+
*/
|
|
24
|
+
export async function createReward(options) {
|
|
25
|
+
const client = getClient();
|
|
26
|
+
const request = {
|
|
27
|
+
data: {
|
|
28
|
+
type: "reward",
|
|
29
|
+
attributes: {
|
|
30
|
+
name: options.name,
|
|
31
|
+
point_value: options.pointValue,
|
|
32
|
+
description: options.description ?? null,
|
|
33
|
+
emoji_icon: options.emojiIcon ?? null,
|
|
34
|
+
respawn_on_redemption: options.respawnOnRedemption ?? false,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
if (options.categoryIds && options.categoryIds.length > 0) {
|
|
39
|
+
request.data.relationships = {
|
|
40
|
+
categories: {
|
|
41
|
+
data: options.categoryIds.map((id) => ({ type: "category", id })),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const response = await client.post("/api/frames/{frameId}/rewards", request);
|
|
46
|
+
return response.data;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Update an existing reward
|
|
50
|
+
*/
|
|
51
|
+
export async function updateReward(rewardId, options) {
|
|
52
|
+
const client = getClient();
|
|
53
|
+
const request = {
|
|
54
|
+
data: {
|
|
55
|
+
type: "reward",
|
|
56
|
+
attributes: {},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
if (options.name !== undefined)
|
|
60
|
+
request.data.attributes.name = options.name;
|
|
61
|
+
if (options.pointValue !== undefined)
|
|
62
|
+
request.data.attributes.point_value = options.pointValue;
|
|
63
|
+
if (options.description !== undefined)
|
|
64
|
+
request.data.attributes.description = options.description;
|
|
65
|
+
if (options.emojiIcon !== undefined)
|
|
66
|
+
request.data.attributes.emoji_icon = options.emojiIcon;
|
|
67
|
+
if (options.respawnOnRedemption !== undefined) {
|
|
68
|
+
request.data.attributes.respawn_on_redemption = options.respawnOnRedemption;
|
|
69
|
+
}
|
|
70
|
+
if (options.categoryIds) {
|
|
71
|
+
request.data.relationships = {
|
|
72
|
+
categories: {
|
|
73
|
+
data: options.categoryIds.map((id) => ({ type: "category", id })),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const response = await client.request(`/api/frames/{frameId}/rewards/${rewardId}`, { method: "PATCH", body: request });
|
|
78
|
+
return response.data;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Delete a reward
|
|
82
|
+
*/
|
|
83
|
+
export async function deleteReward(rewardId) {
|
|
84
|
+
const client = getClient();
|
|
85
|
+
await client.request(`/api/frames/{frameId}/rewards/${rewardId}`, {
|
|
86
|
+
method: "DELETE",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Redeem a reward (spend points)
|
|
91
|
+
*/
|
|
92
|
+
export async function redeemReward(rewardId, categoryId) {
|
|
93
|
+
const client = getClient();
|
|
94
|
+
const body = categoryId ? { category_id: categoryId } : {};
|
|
95
|
+
const response = await client.post(`/api/frames/{frameId}/rewards/${rewardId}/redeem`, body);
|
|
96
|
+
return response.data;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Unredeem a reward (cancel redemption)
|
|
100
|
+
*/
|
|
101
|
+
export async function unredeemReward(rewardId) {
|
|
102
|
+
const client = getClient();
|
|
103
|
+
const response = await client.post(`/api/frames/{frameId}/rewards/${rewardId}/unredeem`, {});
|
|
104
|
+
return response.data;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=rewards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewards.js","sourceRoot":"","sources":["../../../src/api/endpoints/rewards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalise a list response. Skylight's endpoints mostly return JSON:API
|
|
3
|
+
* ({ data: [...] }), but a few (colors, reward points) did not match that on a
|
|
4
|
+
* real account. Accept a bare array, { data: [...] } or { data: {...} }; for
|
|
5
|
+
* anything else fail with the top-level KEYS only (never values, which can
|
|
6
|
+
* hold personal data) so the real shape can be learned from the error.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resourceList<T>(response: unknown, label: string): T[];
|
|
9
|
+
/** Attributes of a resource, tolerating flat items that carry no `attributes`. */
|
|
10
|
+
export declare function attributesOf(item: unknown): Record<string, unknown>;
|
|
11
|
+
//# sourceMappingURL=shape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/shape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,CAUrE;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQnE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalise a list response. Skylight's endpoints mostly return JSON:API
|
|
3
|
+
* ({ data: [...] }), but a few (colors, reward points) did not match that on a
|
|
4
|
+
* real account. Accept a bare array, { data: [...] } or { data: {...} }; for
|
|
5
|
+
* anything else fail with the top-level KEYS only (never values, which can
|
|
6
|
+
* hold personal data) so the real shape can be learned from the error.
|
|
7
|
+
*/
|
|
8
|
+
export function resourceList(response, label) {
|
|
9
|
+
if (Array.isArray(response))
|
|
10
|
+
return response;
|
|
11
|
+
if (response && typeof response === "object") {
|
|
12
|
+
const data = response.data;
|
|
13
|
+
if (Array.isArray(data))
|
|
14
|
+
return data;
|
|
15
|
+
if (data && typeof data === "object")
|
|
16
|
+
return [data];
|
|
17
|
+
const keys = Object.keys(response).join(", ") || "none";
|
|
18
|
+
throw new Error(`${label}: unexpected response shape (top-level keys: ${keys})`);
|
|
19
|
+
}
|
|
20
|
+
throw new Error(`${label}: unexpected response shape (${typeof response})`);
|
|
21
|
+
}
|
|
22
|
+
/** Attributes of a resource, tolerating flat items that carry no `attributes`. */
|
|
23
|
+
export function attributesOf(item) {
|
|
24
|
+
if (!item || typeof item !== "object")
|
|
25
|
+
return {};
|
|
26
|
+
const obj = item;
|
|
27
|
+
if (obj.attributes && typeof obj.attributes === "object")
|
|
28
|
+
return obj.attributes;
|
|
29
|
+
const rest = { ...item };
|
|
30
|
+
delete rest.id;
|
|
31
|
+
delete rest.type;
|
|
32
|
+
return rest;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=shape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape.js","sourceRoot":"","sources":["../../../src/api/endpoints/shape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAI,QAAiB,EAAE,KAAa;IAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAe,CAAC;IACpD,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAI,QAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,OAAO,IAAW,CAAC;QAC5C,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,CAAC,IAAS,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,QAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gDAAgD,IAAI,GAAG,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gCAAgC,OAAO,QAAQ,GAAG,CAAC,CAAC;AAC9E,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACjD,MAAM,GAAG,GAAG,IAAgC,CAAC;IAC7C,IAAI,GAAG,CAAC,UAAU,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,UAAqC,CAAC;IAC3G,MAAM,IAAI,GAA4B,EAAE,GAAI,IAAgC,EAAE,CAAC;IAC/E,OAAO,IAAI,CAAC,EAAE,CAAC;IACf,OAAO,IAAI,CAAC,IAAI,CAAC;IACjB,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TaskBoxItemResource } from "../types.js";
|
|
2
|
+
export interface CreateTaskBoxItemOptions {
|
|
3
|
+
summary: string;
|
|
4
|
+
emojiIcon?: string;
|
|
5
|
+
routine?: boolean;
|
|
6
|
+
rewardPoints?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a task box item
|
|
10
|
+
* Task box items are unscheduled tasks that can later be assigned to specific dates
|
|
11
|
+
*/
|
|
12
|
+
export declare function createTaskBoxItem(options: CreateTaskBoxItemOptions): Promise<TaskBoxItemResource>;
|
|
13
|
+
/**
|
|
14
|
+
* List the task box.
|
|
15
|
+
*
|
|
16
|
+
* Shape captured from the web app: GET /task_box/items returns template items
|
|
17
|
+
* (summary, emoji_icon, routine, reward_points). They carry no assignee and no
|
|
18
|
+
* date: the task box is a library of reusable chores, not scheduled work.
|
|
19
|
+
*/
|
|
20
|
+
export declare function listTaskBoxItems(): Promise<TaskBoxItemResource[]>;
|
|
21
|
+
//# sourceMappingURL=taskbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taskbox.d.ts","sourceRoot":"","sources":["../../../src/api/endpoints/taskbox.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,mBAAmB,EAEpB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAqB9B;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC,CASvE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getClient } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a task box item
|
|
4
|
+
* Task box items are unscheduled tasks that can later be assigned to specific dates
|
|
5
|
+
*/
|
|
6
|
+
export async function createTaskBoxItem(options) {
|
|
7
|
+
const client = getClient();
|
|
8
|
+
const request = {
|
|
9
|
+
data: {
|
|
10
|
+
type: "task_box_item",
|
|
11
|
+
attributes: {
|
|
12
|
+
summary: options.summary,
|
|
13
|
+
emoji_icon: options.emojiIcon ?? null,
|
|
14
|
+
routine: options.routine ?? false,
|
|
15
|
+
reward_points: options.rewardPoints ?? null,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const response = await client.post("/api/frames/{frameId}/task_box/items", request);
|
|
20
|
+
return response.data;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* List the task box.
|
|
24
|
+
*
|
|
25
|
+
* Shape captured from the web app: GET /task_box/items returns template items
|
|
26
|
+
* (summary, emoji_icon, routine, reward_points). They carry no assignee and no
|
|
27
|
+
* date: the task box is a library of reusable chores, not scheduled work.
|
|
28
|
+
*/
|
|
29
|
+
export async function listTaskBoxItems() {
|
|
30
|
+
const client = getClient();
|
|
31
|
+
const response = await client.get("/api/frames/{frameId}/task_box/items");
|
|
32
|
+
if (!Array.isArray(response.data)) {
|
|
33
|
+
// Never report "empty" for a shape we don't recognise. Keys only: values could be personal.
|
|
34
|
+
const keys = response && typeof response === "object" ? Object.keys(response).join(", ") : typeof response;
|
|
35
|
+
throw new Error(`Unexpected task box response (top-level keys: ${keys || "none"})`);
|
|
36
|
+
}
|
|
37
|
+
return response.data;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=taskbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taskbox.js","sourceRoot":"","sources":["../../../src/api/endpoints/taskbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAezC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAiC;IAEjC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,MAAM,OAAO,GAA6B;QACxC,IAAI,EAAE;YACJ,IAAI,EAAE,eAAe;YACrB,UAAU,EAAE;gBACV,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,UAAU,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI;gBACrC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,KAAK;gBACjC,aAAa,EAAE,OAAO,CAAC,YAAY,IAAI,IAAI;aAC5C;SACF;KACF,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAChC,sCAAsC,EACtC,OAAO,CACR,CAAC;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAuB,sCAAsC,CAAC,CAAC;IAChG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,4FAA4F;QAC5F,MAAM,IAAI,GAAG,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC;QAC3G,MAAM,IAAI,KAAK,CAAC,iDAAiD,IAAI,IAAI,MAAM,GAAG,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-paste OAuth login and token refresh.
|
|
3
|
+
*
|
|
4
|
+
* The user signs in to Skylight in their own browser, then pastes the final
|
|
5
|
+
* https://ourskylight.com/welcome?code=... URL back into the CLI. The password
|
|
6
|
+
* never reaches this process. The authorization code is bound to a PKCE
|
|
7
|
+
* verifier and a random state value that are kept in a short-lived, 0600
|
|
8
|
+
* "pending login" file between the two CLI steps.
|
|
9
|
+
*
|
|
10
|
+
* Design informed by kamilio/skylight-calendar-agent (MIT); see
|
|
11
|
+
* THIRD_PARTY_NOTICES.md. Unlike that project's flow, this one uses PKCE (S256)
|
|
12
|
+
* and verifies the returned state against the pending login.
|
|
13
|
+
*/
|
|
14
|
+
export declare const OAUTH_CLIENT_ID = "skylight-mobile";
|
|
15
|
+
/** How long a pending login stays valid between `auth login` and `auth complete`. */
|
|
16
|
+
export declare const PENDING_LOGIN_TTL_MS: number;
|
|
17
|
+
/** Refresh this long before the access token actually expires. */
|
|
18
|
+
export declare const EXPIRY_SKEW_MS: number;
|
|
19
|
+
export interface StoredCredential {
|
|
20
|
+
version: 1;
|
|
21
|
+
type: "oauth";
|
|
22
|
+
accessToken: string;
|
|
23
|
+
refreshToken: string;
|
|
24
|
+
/** Stable per-install device id; sent with every token request. */
|
|
25
|
+
fingerprint: string;
|
|
26
|
+
/** Epoch milliseconds. */
|
|
27
|
+
expiresAt: number;
|
|
28
|
+
}
|
|
29
|
+
export interface PendingLogin {
|
|
30
|
+
state: string;
|
|
31
|
+
codeVerifier: string;
|
|
32
|
+
fingerprint: string;
|
|
33
|
+
createdAt: number;
|
|
34
|
+
}
|
|
35
|
+
export declare class OAuthError extends Error {
|
|
36
|
+
constructor(message: string);
|
|
37
|
+
}
|
|
38
|
+
type FetchLike = typeof fetch;
|
|
39
|
+
/** The S256 challenge for a verifier. */
|
|
40
|
+
export declare function codeChallengeFor(codeVerifier: string): string;
|
|
41
|
+
/** Fresh PKCE verifier, state and device fingerprint for a new login. */
|
|
42
|
+
export declare function newPendingLogin(now?: number, overrides?: Partial<Pick<PendingLogin, "state" | "fingerprint">>): PendingLogin;
|
|
43
|
+
/** The Skylight authorize URL for a pending login. */
|
|
44
|
+
export declare function authorizeUrlFor(pending: PendingLogin): string;
|
|
45
|
+
/**
|
|
46
|
+
* Start a login: returns the URL the user must open in their browser and the
|
|
47
|
+
* pending-login record the caller must persist until `completeBrowserLogin`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function beginBrowserLogin(now?: number, overrides?: Partial<Pick<PendingLogin, "state" | "fingerprint">>): {
|
|
50
|
+
loginUrl: string;
|
|
51
|
+
pending: PendingLogin;
|
|
52
|
+
};
|
|
53
|
+
/** Extract and validate the authorization code from the pasted callback URL. */
|
|
54
|
+
export declare function parseCallbackUrl(callbackUrl: string, pending: PendingLogin, now?: number): string;
|
|
55
|
+
/** Exchange the pasted callback URL for a credential. */
|
|
56
|
+
export declare function completeBrowserLogin(callbackUrl: string, pending: PendingLogin, fetchImpl?: FetchLike, now?: number): Promise<StoredCredential>;
|
|
57
|
+
/** Use the refresh token to obtain a new credential. Refresh tokens rotate. */
|
|
58
|
+
export declare function refreshCredential(credential: StoredCredential, fetchImpl?: FetchLike, now?: number): Promise<StoredCredential>;
|
|
59
|
+
export declare function isExpired(credential: StoredCredential, now?: number): boolean;
|
|
60
|
+
export declare function parseStoredCredential(value: unknown): StoredCredential | null;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/api/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAOjD,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,QAAiB,CAAC;AAEnD,kEAAkE;AAClE,eAAO,MAAM,cAAc,QAAY,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAED,KAAK,SAAS,GAAG,OAAO,KAAK,CAAC;AAyB9B,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAmB,EAAE,SAAS,GAAE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,aAAa,CAAC,CAAM,GAAG,YAAY,CAO5I;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAW7D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,GAAE,MAAmB,EACxB,SAAS,GAAE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,aAAa,CAAC,CAAM,GACnE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAG7C;AAQD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAkC7G;AAsDD,yDAAyD;AACzD,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EACrB,SAAS,GAAE,SAAiB,EAC5B,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAgB3B;AAED,+EAA+E;AAC/E,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,gBAAgB,EAC5B,SAAS,GAAE,SAAiB,EAC5B,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAY3B;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,gBAAgB,EAAE,GAAG,GAAE,MAAmB,GAAG,OAAO,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAe7E"}
|