wikimasters-cli 0.0.0-stage → 0.1.1
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 +125 -2
- package/dist/cli/config.js +47 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/main.js +10 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.js +297 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/pasted-session.js +49 -0
- package/dist/cli/pasted-session.js.map +1 -0
- package/dist/cli/program.js +334 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/session.js +30 -0
- package/dist/cli/session.js.map +1 -0
- package/dist/core/auction-bids.js +31 -0
- package/dist/core/auction-bids.js.map +1 -0
- package/dist/core/auction-cancel.js +17 -0
- package/dist/core/auction-cancel.js.map +1 -0
- package/dist/core/auction-create.js +40 -0
- package/dist/core/auction-create.js.map +1 -0
- package/dist/core/auction-list.js +16 -0
- package/dist/core/auction-list.js.map +1 -0
- package/dist/core/auction-search.js +38 -0
- package/dist/core/auction-search.js.map +1 -0
- package/dist/core/auction.js +79 -0
- package/dist/core/auction.js.map +1 -0
- package/dist/core/auth-cookie.js +50 -0
- package/dist/core/auth-cookie.js.map +1 -0
- package/dist/core/browser-login.js +81 -0
- package/dist/core/browser-login.js.map +1 -0
- package/dist/core/card-id.js +5 -0
- package/dist/core/card-id.js.map +1 -0
- package/dist/core/card-search.js +51 -0
- package/dist/core/card-search.js.map +1 -0
- package/dist/core/card-value.js +43 -0
- package/dist/core/card-value.js.map +1 -0
- package/dist/core/collection-list.js +44 -0
- package/dist/core/collection-list.js.map +1 -0
- package/dist/core/collection.js +46 -0
- package/dist/core/collection.js.map +1 -0
- package/dist/core/entry-id.js +4 -0
- package/dist/core/entry-id.js.map +1 -0
- package/dist/core/errors.js +28 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/favourite.js +27 -0
- package/dist/core/favourite.js.map +1 -0
- package/dist/core/global-collection.js +58 -0
- package/dist/core/global-collection.js.map +1 -0
- package/dist/core/index.js +26 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/integer.js +15 -0
- package/dist/core/integer.js.map +1 -0
- package/dist/core/label.js +39 -0
- package/dist/core/label.js.map +1 -0
- package/dist/core/notification-list.js +32 -0
- package/dist/core/notification-list.js.map +1 -0
- package/dist/core/page.js +22 -0
- package/dist/core/page.js.map +1 -0
- package/dist/core/profile-collection.js +45 -0
- package/dist/core/profile-collection.js.map +1 -0
- package/dist/core/session.js +49 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/site.js +52 -0
- package/dist/core/site.js.map +1 -0
- package/dist/core/supabase.js +5 -0
- package/dist/core/supabase.js.map +1 -0
- package/dist/core/table-query.js +21 -0
- package/dist/core/table-query.js.map +1 -0
- package/dist/core/tag.js +25 -0
- package/dist/core/tag.js.map +1 -0
- package/dist/core/transient.js +40 -0
- package/dist/core/transient.js.map +1 -0
- package/dist/core/uuid.js +10 -0
- package/dist/core/uuid.js.map +1 -0
- package/dist/core/wishlist.js +66 -0
- package/dist/core/wishlist.js.map +1 -0
- package/package.json +42 -4
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { WikiMastersError } from "./errors.js";
|
|
2
|
+
function parseMatching(raw, pattern, kind, { subject, unit, untouched }) {
|
|
3
|
+
if (!pattern.test(raw) || !Number.isSafeInteger(Number(raw))) {
|
|
4
|
+
const ofUnit = unit === undefined ? "" : ` of ${unit}`;
|
|
5
|
+
throw new WikiMastersError(`Invalid ${subject}: ${JSON.stringify(raw)} is not ${kind}${ofUnit}; ${untouched}`);
|
|
6
|
+
}
|
|
7
|
+
return Number(raw);
|
|
8
|
+
}
|
|
9
|
+
export function parseInteger(raw, argument) {
|
|
10
|
+
return parseMatching(raw, /^-?(0|[1-9][0-9]*)$/, "an integer", argument);
|
|
11
|
+
}
|
|
12
|
+
export function parseStrictlyPositiveInteger(raw, argument) {
|
|
13
|
+
return parseMatching(raw, /^[1-9][0-9]*$/, "a strictly positive integer", argument);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=integer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integer.js","sourceRoot":"","sources":["../../src/core/integer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAQ/C,SAAS,aAAa,CACpB,GAAW,EACX,OAAe,EACf,IAAY,EACZ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAmB;IAE7C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;QACvD,MAAM,IAAI,gBAAgB,CACxB,WAAW,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,MAAM,KAAK,SAAS,EAAE,CACnF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,QAAyB;IACjE,OAAO,aAAa,CAAC,GAAG,EAAE,qBAAqB,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,GAAW,EACX,QAAyB;IAEzB,OAAO,aAAa,CAClB,GAAG,EACH,eAAe,EACf,6BAA6B,EAC7B,QAAQ,CACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { apiFailure } from "./errors.js";
|
|
2
|
+
export function asLabelId(raw) {
|
|
3
|
+
return raw;
|
|
4
|
+
}
|
|
5
|
+
export async function listLabels(session) {
|
|
6
|
+
const { data, error, status } = await session.client
|
|
7
|
+
.from("tags")
|
|
8
|
+
.select("id, name, color")
|
|
9
|
+
.eq("user_id", session.userId)
|
|
10
|
+
.order("name")
|
|
11
|
+
.overrideTypes();
|
|
12
|
+
if (error)
|
|
13
|
+
throw apiFailure("Reading your labels", status, error.message);
|
|
14
|
+
return data;
|
|
15
|
+
}
|
|
16
|
+
export async function createLabel(session, name, color) {
|
|
17
|
+
const { data, error, status } = await session.client
|
|
18
|
+
.from("tags")
|
|
19
|
+
.insert({
|
|
20
|
+
user_id: session.userId,
|
|
21
|
+
name,
|
|
22
|
+
...(color === undefined ? {} : { color }),
|
|
23
|
+
})
|
|
24
|
+
.select("id, name, color")
|
|
25
|
+
.single();
|
|
26
|
+
if (error) {
|
|
27
|
+
throw apiFailure(`Creating label ${JSON.stringify(name)}`, status, error.message);
|
|
28
|
+
}
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
export async function deleteLabel(session, id) {
|
|
32
|
+
const { error, status } = await session.client.rpc("delete_tag", {
|
|
33
|
+
p_tag_id: id,
|
|
34
|
+
});
|
|
35
|
+
if (error)
|
|
36
|
+
throw apiFailure(`Deleting label ${id}`, status, error.message);
|
|
37
|
+
return { id };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=label.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label.js","sourceRoot":"","sources":["../../src/core/label.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,GAAc,CAAC;AACxB,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAgB;IAC/C,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM;SACjD,IAAI,CAAC,MAAM,CAAC;SACZ,MAAM,CAAC,iBAAiB,CAAC;SACzB,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC;SAC7B,KAAK,CAAC,MAAM,CAAC;SACb,aAAa,EAA6B,CAAC;IAC9C,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,qBAAqB,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAgB,EAChB,IAAY,EACZ,KAAc;IAEd,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM;SACjD,IAAI,CAAC,MAAM,CAAC;SACZ,MAAM,CAAC;QACN,OAAO,EAAE,OAAO,CAAC,MAAM;QACvB,IAAI;QACJ,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;KAC1C,CAAC;SACD,MAAM,CAAC,iBAAiB,CAAC;SACzB,MAAM,EAAS,CAAC;IACnB,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,UAAU,CACd,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EACxC,MAAM,EACN,KAAK,CAAC,OAAO,CACd,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAgB,EAChB,EAAW;IAEX,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE;QAC/D,QAAQ,EAAE,EAAE;KACb,CAAC,CAAC;IACH,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,kBAAkB,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3E,OAAO,EAAE,EAAE,EAAE,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { apiFailure } from "./errors.js";
|
|
2
|
+
import { isFullPage, pageRange } from "./page.js";
|
|
3
|
+
export const NOTIFICATION_LIMIT = 50;
|
|
4
|
+
export async function listNotifications(session, { types, unread, after }, request) {
|
|
5
|
+
const [from, to] = pageRange(request);
|
|
6
|
+
let query = session.client
|
|
7
|
+
.from("notifications")
|
|
8
|
+
.select("id, type, read, created_at, data")
|
|
9
|
+
.eq("user_id", session.userId);
|
|
10
|
+
if (types.length > 0)
|
|
11
|
+
query = query.in("type", types);
|
|
12
|
+
if (unread)
|
|
13
|
+
query = query.eq("read", false);
|
|
14
|
+
if (after !== undefined)
|
|
15
|
+
query = query.gt("created_at", after);
|
|
16
|
+
const { data, error, status } = await query
|
|
17
|
+
.order("created_at", { ascending: false })
|
|
18
|
+
.order("id", { ascending: false })
|
|
19
|
+
.range(from, to)
|
|
20
|
+
.overrideTypes();
|
|
21
|
+
if (error) {
|
|
22
|
+
throw apiFailure("Listing your notifications", status, error.message);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
notifications: data.map(({ created_at, ...notification }) => ({
|
|
26
|
+
...notification,
|
|
27
|
+
createdAt: created_at,
|
|
28
|
+
})),
|
|
29
|
+
full: isFullPage(data, request.limit),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=notification-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-list.js","sourceRoot":"","sources":["../../src/core/notification-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAoB,MAAM,WAAW,CAAC;AAGpE,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AA6BrC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAgB,EAChB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAsB,EAC5C,OAAoB;IAEpB,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM;SACvB,IAAI,CAAC,eAAe,CAAC;SACrB,MAAM,CAAC,kCAAkC,CAAC;SAC1C,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtD,IAAI,MAAM;QAAE,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5C,IAAI,KAAK,KAAK,SAAS;QAAE,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAC/D,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK;SACxC,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;SACzC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;SACjC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;SACf,aAAa,EAAuC,CAAC;IACxD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,UAAU,CAAC,4BAA4B,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACxE,CAAC;IAED,OAAO;QACL,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5D,GAAG,YAAY;YACf,SAAS,EAAE,UAAU;SACtB,CAAC,CAAC;QACH,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC;KACtC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { parseInteger, parseStrictlyPositiveInteger } from "./integer.js";
|
|
2
|
+
export const PAGE_LIMIT = 1000;
|
|
3
|
+
export function parsePageNumber(raw) {
|
|
4
|
+
return parseStrictlyPositiveInteger(raw, {
|
|
5
|
+
subject: "page",
|
|
6
|
+
untouched: "nothing was read",
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
export function parsePageLimit(raw) {
|
|
10
|
+
return parseInteger(raw, {
|
|
11
|
+
subject: "limit",
|
|
12
|
+
untouched: "nothing was read",
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function pageRange({ page, limit }) {
|
|
16
|
+
const from = (page - 1) * limit;
|
|
17
|
+
return [from, from + limit - 1];
|
|
18
|
+
}
|
|
19
|
+
export function isFullPage(rows, limit) {
|
|
20
|
+
return rows.length === limit;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/core/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AAE1E,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC;AAU/B,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,4BAA4B,CAAC,GAAG,EAAE;QACvC,OAAO,EAAE,MAAM;QACf,SAAS,EAAE,kBAAkB;KAC9B,CAAe,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,YAAY,CAAC,GAAG,EAAE;QACvB,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,kBAAkB;KAC9B,CAAc,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAe;IACpD,MAAM,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IAChC,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAwB,EAAE,KAAa;IAChE,OAAO,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { WikiMastersError } from "./errors.js";
|
|
2
|
+
import { isFullPage } from "./page.js";
|
|
3
|
+
import { siteCookie, siteRequest } from "./site.js";
|
|
4
|
+
export const PROFILE_COLLECTION_PAGE_SIZE = 50;
|
|
5
|
+
function isProfileCollectionResponse(body) {
|
|
6
|
+
return (typeof body === "object" &&
|
|
7
|
+
body !== null &&
|
|
8
|
+
"collection" in body &&
|
|
9
|
+
Array.isArray(body.collection) &&
|
|
10
|
+
"pendingTradeCardIds" in body &&
|
|
11
|
+
Array.isArray(body.pendingTradeCardIds));
|
|
12
|
+
}
|
|
13
|
+
export async function readProfileCollection(session, username, { page, sort, search, rarities, wishlisted }) {
|
|
14
|
+
const action = `Reading the collection of player ${JSON.stringify(username)}`;
|
|
15
|
+
const query = new URLSearchParams({ page, stats: "0" });
|
|
16
|
+
if (sort !== undefined)
|
|
17
|
+
query.set("sort", sort);
|
|
18
|
+
if (search !== undefined)
|
|
19
|
+
query.set("q", search);
|
|
20
|
+
for (const rarity of rarities ?? [])
|
|
21
|
+
query.append("rarity", rarity);
|
|
22
|
+
if (wishlisted)
|
|
23
|
+
query.set("wishlisted_by_me", "1");
|
|
24
|
+
query.set("pending", "1");
|
|
25
|
+
const body = await siteRequest(session, await siteCookie(session), action, "/trades", `/api/profile/${encodeURIComponent(username)}/collection?${query}`, { method: "GET" });
|
|
26
|
+
if (!isProfileCollectionResponse(body)) {
|
|
27
|
+
throw new WikiMastersError(`${action} returned an unexpected response: ${JSON.stringify(body)}`);
|
|
28
|
+
}
|
|
29
|
+
const pending = new Set(body.pendingTradeCardIds);
|
|
30
|
+
return {
|
|
31
|
+
entries: body.collection.map((row) => ({
|
|
32
|
+
entryId: row.id,
|
|
33
|
+
id: row.card.id,
|
|
34
|
+
title: row.card.wikipedia_title,
|
|
35
|
+
rarity: row.card.rarity,
|
|
36
|
+
count: row.count,
|
|
37
|
+
starred: row.starred,
|
|
38
|
+
shiny: row.is_shiny,
|
|
39
|
+
labels: row.tags.map(({ name }) => name),
|
|
40
|
+
pendingTrade: pending.has(row.card.id),
|
|
41
|
+
})),
|
|
42
|
+
full: isFullPage(body.collection, PROFILE_COLLECTION_PAGE_SIZE),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=profile-collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-collection.js","sourceRoot":"","sources":["../../src/core/profile-collection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createClient, isAuthApiError, isAuthRetryableFetchError, } from "@supabase/supabase-js";
|
|
2
|
+
import { AuthRequiredError, WikiMastersError, apiUnavailable, } from "./errors.js";
|
|
3
|
+
import { SUPABASE_ANON_KEY, SUPABASE_URL } from "./supabase.js";
|
|
4
|
+
import { RETRY_DELAYS_MS, fetchRetrying, isTransientStatus, } from "./transient.js";
|
|
5
|
+
const SESSION_REJECTED_STATUSES = new Set([400, 401, 403]);
|
|
6
|
+
const AUTH_PATH = "/auth/v1/";
|
|
7
|
+
const INVALID_API_KEY = "Invalid API key";
|
|
8
|
+
function requestUrl(input) {
|
|
9
|
+
return new URL(input instanceof Request ? input.url : input);
|
|
10
|
+
}
|
|
11
|
+
export async function resumeSession({ anonKey = SUPABASE_ANON_KEY, refreshToken, fetch = globalThis.fetch, retryDelaysMs = RETRY_DELAYS_MS, }) {
|
|
12
|
+
const supabaseFetch = (input, init) => requestUrl(input).pathname.startsWith(AUTH_PATH)
|
|
13
|
+
? fetch(input, init)
|
|
14
|
+
: fetchRetrying(fetch, retryDelaysMs, isTransientStatus, input, init);
|
|
15
|
+
const client = createClient(SUPABASE_URL, anonKey, {
|
|
16
|
+
auth: {
|
|
17
|
+
persistSession: false,
|
|
18
|
+
autoRefreshToken: false,
|
|
19
|
+
detectSessionInUrl: false,
|
|
20
|
+
},
|
|
21
|
+
db: { retry: false },
|
|
22
|
+
global: { fetch: supabaseFetch },
|
|
23
|
+
});
|
|
24
|
+
const { data, error } = await client.auth.refreshSession({
|
|
25
|
+
refresh_token: refreshToken,
|
|
26
|
+
});
|
|
27
|
+
if (error) {
|
|
28
|
+
if (isAuthRetryableFetchError(error) && isTransientStatus(error.status)) {
|
|
29
|
+
throw apiUnavailable(error.status);
|
|
30
|
+
}
|
|
31
|
+
if (isAuthApiError(error) && error.message === INVALID_API_KEY) {
|
|
32
|
+
throw new WikiMastersError(`Supabase rejected the site's public key (${error.message}); the site may have changed it`);
|
|
33
|
+
}
|
|
34
|
+
throw isAuthApiError(error) && SESSION_REJECTED_STATUSES.has(error.status)
|
|
35
|
+
? new AuthRequiredError(`The stored session is expired or revoked (${error.message})`)
|
|
36
|
+
: new WikiMastersError(`Resuming the session failed: ${error.message}`);
|
|
37
|
+
}
|
|
38
|
+
if (!data.session || !data.user) {
|
|
39
|
+
throw new WikiMastersError("Resuming the session returned no session");
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
client,
|
|
43
|
+
userId: data.user.id,
|
|
44
|
+
refreshToken: data.session.refresh_token,
|
|
45
|
+
fetch,
|
|
46
|
+
retryDelaysMs,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { authCookieHeader } from "./auth-cookie.js";
|
|
2
|
+
import { WikiMastersError, apiFailure, outcomeUnknown } from "./errors.js";
|
|
3
|
+
import { SITE_URL } from "./supabase.js";
|
|
4
|
+
import { fetchRetrying, isPossiblyDeliveredStatus, isTransientStatus, isUndeliveredStatus, } from "./transient.js";
|
|
5
|
+
export const SITE_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
6
|
+
export async function siteCookie(session) {
|
|
7
|
+
const { data, error } = await session.client.auth.getSession();
|
|
8
|
+
if (error || !data.session) {
|
|
9
|
+
throw new WikiMastersError("The session holds no access token");
|
|
10
|
+
}
|
|
11
|
+
return authCookieHeader(data.session);
|
|
12
|
+
}
|
|
13
|
+
export async function sendSiteRequest(session, cookie, action, fromPage, path, init) {
|
|
14
|
+
const isRead = init.method === "GET";
|
|
15
|
+
const hasBody = "body" in init;
|
|
16
|
+
const response = await fetchRetrying(session.fetch, session.retryDelaysMs, isRead ? isTransientStatus : isUndeliveredStatus, `${SITE_URL}${path}`, {
|
|
17
|
+
method: init.method,
|
|
18
|
+
headers: {
|
|
19
|
+
Cookie: cookie,
|
|
20
|
+
Origin: SITE_URL,
|
|
21
|
+
Referer: `${SITE_URL}${fromPage}`,
|
|
22
|
+
...(hasBody ? { "Content-Type": "application/json" } : {}),
|
|
23
|
+
},
|
|
24
|
+
...(hasBody ? { body: JSON.stringify(init.body) } : {}),
|
|
25
|
+
redirect: "manual",
|
|
26
|
+
});
|
|
27
|
+
const text = await response.text();
|
|
28
|
+
if (!isRead && isPossiblyDeliveredStatus(response.status)) {
|
|
29
|
+
throw outcomeUnknown(action, response.status);
|
|
30
|
+
}
|
|
31
|
+
if (isTransientStatus(response.status)) {
|
|
32
|
+
throw apiFailure(action, response.status, text);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
status: response.status,
|
|
36
|
+
ok: response.ok,
|
|
37
|
+
location: response.headers.get("location"),
|
|
38
|
+
body: text,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export async function siteRequest(session, cookie, action, fromPage, path, init) {
|
|
42
|
+
const { status, ok, body } = await sendSiteRequest(session, cookie, action, fromPage, path, init);
|
|
43
|
+
if (!ok)
|
|
44
|
+
throw apiFailure(action, status, body);
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(body);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
throw new WikiMastersError(`${action} returned no JSON: ${body}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=site.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.js","sourceRoot":"","sources":["../../src/core/site.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const SUPABASE_PROJECT_REF = "cyrxjeppjqsxxjayfrur";
|
|
2
|
+
export const SUPABASE_URL = `https://${SUPABASE_PROJECT_REF}.supabase.co`;
|
|
3
|
+
export const SITE_URL = "https://www.wiki-masters.com";
|
|
4
|
+
export const SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImN5cnhqZXBwanFzeHhqYXlmcnVyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzM4ODAzMzksImV4cCI6MjA4OTQ1NjMzOX0.BZluyXygNxuQGDPxFX1zG5i-cqp10CVK-8GGtuak4Rg";
|
|
5
|
+
//# sourceMappingURL=supabase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/core/supabase.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAC3D,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,oBAAoB,cAAc,CAAC;AAC1E,MAAM,CAAC,MAAM,QAAQ,GAAG,8BAA8B,CAAC;AACvD,MAAM,CAAC,MAAM,iBAAiB,GAC5B,kNAAkN,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WikiMastersError, apiFailure } from "./errors.js";
|
|
2
|
+
const TABLE_NAME = /^[A-Za-z0-9_]+$/;
|
|
3
|
+
export async function queryTable(session, query) {
|
|
4
|
+
const separator = query.indexOf("?");
|
|
5
|
+
const table = separator === -1 ? query : query.slice(0, separator);
|
|
6
|
+
if (!TABLE_NAME.test(table)) {
|
|
7
|
+
throw new WikiMastersError(`Invalid table name "${table}"`);
|
|
8
|
+
}
|
|
9
|
+
const params = new URLSearchParams(separator === -1 ? "" : query.slice(separator + 1));
|
|
10
|
+
const builder = session.client.from(table);
|
|
11
|
+
for (const [name, value] of params) {
|
|
12
|
+
if (name !== "select")
|
|
13
|
+
builder.url.searchParams.append(name, value);
|
|
14
|
+
}
|
|
15
|
+
const { data, error, status } = await builder.select(params.get("select") ?? "*");
|
|
16
|
+
if (error) {
|
|
17
|
+
throw apiFailure(`Querying ${table}`, status, [error.message, error.details, error.hint].filter(Boolean).join(" "));
|
|
18
|
+
}
|
|
19
|
+
return data;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=table-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-query.js","sourceRoot":"","sources":["../../src/core/table-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG3D,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAgB,EAChB,KAAa;IAEb,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACnE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,gBAAgB,CAAC,uBAAuB,KAAK,GAAG,CAAC,CAAC;IAC9D,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,eAAe,CAChC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CACnD,CAAC;IAEF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACnC,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,CAClD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAC5B,CAAC;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,UAAU,CACd,YAAY,KAAK,EAAE,EACnB,MAAM,EACN,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CACrE,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/core/tag.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { WikiMastersError, apiFailure } from "./errors.js";
|
|
2
|
+
export async function tagEntry(session, entryId, labelId) {
|
|
3
|
+
const { error, status } = await session.client
|
|
4
|
+
.from("user_card_tags")
|
|
5
|
+
.insert({ user_card_id: entryId, tag_id: labelId });
|
|
6
|
+
if (error) {
|
|
7
|
+
throw apiFailure(`Labelling entry ${entryId} with label ${labelId}`, status, error.message);
|
|
8
|
+
}
|
|
9
|
+
return { entryId, labelId };
|
|
10
|
+
}
|
|
11
|
+
export async function untagEntry(session, entryId, labelId) {
|
|
12
|
+
const action = `Removing label ${labelId} from entry ${entryId}`;
|
|
13
|
+
const { error, status, count } = await session.client
|
|
14
|
+
.from("user_card_tags")
|
|
15
|
+
.delete({ count: "exact" })
|
|
16
|
+
.eq("user_card_id", entryId)
|
|
17
|
+
.eq("tag_id", labelId);
|
|
18
|
+
if (error)
|
|
19
|
+
throw apiFailure(action, status, error.message);
|
|
20
|
+
if (count === null) {
|
|
21
|
+
throw new WikiMastersError(`${action} returned no row count (HTTP ${status})`);
|
|
22
|
+
}
|
|
23
|
+
return { entryId, labelId, removed: count > 0 };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=tag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/core/tag.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa3D,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAgB,EAChB,OAAgB,EAChB,OAAgB;IAEhB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM;SAC3C,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACtD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,UAAU,CACd,mBAAmB,OAAO,eAAe,OAAO,EAAE,EAClD,MAAM,EACN,KAAK,CAAC,OAAO,CACd,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAgB,EAChB,OAAgB,EAChB,OAAgB;IAEhB,MAAM,MAAM,GAAG,kBAAkB,OAAO,eAAe,OAAO,EAAE,CAAC;IACjE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM;SAClD,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;SAC1B,EAAE,CAAC,cAAc,EAAE,OAAO,CAAC;SAC3B,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzB,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3D,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,gBAAgB,CACxB,GAAG,MAAM,gCAAgC,MAAM,GAAG,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
|
+
// Cloudflare 52x meanings: https://developers.cloudflare.com/support/troubleshooting/http-status-codes/cloudflare-5xx-errors/
|
|
3
|
+
const TRANSIENT_STATUSES = new Map([
|
|
4
|
+
[502, "bad gateway"],
|
|
5
|
+
[503, "service unavailable"],
|
|
6
|
+
[504, "gateway timeout"],
|
|
7
|
+
[520, "web server returned an unknown error"],
|
|
8
|
+
[521, "web server is down"],
|
|
9
|
+
[522, "connection timed out"],
|
|
10
|
+
[523, "origin is unreachable"],
|
|
11
|
+
[524, "a timeout occurred"],
|
|
12
|
+
[525, "SSL handshake failed"],
|
|
13
|
+
[526, "invalid SSL certificate"],
|
|
14
|
+
]);
|
|
15
|
+
// Cloudflare answers these before forwarding the request to the origin.
|
|
16
|
+
const UNDELIVERED_STATUSES = new Set([521, 522, 523, 525, 526]);
|
|
17
|
+
export const RETRY_DELAYS_MS = [1_000, 2_000, 4_000];
|
|
18
|
+
export function isTransientStatus(status) {
|
|
19
|
+
return TRANSIENT_STATUSES.has(status);
|
|
20
|
+
}
|
|
21
|
+
export function isUndeliveredStatus(status) {
|
|
22
|
+
return UNDELIVERED_STATUSES.has(status);
|
|
23
|
+
}
|
|
24
|
+
export function isPossiblyDeliveredStatus(status) {
|
|
25
|
+
return isTransientStatus(status) && !isUndeliveredStatus(status);
|
|
26
|
+
}
|
|
27
|
+
export function describeTransientStatus(status) {
|
|
28
|
+
return TRANSIENT_STATUSES.get(status) ?? "server error";
|
|
29
|
+
}
|
|
30
|
+
export async function fetchRetrying(fetch, delaysMs, retryOn, input, init) {
|
|
31
|
+
for (const delayMs of delaysMs) {
|
|
32
|
+
const response = await fetch(input instanceof Request ? input.clone() : input, init);
|
|
33
|
+
if (!retryOn(response.status))
|
|
34
|
+
return response;
|
|
35
|
+
await response.body?.cancel();
|
|
36
|
+
await sleep(delayMs);
|
|
37
|
+
}
|
|
38
|
+
return fetch(input, init);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=transient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transient.js","sourceRoot":"","sources":["../../src/core/transient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE3D,8HAA8H;AAC9H,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAiB;IACjD,CAAC,GAAG,EAAE,aAAa,CAAC;IACpB,CAAC,GAAG,EAAE,qBAAqB,CAAC;IAC5B,CAAC,GAAG,EAAE,iBAAiB,CAAC;IACxB,CAAC,GAAG,EAAE,sCAAsC,CAAC;IAC7C,CAAC,GAAG,EAAE,oBAAoB,CAAC;IAC3B,CAAC,GAAG,EAAE,sBAAsB,CAAC;IAC7B,CAAC,GAAG,EAAE,uBAAuB,CAAC;IAC9B,CAAC,GAAG,EAAE,oBAAoB,CAAC;IAC3B,CAAC,GAAG,EAAE,sBAAsB,CAAC;IAC7B,CAAC,GAAG,EAAE,yBAAyB,CAAC;CACjC,CAAC,CAAC;AAEH,wEAAwE;AACxE,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAEhE,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAIxE,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,OAAO,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAAc;IACtD,OAAO,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAc;IACpD,OAAO,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,cAAc,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA8B,EAC9B,QAA2B,EAC3B,OAAuB,EACvB,KAA6B,EAC7B,IAAkB;IAElB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,EAChD,IAAI,CACL,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,QAAQ,CAAC;QAC/C,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAC9B,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WikiMastersError } from "./errors.js";
|
|
2
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3
|
+
export function parseUuid(raw, entity) {
|
|
4
|
+
const candidate = raw.trim().toLowerCase();
|
|
5
|
+
if (!UUID.test(candidate)) {
|
|
6
|
+
throw new WikiMastersError(`Invalid ${entity} id "${raw}": expected a UUID`);
|
|
7
|
+
}
|
|
8
|
+
return candidate;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=uuid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../src/core/uuid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,IAAI,GAAG,iEAAiE,CAAC;AAE/E,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,MAAc;IACnD,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,gBAAgB,CACxB,WAAW,MAAM,QAAQ,GAAG,oBAAoB,CACjD,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { WikiMastersError, apiFailure, isUniqueViolation } from "./errors.js";
|
|
2
|
+
export async function listWishlist(session) {
|
|
3
|
+
const { data, error, status } = await session.client
|
|
4
|
+
.from("wishlist_items")
|
|
5
|
+
.select("card_id, cards(id, wikipedia_title, rarity, user_cards(card_id))")
|
|
6
|
+
.eq("user_id", session.userId)
|
|
7
|
+
.eq("cards.user_cards.user_id", session.userId)
|
|
8
|
+
.gt("cards.user_cards.count", 0)
|
|
9
|
+
.order("created_at", { ascending: false })
|
|
10
|
+
.overrideTypes();
|
|
11
|
+
if (error) {
|
|
12
|
+
throw apiFailure("Listing the wishlist", status, error.message);
|
|
13
|
+
}
|
|
14
|
+
return data.map(({ card_id, cards }) => {
|
|
15
|
+
if (!cards) {
|
|
16
|
+
throw new WikiMastersError(`Wishlist card ${card_id} has no readable card details`);
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
id: cards.id,
|
|
20
|
+
title: cards.wikipedia_title,
|
|
21
|
+
rarity: cards.rarity,
|
|
22
|
+
owned: cards.user_cards.length > 0,
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export async function addToWishlist(session, cardId) {
|
|
27
|
+
const { data, error, status } = await session.client
|
|
28
|
+
.from("cards")
|
|
29
|
+
.select("wikipedia_title, wishlist_items(card_id)")
|
|
30
|
+
.eq("id", cardId)
|
|
31
|
+
.eq("wishlist_items.user_id", session.userId)
|
|
32
|
+
.maybeSingle();
|
|
33
|
+
if (error) {
|
|
34
|
+
throw apiFailure(`Reading card ${cardId} in the catalogue`, status, error.message);
|
|
35
|
+
}
|
|
36
|
+
if (!data) {
|
|
37
|
+
throw new WikiMastersError(`Card ${cardId} is not in the card catalogue; nothing was changed`);
|
|
38
|
+
}
|
|
39
|
+
const title = data.wikipedia_title;
|
|
40
|
+
if (data.wishlist_items.length > 0)
|
|
41
|
+
return { cardId, title, added: false };
|
|
42
|
+
const insert = await session.client
|
|
43
|
+
.from("wishlist_items")
|
|
44
|
+
.insert({ user_id: session.userId, card_id: cardId });
|
|
45
|
+
if (isUniqueViolation(insert.error))
|
|
46
|
+
return { cardId, title, added: false };
|
|
47
|
+
if (insert.error) {
|
|
48
|
+
throw apiFailure(`Adding card ${cardId} to the wishlist`, insert.status, insert.error.message);
|
|
49
|
+
}
|
|
50
|
+
return { cardId, title, added: true };
|
|
51
|
+
}
|
|
52
|
+
export async function removeFromWishlist(session, cardId) {
|
|
53
|
+
const { error, status, count } = await session.client
|
|
54
|
+
.from("wishlist_items")
|
|
55
|
+
.delete({ count: "exact" })
|
|
56
|
+
.eq("user_id", session.userId)
|
|
57
|
+
.eq("card_id", cardId);
|
|
58
|
+
if (error) {
|
|
59
|
+
throw apiFailure(`Removing card ${cardId} from the wishlist`, status, error.message);
|
|
60
|
+
}
|
|
61
|
+
if (count === null) {
|
|
62
|
+
throw new WikiMastersError(`Removing card ${cardId} from the wishlist returned no row count (HTTP ${status})`);
|
|
63
|
+
}
|
|
64
|
+
return { cardId, removed: count > 0 };
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=wishlist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wishlist.js","sourceRoot":"","sources":["../../src/core/wishlist.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikimasters-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Interact with WikiMasters from the command line",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"wikimasters": "dist/cli/main.js"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=22.13.0"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.build.json",
|
|
15
|
+
"build:tools": "tsc -p tsconfig.tools.json",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"lint": "biome lint src tools",
|
|
19
|
+
"lint:fix": "biome lint --write src tools",
|
|
20
|
+
"format": "biome format --write src tools",
|
|
21
|
+
"format:check": "biome format src tools",
|
|
22
|
+
"wikimasters": "node dist/cli/main.js",
|
|
23
|
+
"api:get": "npm run -s build:tools && node dist-tools/tools/api-get.js",
|
|
24
|
+
"api:site": "npm run -s build:tools && node dist-tools/tools/api-site.js",
|
|
25
|
+
"prepack": "node --eval \"fs.rmSync('dist', { recursive: true, force: true })\" && npm run build"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@supabase/supabase-js": "^2.117.2",
|
|
29
|
+
"commander": "^15.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@biomejs/biome": "2.5.15",
|
|
33
|
+
"@types/node": "^22.20.4",
|
|
34
|
+
"typescript": "^7.0.2",
|
|
35
|
+
"vitest": "^5.0.2"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/qpautrat/wikimasters-cli.git"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist"
|
|
43
|
+
]
|
|
44
|
+
}
|