@openrails/contentkit-ui 0.97.1 → 0.98.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/README.md +57 -4
- package/dist/client/beacons.d.ts +17 -7
- package/dist/client/beacons.js +205 -41
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/browser-reader-preferences.d.ts +15 -2
- package/dist/client/browser-reader-preferences.js +67 -30
- package/dist/client/browser-reader-preferences.js.map +1 -1
- package/dist/client/discovery.d.ts +13 -3
- package/dist/client/discovery.js +31 -16
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/generated/routes.d.ts +14 -1
- package/dist/client/generated/routes.js +18 -0
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +47 -4
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/http.d.ts +7 -3
- package/dist/client/http.js +26 -7
- package/dist/client/http.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/reader-preferences.d.ts +7 -0
- package/dist/client/reader-preferences.js +16 -4
- package/dist/client/reader-preferences.js.map +1 -1
- package/dist/client.js +17 -17
- package/dist/components/content/card.js +50 -40
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/filters.d.ts +5 -0
- package/dist/components/content/filters.js +61 -52
- package/dist/components/content/filters.js.map +1 -1
- package/dist/components/content/popular.d.ts +1 -1
- package/dist/components/content/popular.js.map +1 -1
- package/dist/components/content/reader-settings.d.ts +4 -0
- package/dist/components/content/reader-settings.js +3 -1
- package/dist/components/content/reader-settings.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/react/discovery.d.ts +7 -2
- package/dist/react/discovery.js +208 -87
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/provider.js +4 -1
- package/dist/react/provider.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
//#region src/client/browser-reader-preferences.ts
|
|
2
2
|
var e = Object.freeze({
|
|
3
|
-
|
|
3
|
+
kinds: Object.freeze({}),
|
|
4
|
+
legacy_filters: Object.freeze([]),
|
|
4
5
|
registrations: Object.freeze([])
|
|
5
6
|
});
|
|
6
7
|
function t(e) {
|
|
@@ -13,36 +14,70 @@ function t(e) {
|
|
|
13
14
|
function n(e) {
|
|
14
15
|
if (!Array.isArray(e)) return [];
|
|
15
16
|
let t = /* @__PURE__ */ new Map();
|
|
16
|
-
for (let n of e
|
|
17
|
+
for (let n of e) n && typeof (n.entity_id ?? n.group_id) == "string" && (n.entity_id ?? n.group_id).length > 0 && (n.entity_id ?? n.group_id).length <= 128 && typeof n.visible == "boolean" && t.set(n.entity_id ?? n.group_id, n.visible);
|
|
17
18
|
return [...t].sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => ({
|
|
18
|
-
|
|
19
|
+
entity_id: e,
|
|
19
20
|
visible: t
|
|
20
21
|
}));
|
|
21
22
|
}
|
|
22
|
-
function r(
|
|
23
|
+
function r(e) {
|
|
24
|
+
if (!Array.isArray(e)) return [];
|
|
25
|
+
let t = /* @__PURE__ */ new Map();
|
|
26
|
+
for (let n of e) {
|
|
27
|
+
let e = n?.entity_id;
|
|
28
|
+
typeof e != "string" || !e || e.length > 128 || (n.default === !0 && n.visible === void 0 ? t.set(e, {
|
|
29
|
+
entity_id: e,
|
|
30
|
+
default: !0
|
|
31
|
+
}) : n.default === void 0 && typeof n.visible == "boolean" && t.set(e, {
|
|
32
|
+
entity_id: e,
|
|
33
|
+
visible: n.visible
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
return [...t].sort(([e], [t]) => e.localeCompare(t)).map(([, e]) => e);
|
|
37
|
+
}
|
|
38
|
+
function i(e) {
|
|
39
|
+
return !e || typeof e != "object" || Array.isArray(e) ? {} : Object.fromEntries(Object.entries(e).filter(([e]) => /^[a-z][a-z0-9_]*$/.test(e)).sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => [e, r(t)]));
|
|
40
|
+
}
|
|
41
|
+
function a(e) {
|
|
42
|
+
return {
|
|
43
|
+
kinds: i(e.kinds),
|
|
44
|
+
legacy_filters: n(e.legacy_filters ?? e.filters)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function o(e) {
|
|
48
|
+
return e.legacy_filters.length > 0 || Object.values(e.kinds).some((e) => e.length > 0);
|
|
49
|
+
}
|
|
50
|
+
function s(e) {
|
|
51
|
+
return {
|
|
52
|
+
language: e.language,
|
|
53
|
+
kinds: Object.freeze(Object.fromEntries(Object.entries(e.kinds).map(([e, t]) => [e, Object.freeze(t.map((e) => Object.freeze({ ...e })))]))),
|
|
54
|
+
legacy_filters: Object.freeze(e.legacy_filters.map((e) => Object.freeze({ ...e })))
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function c(n) {
|
|
23
58
|
try {
|
|
24
|
-
let
|
|
25
|
-
if (!
|
|
26
|
-
let
|
|
27
|
-
if (Array.isArray(
|
|
59
|
+
let r = JSON.parse(n ?? "{}");
|
|
60
|
+
if (!r || typeof r != "object") return e;
|
|
61
|
+
let i = r, o = [];
|
|
62
|
+
if (Array.isArray(i.registrations)) for (let e of i.registrations.slice(0, 20)) !e || typeof e.account != "string" || !e.account || e.account.length > 128 || o.some((t) => t.account === e.account) || o.push({
|
|
28
63
|
account: e.account,
|
|
29
64
|
language: t(e.language),
|
|
30
|
-
|
|
65
|
+
...a(e),
|
|
31
66
|
languageDone: e.languageDone === !0,
|
|
32
67
|
filtersDone: e.filtersDone === !0,
|
|
33
68
|
languageObserved: e.languageObserved === !0,
|
|
34
69
|
initialLanguage: e.initialLanguage === null ? null : t(e.initialLanguage)
|
|
35
70
|
});
|
|
36
71
|
return {
|
|
37
|
-
language: t(
|
|
38
|
-
|
|
72
|
+
language: t(i.language),
|
|
73
|
+
...a(i),
|
|
39
74
|
registrations: o
|
|
40
75
|
};
|
|
41
76
|
} catch {
|
|
42
77
|
return e;
|
|
43
78
|
}
|
|
44
79
|
}
|
|
45
|
-
var
|
|
80
|
+
var l = class {
|
|
46
81
|
key;
|
|
47
82
|
browser;
|
|
48
83
|
value = e;
|
|
@@ -68,7 +103,7 @@ var i = class {
|
|
|
68
103
|
setFilters(e) {
|
|
69
104
|
this.sync(), this.save({
|
|
70
105
|
...this.value,
|
|
71
|
-
|
|
106
|
+
kinds: i(e)
|
|
72
107
|
});
|
|
73
108
|
}
|
|
74
109
|
pending(e) {
|
|
@@ -76,16 +111,17 @@ var i = class {
|
|
|
76
111
|
}
|
|
77
112
|
register(e) {
|
|
78
113
|
if (this.sync(), !e || e.length > 128) throw Error("contentkit: registration account is required");
|
|
79
|
-
if (!this.pending(e) && (this.value.language || this.value
|
|
114
|
+
if (!this.pending(e) && (this.value.language || o(this.value))) {
|
|
80
115
|
if (this.value.registrations.length >= 20) throw Error("contentkit: too many pending preference registrations");
|
|
81
116
|
this.save({
|
|
82
117
|
...this.value,
|
|
83
118
|
registrations: [...this.value.registrations, {
|
|
84
119
|
account: e,
|
|
85
120
|
language: this.value.language,
|
|
86
|
-
|
|
121
|
+
kinds: this.value.kinds,
|
|
122
|
+
legacy_filters: this.value.legacy_filters,
|
|
87
123
|
languageDone: !this.value.language,
|
|
88
|
-
filtersDone: !this.value
|
|
124
|
+
filtersDone: !o(this.value)
|
|
89
125
|
}]
|
|
90
126
|
});
|
|
91
127
|
}
|
|
@@ -116,7 +152,7 @@ var i = class {
|
|
|
116
152
|
};
|
|
117
153
|
sync() {
|
|
118
154
|
if (this.browser && !this.unavailable) try {
|
|
119
|
-
this.replace(
|
|
155
|
+
this.replace(c(this.browser.localStorage.getItem(this.key)));
|
|
120
156
|
} catch {
|
|
121
157
|
this.unavailable = !0;
|
|
122
158
|
}
|
|
@@ -132,41 +168,42 @@ var i = class {
|
|
|
132
168
|
replace(e) {
|
|
133
169
|
let t = JSON.stringify({
|
|
134
170
|
language: e.language,
|
|
135
|
-
|
|
171
|
+
kinds: e.kinds,
|
|
172
|
+
legacy_filters: e.legacy_filters,
|
|
136
173
|
registrations: e.registrations
|
|
137
174
|
});
|
|
138
175
|
if (t === this.encoded) return;
|
|
139
176
|
this.encoded = t, this.value = Object.freeze({
|
|
140
|
-
...e,
|
|
141
|
-
filters: Object.freeze(e.filters.map((e) => Object.freeze({ ...e }))),
|
|
177
|
+
...s(e),
|
|
142
178
|
registrations: Object.freeze(e.registrations.map((e) => Object.freeze({
|
|
143
179
|
...e,
|
|
144
|
-
|
|
180
|
+
...s(e)
|
|
145
181
|
})))
|
|
146
182
|
});
|
|
147
183
|
let n = {
|
|
148
184
|
language: this.value.language,
|
|
149
|
-
|
|
185
|
+
kinds: this.value.kinds,
|
|
186
|
+
legacy_filters: this.value.legacy_filters
|
|
150
187
|
};
|
|
151
188
|
JSON.stringify(n) !== JSON.stringify(this.publicValue) && (this.publicValue = Object.freeze(n));
|
|
152
189
|
for (let e of this.listeners) try {
|
|
153
190
|
e();
|
|
154
191
|
} catch {}
|
|
155
192
|
}
|
|
156
|
-
},
|
|
157
|
-
function
|
|
193
|
+
}, u = /* @__PURE__ */ new WeakMap();
|
|
194
|
+
function d(e) {
|
|
158
195
|
let t = typeof window > "u" ? void 0 : window, n = e.replace(/\/+$/, "");
|
|
159
196
|
if (t) try {
|
|
160
197
|
n = new URL(n, t.location.href).href;
|
|
161
198
|
} catch {}
|
|
162
199
|
let r = `contentkit:reader-preferences:v1:${n}`;
|
|
163
|
-
if (!t) return new
|
|
164
|
-
let
|
|
165
|
-
|
|
166
|
-
let
|
|
167
|
-
return
|
|
200
|
+
if (!t) return new l(r);
|
|
201
|
+
let i = u.get(t);
|
|
202
|
+
i || u.set(t, i = /* @__PURE__ */ new Map());
|
|
203
|
+
let a = i.get(r);
|
|
204
|
+
return a || i.set(r, a = new l(r, t)), a;
|
|
168
205
|
}
|
|
169
206
|
//#endregion
|
|
170
|
-
export {
|
|
207
|
+
export { l as BrowserReaderPreferences, d as browserReaderPreferences };
|
|
171
208
|
|
|
172
209
|
//# sourceMappingURL=browser-reader-preferences.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-reader-preferences.js","names":[],"sources":["../../src/client/browser-reader-preferences.ts"],"sourcesContent":["import type { FilterSetting } from \"./generated/wire.js\";\n\nexport interface GuestReaderPreferences {\n language?: string;\n filters: readonly FilterSetting[];\n}\n\nexport interface PendingReaderPreferences extends GuestReaderPreferences {\n account: string;\n languageDone: boolean;\n filtersDone: boolean;\n languageObserved?: boolean;\n initialLanguage?: string | null;\n}\n\ntype Document = GuestReaderPreferences & { registrations: readonly PendingReaderPreferences[] };\nconst EMPTY: Document = Object.freeze({ filters: Object.freeze([]), registrations: Object.freeze([]) });\n\nfunction language(value: unknown): string | undefined {\n if (typeof value !== \"string\" || value.length > 64) return;\n try { return Intl.getCanonicalLocales(value)[0]; } catch { return; }\n}\n\nfunction filters(value: unknown): FilterSetting[] {\n if (!Array.isArray(value)) return [];\n const entries = new Map<string, boolean>();\n for (const row of value.slice(0, 100)) {\n if (row && typeof row.group_id === \"string\" && row.group_id.length > 0 && row.group_id.length <= 128 && typeof row.visible === \"boolean\") entries.set(row.group_id, row.visible);\n }\n return [...entries].sort(([a], [b]) => a.localeCompare(b)).map(([group_id, visible]) => ({ group_id, visible }));\n}\n\nfunction decode(raw: string | null): Document {\n try {\n const data: unknown = JSON.parse(raw ?? \"{}\");\n if (!data || typeof data !== \"object\") return EMPTY;\n const value = data as Record<string, unknown>;\n const registrations: PendingReaderPreferences[] = [];\n if (Array.isArray(value.registrations)) {\n for (const entry of value.registrations.slice(0, 20)) {\n if (!entry || typeof entry.account !== \"string\" || !entry.account || entry.account.length > 128 || registrations.some((r) => r.account === entry.account)) continue;\n registrations.push({ account: entry.account, language: language(entry.language), filters: filters(entry.filters), languageDone: entry.languageDone === true, filtersDone: entry.filtersDone === true,\n languageObserved: entry.languageObserved === true, initialLanguage: entry.initialLanguage === null ? null : language(entry.initialLanguage) });\n }\n }\n return { language: language(value.language), filters: filters(value.filters), registrations };\n } catch { return EMPTY; }\n}\n\n/** Anonymous preferences and registration retries, isolated to one app URL. */\nexport class BrowserReaderPreferences {\n private value: Document = EMPTY;\n private publicValue: GuestReaderPreferences = EMPTY;\n private encoded = JSON.stringify(EMPTY);\n private unavailable = false;\n private readonly listeners = new Set<() => void>();\n\n constructor(private readonly key: string, private readonly browser?: Window) { this.sync(); }\n\n readonly snapshot = (): GuestReaderPreferences => this.publicValue;\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.sync();\n if (!this.listeners.size) this.browser?.addEventListener(\"storage\", this.onStorage);\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n if (!this.listeners.size) this.browser?.removeEventListener(\"storage\", this.onStorage);\n };\n };\n\n setLanguage(value: string): void {\n const next = language(value);\n if (!next) throw new Error(\"contentkit: invalid preferred language\");\n this.sync();\n this.save({ ...this.value, language: next });\n }\n\n setFilters(value: readonly FilterSetting[]): void {\n this.sync();\n this.save({ ...this.value, filters: filters(value) });\n }\n\n pending(account: string): PendingReaderPreferences | undefined {\n this.sync();\n return this.value.registrations.find((r) => r.account === account);\n }\n\n /** Capture only on a confirmed registration, never on a login transition. */\n register(account: string): void {\n this.sync();\n if (!account || account.length > 128) throw new Error(\"contentkit: registration account is required\");\n if (this.pending(account)) return;\n if (!this.value.language && !this.value.filters.length) return;\n if (this.value.registrations.length >= 20) throw new Error(\"contentkit: too many pending preference registrations\");\n this.save({ ...this.value, registrations: [...this.value.registrations, {\n account, language: this.value.language, filters: this.value.filters,\n languageDone: !this.value.language, filtersDone: !this.value.filters.length,\n }] });\n }\n\n complete(account: string, step: \"language\" | \"filters\"): void {\n this.sync();\n const registrations = this.value.registrations.map((r) => r.account === account ? { ...r, [step === \"language\" ? \"languageDone\" : \"filtersDone\"]: true } : r)\n .filter((r) => !r.languageDone || !r.filtersDone);\n this.save({ ...this.value, registrations });\n }\n\n observeLanguage(account: string, initialLanguage: string | null): void {\n this.sync();\n this.save({ ...this.value, registrations: this.value.registrations.map((r) => r.account === account && !r.languageObserved ? { ...r, languageObserved: true, initialLanguage } : r) });\n }\n\n private readonly onStorage = (event: StorageEvent): void => {\n if (event.key === null || event.key === this.key) this.sync();\n };\n\n private sync(): void {\n if (!this.browser || this.unavailable) return;\n try { this.replace(decode(this.browser.localStorage.getItem(this.key))); }\n catch { this.unavailable = true; }\n }\n\n private save(next: Document): void {\n if (this.browser && !this.unavailable) {\n try { this.browser.localStorage.setItem(this.key, JSON.stringify(next)); }\n catch { this.unavailable = true; }\n }\n this.replace(next);\n }\n\n private replace(next: Document): void {\n const encoded = JSON.stringify({ language: next.language, filters: next.filters, registrations: next.registrations });\n if (encoded === this.encoded) return;\n this.encoded = encoded;\n this.value = Object.freeze({ ...next, filters: Object.freeze(next.filters.map((f) => Object.freeze({ ...f }))), registrations: Object.freeze(next.registrations.map((r) => Object.freeze({ ...r, filters: Object.freeze(r.filters.map((f) => Object.freeze({ ...f }))) }))) });\n const publicValue = { language: this.value.language, filters: this.value.filters };\n if (JSON.stringify(publicValue) !== JSON.stringify(this.publicValue)) this.publicValue = Object.freeze(publicValue);\n for (const listener of this.listeners) { try { listener(); } catch { /* Observers do not own persistence. */ } }\n }\n}\n\nconst stores = new WeakMap<Window, Map<string, BrowserReaderPreferences>>();\n\n/** Same-app clients share a store; server-rendered requests never do. */\nexport function browserReaderPreferences(mount: string): BrowserReaderPreferences {\n const browser = typeof window === \"undefined\" ? undefined : window;\n let scope = mount.replace(/\\/+$/, \"\");\n if (browser) { try { scope = new URL(scope, browser.location.href).href; } catch { /* Keep the explicit app key. */ } }\n const key = `contentkit:reader-preferences:v1:${scope}`;\n if (!browser) return new BrowserReaderPreferences(key);\n let scoped = stores.get(browser);\n if (!scoped) stores.set(browser, (scoped = new Map()));\n let store = scoped.get(key);\n if (!store) scoped.set(key, (store = new BrowserReaderPreferences(key, browser)));\n return store;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"browser-reader-preferences.js","names":[],"sources":["../../src/client/browser-reader-preferences.ts"],"sourcesContent":["import type { FilterSetting } from \"./generated/wire.js\";\n\n/** Explicit visibility or a reset that follows the current domain default. */\nexport type ReaderFilterChoice = { entity_id: string; visible: boolean; default?: never } | { entity_id: string; default: true; visible?: never };\nexport type ReaderFilterKinds = Record<string, readonly ReaderFilterChoice[]>;\n\nexport interface GuestReaderPreferences {\n language?: string;\n kinds: ReaderFilterKinds;\n /** Choices saved before content kinds were introduced. Explicit kind choices win. */\n legacy_filters: readonly FilterSetting[];\n}\n\nexport interface PendingReaderPreferences extends GuestReaderPreferences {\n account: string;\n languageDone: boolean;\n filtersDone: boolean;\n languageObserved?: boolean;\n initialLanguage?: string | null;\n}\n\ntype Document = GuestReaderPreferences & { registrations: readonly PendingReaderPreferences[] };\nconst EMPTY: Document = Object.freeze({ kinds: Object.freeze({}), legacy_filters: Object.freeze([]), registrations: Object.freeze([]) });\n\nfunction language(value: unknown): string | undefined {\n if (typeof value !== \"string\" || value.length > 64) return;\n try { return Intl.getCanonicalLocales(value)[0]; } catch { return; }\n}\n\nfunction filters(value: unknown): FilterSetting[] {\n if (!Array.isArray(value)) return [];\n const entries = new Map<string, boolean>();\n for (const row of value) {\n if (row && typeof (row.entity_id ?? row.group_id) === \"string\" && (row.entity_id ?? row.group_id).length > 0 && (row.entity_id ?? row.group_id).length <= 128 && typeof row.visible === \"boolean\") entries.set(row.entity_id ?? row.group_id, row.visible);\n }\n return [...entries].sort(([a], [b]) => a.localeCompare(b)).map(([entity_id, visible]) => ({ entity_id, visible }));\n}\n\nfunction scopedFilters(value: unknown): ReaderFilterChoice[] {\n if (!Array.isArray(value)) return [];\n const entries = new Map<string, ReaderFilterChoice>();\n for (const row of value) {\n const id = row?.entity_id;\n if (typeof id !== \"string\" || !id || id.length > 128) continue;\n if (row.default === true && row.visible === undefined) entries.set(id, { entity_id: id, default: true });\n else if (row.default === undefined && typeof row.visible === \"boolean\") entries.set(id, { entity_id: id, visible: row.visible });\n }\n return [...entries].sort(([a], [b]) => a.localeCompare(b)).map(([, row]) => row);\n}\n\nfunction kinds(value: unknown): ReaderFilterKinds {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return {};\n return Object.fromEntries(Object.entries(value)\n .filter(([kind]) => /^[a-z][a-z0-9_]*$/.test(kind))\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([kind, value]) => [kind, scopedFilters(value)]));\n}\n\nfunction choices(value: Record<string, unknown>) {\n return { kinds: kinds(value.kinds), legacy_filters: filters(value.legacy_filters ?? value.filters) };\n}\n\nfunction hasChoices(value: GuestReaderPreferences): boolean {\n return value.legacy_filters.length > 0 || Object.values(value.kinds).some((rows) => rows.length > 0);\n}\n\nfunction freezeChoices(value: GuestReaderPreferences): GuestReaderPreferences {\n return { language: value.language,\n kinds: Object.freeze(Object.fromEntries(Object.entries(value.kinds).map(([kind, rows]) => [kind, Object.freeze(rows.map((f) => Object.freeze({ ...f })))]))),\n legacy_filters: Object.freeze(value.legacy_filters.map((f) => Object.freeze({ ...f }))) };\n}\n\nfunction decode(raw: string | null): Document {\n try {\n const data: unknown = JSON.parse(raw ?? \"{}\");\n if (!data || typeof data !== \"object\") return EMPTY;\n const value = data as Record<string, unknown>;\n const registrations: PendingReaderPreferences[] = [];\n if (Array.isArray(value.registrations)) {\n for (const entry of value.registrations.slice(0, 20)) {\n if (!entry || typeof entry.account !== \"string\" || !entry.account || entry.account.length > 128 || registrations.some((r) => r.account === entry.account)) continue;\n registrations.push({ account: entry.account, language: language(entry.language), ...choices(entry), languageDone: entry.languageDone === true, filtersDone: entry.filtersDone === true,\n languageObserved: entry.languageObserved === true, initialLanguage: entry.initialLanguage === null ? null : language(entry.initialLanguage) });\n }\n }\n return { language: language(value.language), ...choices(value), registrations };\n } catch { return EMPTY; }\n}\n\n/** Anonymous preferences and registration retries, isolated to one app URL. */\nexport class BrowserReaderPreferences {\n private value: Document = EMPTY;\n private publicValue: GuestReaderPreferences = EMPTY;\n private encoded = JSON.stringify(EMPTY);\n private unavailable = false;\n private readonly listeners = new Set<() => void>();\n\n constructor(private readonly key: string, private readonly browser?: Window) { this.sync(); }\n\n readonly snapshot = (): GuestReaderPreferences => this.publicValue;\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.sync();\n if (!this.listeners.size) this.browser?.addEventListener(\"storage\", this.onStorage);\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n if (!this.listeners.size) this.browser?.removeEventListener(\"storage\", this.onStorage);\n };\n };\n\n setLanguage(value: string): void {\n const next = language(value);\n if (!next) throw new Error(\"contentkit: invalid preferred language\");\n this.sync();\n this.save({ ...this.value, language: next });\n }\n\n setFilters(value: ReaderFilterKinds): void {\n this.sync();\n this.save({ ...this.value, kinds: kinds(value) });\n }\n\n pending(account: string): PendingReaderPreferences | undefined {\n this.sync();\n return this.value.registrations.find((r) => r.account === account);\n }\n\n /** Capture only on a confirmed registration, never on a login transition. */\n register(account: string): void {\n this.sync();\n if (!account || account.length > 128) throw new Error(\"contentkit: registration account is required\");\n if (this.pending(account)) return;\n if (!this.value.language && !hasChoices(this.value)) return;\n if (this.value.registrations.length >= 20) throw new Error(\"contentkit: too many pending preference registrations\");\n this.save({ ...this.value, registrations: [...this.value.registrations, {\n account, language: this.value.language, kinds: this.value.kinds, legacy_filters: this.value.legacy_filters,\n languageDone: !this.value.language, filtersDone: !hasChoices(this.value),\n }] });\n }\n\n complete(account: string, step: \"language\" | \"filters\"): void {\n this.sync();\n const registrations = this.value.registrations.map((r) => r.account === account ? { ...r, [step === \"language\" ? \"languageDone\" : \"filtersDone\"]: true } : r)\n .filter((r) => !r.languageDone || !r.filtersDone);\n this.save({ ...this.value, registrations });\n }\n\n observeLanguage(account: string, initialLanguage: string | null): void {\n this.sync();\n this.save({ ...this.value, registrations: this.value.registrations.map((r) => r.account === account && !r.languageObserved ? { ...r, languageObserved: true, initialLanguage } : r) });\n }\n\n private readonly onStorage = (event: StorageEvent): void => {\n if (event.key === null || event.key === this.key) this.sync();\n };\n\n private sync(): void {\n if (!this.browser || this.unavailable) return;\n try { this.replace(decode(this.browser.localStorage.getItem(this.key))); }\n catch { this.unavailable = true; }\n }\n\n private save(next: Document): void {\n if (this.browser && !this.unavailable) {\n try { this.browser.localStorage.setItem(this.key, JSON.stringify(next)); }\n catch { this.unavailable = true; }\n }\n this.replace(next);\n }\n\n private replace(next: Document): void {\n const encoded = JSON.stringify({ language: next.language, kinds: next.kinds, legacy_filters: next.legacy_filters, registrations: next.registrations });\n if (encoded === this.encoded) return;\n this.encoded = encoded;\n this.value = Object.freeze({ ...freezeChoices(next), registrations: Object.freeze(next.registrations.map((r) => Object.freeze({ ...r, ...freezeChoices(r) }))) });\n const publicValue = { language: this.value.language, kinds: this.value.kinds, legacy_filters: this.value.legacy_filters };\n if (JSON.stringify(publicValue) !== JSON.stringify(this.publicValue)) this.publicValue = Object.freeze(publicValue);\n for (const listener of this.listeners) { try { listener(); } catch { /* Observers do not own persistence. */ } }\n }\n}\n\nconst stores = new WeakMap<Window, Map<string, BrowserReaderPreferences>>();\n\n/** Same-app clients share a store; server-rendered requests never do. */\nexport function browserReaderPreferences(mount: string): BrowserReaderPreferences {\n const browser = typeof window === \"undefined\" ? undefined : window;\n let scope = mount.replace(/\\/+$/, \"\");\n if (browser) { try { scope = new URL(scope, browser.location.href).href; } catch { /* Keep the explicit app key. */ } }\n const key = `contentkit:reader-preferences:v1:${scope}`;\n if (!browser) return new BrowserReaderPreferences(key);\n let scoped = stores.get(browser);\n if (!scoped) stores.set(browser, (scoped = new Map()));\n let store = scoped.get(key);\n if (!store) scoped.set(key, (store = new BrowserReaderPreferences(key, browser)));\n return store;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, ExposureInput, RecentSearches, ReleaseDates, SignalInput, Typeahead } from './generated/wire.js';
|
|
1
|
+
import { ActivityContexts, ActivityTarget, ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, ExposureInput, RecentSearches, ReleaseDates, SignalInput, Typeahead } from './generated/wire.js';
|
|
2
2
|
import { Http } from './http.js';
|
|
3
3
|
import { BrowserSearchHistory } from './browser-search-history.js';
|
|
4
4
|
/** A popularity period. */
|
|
@@ -53,11 +53,19 @@ export interface PageQuery {
|
|
|
53
53
|
}
|
|
54
54
|
export type ContentQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & {
|
|
55
55
|
sort?: ListSort;
|
|
56
|
+
/** Inclusive UTC date (YYYY-MM-DD); requires activity_until, kind and sort=popular. */
|
|
57
|
+
activity_from?: string;
|
|
58
|
+
/** Exclusive UTC date (YYYY-MM-DD); requires activity_from, kind and sort=popular. */
|
|
59
|
+
activity_until?: string;
|
|
56
60
|
};
|
|
57
61
|
export type PopularPeriod = "7d" | "90d" | "365d" | "all";
|
|
58
|
-
export type PopularQuery = Omit<ContentQuery, "sort" | "
|
|
59
|
-
/**
|
|
62
|
+
export type PopularQuery = Omit<ContentQuery, "sort" | "activity_from" | "activity_until">;
|
|
63
|
+
/** Rank activity in the selected window; publication age is an optional separate filter. */
|
|
60
64
|
export declare function popularQuery(period?: PopularPeriod, filters?: PopularQuery): ContentQuery;
|
|
65
|
+
/** Rank activity between two UTC dates: from inclusive, until exclusive. */
|
|
66
|
+
export declare function popularBetween(from: string, until: string, filters: PopularQuery & {
|
|
67
|
+
kind: string;
|
|
68
|
+
}): ContentQuery;
|
|
61
69
|
export type SearchQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & {
|
|
62
70
|
q: string;
|
|
63
71
|
sort?: "relevance" | ListSort;
|
|
@@ -138,6 +146,8 @@ export declare class DiscoveryClient {
|
|
|
138
146
|
kind?: string;
|
|
139
147
|
content_id?: string;
|
|
140
148
|
}): Promise<void>;
|
|
149
|
+
/** Capture server-owned access and eligibility at an observation's start. */
|
|
150
|
+
activityContexts(targets: readonly ActivityTarget[], session?: string, language?: string | undefined): Promise<ActivityContexts>;
|
|
141
151
|
/** Views and clicks; signed out, of the session named. */
|
|
142
152
|
signals(signals: SignalInput[], session?: string, o?: {
|
|
143
153
|
keepalive?: boolean;
|
package/dist/client/discovery.js
CHANGED
|
@@ -4,11 +4,18 @@ import { browserSearchHistory as n } from "./browser-search-history.js";
|
|
|
4
4
|
function r(e = "7d", t = {}) {
|
|
5
5
|
return {
|
|
6
6
|
...t,
|
|
7
|
-
sort: `popular:${e}
|
|
8
|
-
published_within: e
|
|
7
|
+
sort: `popular:${e}`
|
|
9
8
|
};
|
|
10
9
|
}
|
|
11
|
-
|
|
10
|
+
function i(e, t, n) {
|
|
11
|
+
return {
|
|
12
|
+
...n,
|
|
13
|
+
sort: "popular",
|
|
14
|
+
activity_from: e,
|
|
15
|
+
activity_until: t
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
var a = /* @__PURE__ */ new Set([
|
|
12
19
|
"groups",
|
|
13
20
|
"exclude_groups",
|
|
14
21
|
"creators",
|
|
@@ -18,12 +25,12 @@ var i = /* @__PURE__ */ new Set([
|
|
|
18
25
|
"card_entities",
|
|
19
26
|
"entity_kinds"
|
|
20
27
|
]);
|
|
21
|
-
function
|
|
28
|
+
function o(e) {
|
|
22
29
|
let t = {};
|
|
23
|
-
for (let [n, r] of Object.entries(e)) t[n] =
|
|
30
|
+
for (let [n, r] of Object.entries(e)) t[n] = a.has(n) && Array.isArray(r) ? r.length ? r.join(",") : void 0 : r;
|
|
24
31
|
return t;
|
|
25
32
|
}
|
|
26
|
-
var
|
|
33
|
+
var s = class {
|
|
27
34
|
http;
|
|
28
35
|
browserSearches;
|
|
29
36
|
constructor(e) {
|
|
@@ -31,13 +38,13 @@ var o = class {
|
|
|
31
38
|
}
|
|
32
39
|
list(t = {}, n) {
|
|
33
40
|
return e(this.http, "GET", "/contents", {
|
|
34
|
-
query:
|
|
41
|
+
query: o(t),
|
|
35
42
|
signal: n
|
|
36
43
|
});
|
|
37
44
|
}
|
|
38
45
|
async search(t, n) {
|
|
39
46
|
let r = t.cursor ? null : this.http.captureChanges(), i = await e(this.http, "GET", "/search", {
|
|
40
|
-
query:
|
|
47
|
+
query: o(t),
|
|
41
48
|
signal: n
|
|
42
49
|
});
|
|
43
50
|
return r?.({ type: "searches.changed" }), i;
|
|
@@ -54,32 +61,32 @@ var o = class {
|
|
|
54
61
|
}
|
|
55
62
|
typeahead(t, n) {
|
|
56
63
|
return e(this.http, "GET", "/typeahead", {
|
|
57
|
-
query:
|
|
64
|
+
query: o(t),
|
|
58
65
|
signal: n
|
|
59
66
|
});
|
|
60
67
|
}
|
|
61
68
|
similar(t, n = {}, r) {
|
|
62
69
|
return e(this.http, "GET", "/contents/{id}/similar", {
|
|
63
70
|
params: { id: t },
|
|
64
|
-
query:
|
|
71
|
+
query: o(n),
|
|
65
72
|
signal: r
|
|
66
73
|
});
|
|
67
74
|
}
|
|
68
75
|
recommendations(t = {}, n) {
|
|
69
76
|
return e(this.http, "GET", "/recommendations", {
|
|
70
|
-
query:
|
|
77
|
+
query: o(t),
|
|
71
78
|
signal: n
|
|
72
79
|
});
|
|
73
80
|
}
|
|
74
81
|
releaseDates(t = {}, n) {
|
|
75
82
|
return e(this.http, "GET", "/release-dates", {
|
|
76
|
-
query:
|
|
83
|
+
query: o(t),
|
|
77
84
|
signal: n
|
|
78
85
|
});
|
|
79
86
|
}
|
|
80
87
|
releases(t = {}, n) {
|
|
81
88
|
return e(this.http, "GET", "/releases", {
|
|
82
|
-
query:
|
|
89
|
+
query: o(t),
|
|
83
90
|
signal: n
|
|
84
91
|
});
|
|
85
92
|
}
|
|
@@ -88,7 +95,7 @@ var o = class {
|
|
|
88
95
|
signal: n,
|
|
89
96
|
guestPreferences: !1
|
|
90
97
|
});
|
|
91
|
-
return this.http.acceptGuestFilters(r.
|
|
98
|
+
return this.http.acceptGuestFilters(r.kinds), r;
|
|
92
99
|
}
|
|
93
100
|
async setContentFilters(t, n) {
|
|
94
101
|
let r = this.http.captureChanges(), i = await e(this.http, "PUT", "/me/content-filters", {
|
|
@@ -99,7 +106,7 @@ var o = class {
|
|
|
99
106
|
}
|
|
100
107
|
history(t = {}, n) {
|
|
101
108
|
return e(this.http, "GET", "/me/history", {
|
|
102
|
-
query:
|
|
109
|
+
query: o(t),
|
|
103
110
|
signal: n
|
|
104
111
|
});
|
|
105
112
|
}
|
|
@@ -107,6 +114,14 @@ var o = class {
|
|
|
107
114
|
let n = this.http.captureChanges();
|
|
108
115
|
await e(this.http, "DELETE", "/me/history", { query: t }), n({ type: "history.changed" });
|
|
109
116
|
}
|
|
117
|
+
activityContexts(t, n, r = this.http.language()) {
|
|
118
|
+
let i = {
|
|
119
|
+
targets: [...t],
|
|
120
|
+
session: n,
|
|
121
|
+
language: r
|
|
122
|
+
};
|
|
123
|
+
return e(this.http, "POST", "/activity-contexts", { body: i });
|
|
124
|
+
}
|
|
110
125
|
signals(t, n, r = {}) {
|
|
111
126
|
let i = {
|
|
112
127
|
session: n,
|
|
@@ -129,6 +144,6 @@ var o = class {
|
|
|
129
144
|
}
|
|
130
145
|
};
|
|
131
146
|
//#endregion
|
|
132
|
-
export {
|
|
147
|
+
export { s as DiscoveryClient, i as popularBetween, r as popularQuery, o as query };
|
|
133
148
|
|
|
134
149
|
//# sourceMappingURL=discovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","names":[],"sources":["../../src/client/discovery.ts"],"sourcesContent":["import type {\n ContentFilters,\n ContentFiltersUpdate,\n ContentPage,\n DailyReleases,\n ExposureInput,\n Exposures,\n RecentSearches,\n ReleaseDates,\n SignalInput,\n Signals,\n Typeahead,\n} from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, routeURL } from \"./route.js\";\nimport { browserSearchHistory, type BrowserSearchHistory } from \"./browser-search-history.js\";\n\n/** A popularity period. */\nexport type Period = \"7d\" | \"30d\" | \"90d\" | \"365d\" | \"all\";\n/** A list's order; position orders by the first of `groups` (an ordered group). */\nexport type ListSort = \"newest\" | \"oldest\" | \"title\" | \"popular\" | `popular:${Period}` | \"top_rated\" | `top_rated:${Period}` | \"most_favorited\" | \"most_viewed\" | \"position\" | \"random\";\n/** How locked contents list: marked (lock, the default) or left out (hide). */\nexport type AccessMode = \"lock\" | \"hide\";\n\n/** Which contents a list holds. */\nexport interface ContentFilterQuery {\n kind?: string;\n /** Group ids every listed version is in. */\n groups?: readonly string[];\n /** Group ids no listed version is in. */\n exclude_groups?: readonly string[];\n /** Only contents this group owns: a channel's feed. */\n owner_group?: string;\n /** User ids: only contents one of them is credited on. */\n creators?: readonly string[];\n /** public (anyone opens it now) or the level it stays locked at. */\n access?: readonly (\"public\" | \"tier\" | \"group\" | \"ppv\" | \"group_ppv\")[];\n /** Only contents locked behind one of these tiers. */\n tiers?: readonly string[];\n /** Version traits every listed version has. */\n traits?: readonly string[];\n /** \"name:value\" of the kind's filterable attributes. */\n attribute?: readonly string[];\n /** Published on this day (YYYY-MM-DD) or month (YYYY-MM). */\n released_on?: string;\n /** Only contents published within this age window; independent of the popularity score window. */\n published_within?: Period;\n /** IANA time zone of released_on and release dates; UTC by default. */\n tz?: string;\n /** The signed-in reader's unseen, in-progress or completed contents. */\n view_status?: \"unseen\" | \"in_progress\" | \"completed\";\n}\n\n/** How a list reads to its reader. */\nexport interface ReaderQuery {\n /** Only content with a live version in this language. */\n language?: string;\n /** Titles, names and paths in this language, and each card's preferred version's; language by default. */\n display_language?: string;\n mode?: AccessMode;\n}\n\n/** The group kinds cards name; every kind with a page by default. */\nexport interface CardQuery {\n card_entities?: readonly string[];\n}\n\nexport interface PageQuery {\n cursor?: string;\n limit?: number;\n}\n\nexport type ContentQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & { sort?: ListSort };\nexport type PopularPeriod = \"7d\" | \"90d\" | \"365d\" | \"all\";\nexport type PopularQuery = Omit<ContentQuery, \"sort\" | \"published_within\">;\n\n/** Match the popularity score window and publication age window. */\nexport function popularQuery(period: PopularPeriod = \"7d\", filters: PopularQuery = {}): ContentQuery {\n return { ...filters, sort: `popular:${period}`, published_within: period };\n}\n\nexport type SearchQuery = ContentFilterQuery &\n ReaderQuery &\n CardQuery &\n PageQuery & {\n q: string;\n sort?: \"relevance\" | ListSort;\n personalize?: boolean;\n /** Explicit legacy server-side anonymous history. Omit for public search without server history. */\n session?: string;\n };\nexport interface RecentSearchesQuery {\n /** Explicit legacy server-side anonymous history; no anonymous session is created by default. */\n session?: string;\n /** 10 by default, at most 100. */\n limit?: number;\n}\nexport type RailQuery = ContentFilterQuery & ReaderQuery & CardQuery & { limit?: number };\nexport type ReleaseDatesQuery = ContentFilterQuery & ReaderQuery & PageQuery & { by?: \"month\" | \"day\" };\n/** Complete daily metadata for one calendar window, without pagination. */\nexport type DailyReleasesQuery = Omit<ContentFilterQuery, \"released_on\" | \"tz\"> & ReaderQuery & CardQuery & { days?: number; time_zone?: string };\nexport type HistoryQuery = ReaderQuery & CardQuery & PageQuery & { kind?: string; status?: \"seen\" | \"in_progress\" | \"completed\" };\nexport interface TypeaheadQuery extends ReaderQuery {\n q: string;\n /** Only contents of this kind. */\n kind?: string;\n /** The group kinds suggested; every kind with a page by default. */\n entity_kinds?: readonly string[];\n /** Per section: 8 by default, at most 20. */\n limit?: number;\n}\n\n// Comma-joined list parameters; `attribute` repeats instead.\nconst LISTS = new Set([\"groups\", \"exclude_groups\", \"creators\", \"access\", \"tiers\", \"traits\", \"card_entities\", \"entity_kinds\"]);\n\n/** A query with its list parameters comma-joined, as discovery routes read them. */\nexport function query(q: object): Record<string, string | number | boolean | readonly string[] | undefined> {\n const out: Record<string, string | number | boolean | readonly string[] | undefined> = {};\n for (const [k, v] of Object.entries(q)) out[k] = LISTS.has(k) && Array.isArray(v) ? (v.length ? v.join(\",\") : undefined) : v;\n return out;\n}\n\n/**\n * Discovery: lists, search, typeahead, similar and recommended contents,\n * release dates, the reader's content filters and history, signals and exposures.\n */\nexport class DiscoveryClient {\n /** Local anonymous history, isolated from authenticated server history. */\n readonly browserSearches: BrowserSearchHistory;\n\n constructor(private readonly http: Http) {\n this.browserSearches = browserSearchHistory(http.mount(\"discovery\"));\n }\n\n /** Contents as cards, one per content item with the version that fits the reader. */\n list(q: ContentQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents\", { query: query(q) as never, signal });\n }\n /** A first page is kept among the reader's recent searches. */\n async search(q: SearchQuery, signal?: AbortSignal): Promise<ContentPage> {\n const emit = q.cursor ? null : this.http.captureChanges();\n const out: ContentPage = await call(this.http, \"GET\", \"/search\", { query: query(q) as never, signal });\n emit?.({ type: \"searches.changed\" });\n return out;\n }\n /** The reader's recent searches, newest first, since they last cleared them. */\n recentSearches(q: RecentSearchesQuery = {}, signal?: AbortSignal): Promise<RecentSearches> {\n return call(this.http, \"GET\", \"/me/searches\", { query: q, signal });\n }\n /** Clears one recent search, or all of them. */\n async clearSearches(o: { query?: string; session?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/searches\", { query: o });\n emit({ type: \"searches.changed\" });\n }\n /** Contents and groups while the reader types. */\n typeahead(q: TypeaheadQuery, signal?: AbortSignal): Promise<Typeahead> {\n return call(this.http, \"GET\", \"/typeahead\", { query: query(q) as never, signal });\n }\n /** Contents like one, of its kind unless q.kind names another. */\n similar(id: string, q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents/{id}/similar\", { params: { id }, query: query(q) as never, signal });\n }\n /** For the signed-in reader. */\n recommendations(q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/recommendations\", { query: query(q) as never, signal });\n }\n /** Per month or day, newest first: how many contents the reader's listing shows released then, and how many are free. */\n releaseDates(q: ReleaseDatesQuery = {}, signal?: AbortSignal): Promise<ReleaseDates> {\n return call(this.http, \"GET\", \"/release-dates\", { query: query(q) as never, signal });\n }\n /** Every visible card in each day; opening or expanding a day needs no further request. */\n releases(q: DailyReleasesQuery = {}, signal?: AbortSignal): Promise<DailyReleases> {\n return call(this.http, \"GET\", \"/releases\", { query: query(q) as never, signal });\n }\n /** Only the current domain's reader-toggleable entities, named in the requested language. */\n async contentFilters(language?: string, signal?: AbortSignal): Promise<ContentFilters> {\n const result = await this.http.request<ContentFilters>(routeURL(this.http, \"GET\", \"/content-filters\", { query: { language } }), { signal, guestPreferences: false });\n this.http.acceptGuestFilters(result.filters);\n return result;\n }\n /** Replaces this domain's reader settings; other domains' choices remain intact. */\n async setContentFilters(update: ContentFiltersUpdate, language?: string): Promise<ContentFilters> {\n const emit = this.http.captureChanges();\n const out: ContentFilters = await call(this.http, \"PUT\", \"/me/content-filters\", { query: { language }, body: update });\n emit({ type: \"contentFilters.changed\" });\n return out;\n }\n /** What the reader engaged with, most recent first. */\n history(q: HistoryQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/me/history\", { query: query(q) as never, signal });\n }\n /** Erases the reader's history: of one content item, one kind or everything. */\n async forgetHistory(o: { kind?: string; content_id?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/history\", { query: o });\n emit({ type: \"history.changed\" });\n }\n /** Views and clicks; signed out, of the session named. */\n signals(signals: SignalInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Signals = { session, signals };\n return call(this.http, \"POST\", \"/signals\", { body, keepalive: o.keepalive });\n }\n /** Result lists served, rendered or shown, for click attribution. */\n exposures(exposures: ExposureInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Exposures = { session, exposures };\n return call(this.http, \"POST\", \"/exposures\", { body, keepalive: o.keepalive });\n }\n}\n"],"mappings":";;;AA6EA,SAAgB,EAAa,IAAwB,MAAM,IAAwB,CAAC,GAAiB;CACnG,OAAO;EAAE,GAAG;EAAS,MAAM,WAAW;EAAU,kBAAkB;CAAO;AAC3E;AAkCA,IAAM,oBAAQ,IAAI,IAAI;CAAC;CAAU;CAAkB;CAAY;CAAU;CAAS;CAAU;CAAiB;AAAc,CAAC;AAG5H,SAAgB,EAAM,GAAsF;CAC1G,IAAM,IAAiF,CAAC;CACxF,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,CAAC,GAAG,EAAI,KAAK,EAAM,IAAI,CAAC,KAAK,MAAM,QAAQ,CAAC,IAAK,EAAE,SAAS,EAAE,KAAK,GAAG,IAAI,KAAA,IAAa;CAC3H,OAAO;AACT;AAMA,IAAa,IAAb,MAA6B;CAIE;CAF7B;CAEA,YAAY,GAA6B;EACvC,AAD2B,KAAA,OAAA,GAC3B,KAAK,kBAAkB,EAAqB,EAAK,MAAM,WAAW,CAAC;CACrE;CAGA,KAAK,IAAkB,CAAC,GAAG,GAA4C;EACrE,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACjF;CAEA,MAAM,OAAO,GAAgB,GAA4C;EACvE,IAAM,IAAO,EAAE,SAAS,OAAO,KAAK,KAAK,eAAe,GAClD,IAAmB,MAAM,EAAK,KAAK,MAAM,OAAO,WAAW;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;EAErG,OADA,IAAO,EAAE,MAAM,mBAAmB,CAAC,GAC5B;CACT;CAEA,eAAe,IAAyB,CAAC,GAAG,GAA+C;EACzF,OAAO,EAAK,KAAK,MAAM,OAAO,gBAAgB;GAAE,OAAO;GAAG;EAAO,CAAC;CACpE;CAEA,MAAM,cAAc,IAA0C,CAAC,GAAkB;EAC/E,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,gBAAgB,EAAE,OAAO,EAAE,CAAC,GAC5D,EAAK,EAAE,MAAM,mBAAmB,CAAC;CACnC;CAEA,UAAU,GAAmB,GAA0C;EACrE,OAAO,EAAK,KAAK,MAAM,OAAO,cAAc;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CAClF;CAEA,QAAQ,GAAY,IAAe,CAAC,GAAG,GAA4C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,0BAA0B;GAAE,QAAQ,EAAE,MAAG;GAAG,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CAC9G;CAEA,gBAAgB,IAAe,CAAC,GAAG,GAA4C;EAC7E,OAAO,EAAK,KAAK,MAAM,OAAO,oBAAoB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACxF;CAEA,aAAa,IAAuB,CAAC,GAAG,GAA6C;EACnF,OAAO,EAAK,KAAK,MAAM,OAAO,kBAAkB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACtF;CAEA,SAAS,IAAwB,CAAC,GAAG,GAA8C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACjF;CAEA,MAAM,eAAe,GAAmB,GAA+C;EACrF,IAAM,IAAS,MAAM,KAAK,KAAK,QAAwB,EAAS,KAAK,MAAM,OAAO,oBAAoB,EAAE,OAAO,EAAE,YAAS,EAAE,CAAC,GAAG;GAAE;GAAQ,kBAAkB;EAAM,CAAC;EAEnK,OADA,KAAK,KAAK,mBAAmB,EAAO,OAAO,GACpC;CACT;CAEA,MAAM,kBAAkB,GAA8B,GAA4C;EAChG,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAsB,MAAM,EAAK,KAAK,MAAM,OAAO,uBAAuB;GAAE,OAAO,EAAE,YAAS;GAAG,MAAM;EAAO,CAAC;EAErH,OADA,EAAK,EAAE,MAAM,yBAAyB,CAAC,GAChC;CACT;CAEA,QAAQ,IAAkB,CAAC,GAAG,GAA4C;EACxE,OAAO,EAAK,KAAK,MAAM,OAAO,eAAe;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACnF;CAEA,MAAM,cAAc,IAA4C,CAAC,GAAkB;EACjF,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,eAAe,EAAE,OAAO,EAAE,CAAC,GAC3D,EAAK,EAAE,MAAM,kBAAkB,CAAC;CAClC;CAEA,QAAQ,GAAwB,GAAkB,IAA6B,CAAC,GAAkB;EAChG,IAAM,IAAgB;GAAE;GAAS;EAAQ;EACzC,OAAO,EAAK,KAAK,MAAM,QAAQ,YAAY;GAAE;GAAM,WAAW,EAAE;EAAU,CAAC;CAC7E;CAEA,UAAU,GAA4B,GAAkB,IAA6B,CAAC,GAAkB;EACtG,IAAM,IAAkB;GAAE;GAAS;EAAU;EAC7C,OAAO,EAAK,KAAK,MAAM,QAAQ,cAAc;GAAE;GAAM,WAAW,EAAE;EAAU,CAAC;CAC/E;AACF"}
|
|
1
|
+
{"version":3,"file":"discovery.js","names":[],"sources":["../../src/client/discovery.ts"],"sourcesContent":["import type {\n ActivityContexts,\n ActivityContextsInput,\n ActivityTarget,\n ContentFilters,\n ContentFiltersUpdate,\n ContentPage,\n DailyReleases,\n ExposureInput,\n Exposures,\n RecentSearches,\n ReleaseDates,\n SignalInput,\n Signals,\n Typeahead,\n} from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, routeURL } from \"./route.js\";\nimport { browserSearchHistory, type BrowserSearchHistory } from \"./browser-search-history.js\";\n\n/** A popularity period. */\nexport type Period = \"7d\" | \"30d\" | \"90d\" | \"365d\" | \"all\";\n/** A list's order; position orders by the first of `groups` (an ordered group). */\nexport type ListSort = \"newest\" | \"oldest\" | \"title\" | \"popular\" | `popular:${Period}` | \"top_rated\" | `top_rated:${Period}` | \"most_favorited\" | \"most_viewed\" | \"position\" | \"random\";\n/** How locked contents list: marked (lock, the default) or left out (hide). */\nexport type AccessMode = \"lock\" | \"hide\";\n\n/** Which contents a list holds. */\nexport interface ContentFilterQuery {\n kind?: string;\n /** Group ids every listed version is in. */\n groups?: readonly string[];\n /** Group ids no listed version is in. */\n exclude_groups?: readonly string[];\n /** Only contents this group owns: a channel's feed. */\n owner_group?: string;\n /** User ids: only contents one of them is credited on. */\n creators?: readonly string[];\n /** public (anyone opens it now) or the level it stays locked at. */\n access?: readonly (\"public\" | \"tier\" | \"group\" | \"ppv\" | \"group_ppv\")[];\n /** Only contents locked behind one of these tiers. */\n tiers?: readonly string[];\n /** Version traits every listed version has. */\n traits?: readonly string[];\n /** \"name:value\" of the kind's filterable attributes. */\n attribute?: readonly string[];\n /** Published on this day (YYYY-MM-DD) or month (YYYY-MM). */\n released_on?: string;\n /** Only contents published within this age window; independent of the popularity score window. */\n published_within?: Period;\n /** IANA time zone of released_on and release dates; UTC by default. */\n tz?: string;\n /** The signed-in reader's unseen, in-progress or completed contents. */\n view_status?: \"unseen\" | \"in_progress\" | \"completed\";\n}\n\n/** How a list reads to its reader. */\nexport interface ReaderQuery {\n /** Only content with a live version in this language. */\n language?: string;\n /** Titles, names and paths in this language, and each card's preferred version's; language by default. */\n display_language?: string;\n mode?: AccessMode;\n}\n\n/** The group kinds cards name; every kind with a page by default. */\nexport interface CardQuery {\n card_entities?: readonly string[];\n}\n\nexport interface PageQuery {\n cursor?: string;\n limit?: number;\n}\n\nexport type ContentQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & {\n sort?: ListSort;\n /** Inclusive UTC date (YYYY-MM-DD); requires activity_until, kind and sort=popular. */\n activity_from?: string;\n /** Exclusive UTC date (YYYY-MM-DD); requires activity_from, kind and sort=popular. */\n activity_until?: string;\n};\nexport type PopularPeriod = \"7d\" | \"90d\" | \"365d\" | \"all\";\nexport type PopularQuery = Omit<ContentQuery, \"sort\" | \"activity_from\" | \"activity_until\">;\n\n/** Rank activity in the selected window; publication age is an optional separate filter. */\nexport function popularQuery(period: PopularPeriod = \"7d\", filters: PopularQuery = {}): ContentQuery {\n return { ...filters, sort: `popular:${period}` };\n}\n\n/** Rank activity between two UTC dates: from inclusive, until exclusive. */\nexport function popularBetween(from: string, until: string, filters: PopularQuery & { kind: string }): ContentQuery {\n return { ...filters, sort: \"popular\", activity_from: from, activity_until: until };\n}\n\nexport type SearchQuery = ContentFilterQuery &\n ReaderQuery &\n CardQuery &\n PageQuery & {\n q: string;\n sort?: \"relevance\" | ListSort;\n personalize?: boolean;\n /** Explicit legacy server-side anonymous history. Omit for public search without server history. */\n session?: string;\n };\nexport interface RecentSearchesQuery {\n /** Explicit legacy server-side anonymous history; no anonymous session is created by default. */\n session?: string;\n /** 10 by default, at most 100. */\n limit?: number;\n}\nexport type RailQuery = ContentFilterQuery & ReaderQuery & CardQuery & { limit?: number };\nexport type ReleaseDatesQuery = ContentFilterQuery & ReaderQuery & PageQuery & { by?: \"month\" | \"day\" };\n/** Complete daily metadata for one calendar window, without pagination. */\nexport type DailyReleasesQuery = Omit<ContentFilterQuery, \"released_on\" | \"tz\"> & ReaderQuery & CardQuery & { days?: number; time_zone?: string };\nexport type HistoryQuery = ReaderQuery & CardQuery & PageQuery & { kind?: string; status?: \"seen\" | \"in_progress\" | \"completed\" };\nexport interface TypeaheadQuery extends ReaderQuery {\n q: string;\n /** Only contents of this kind. */\n kind?: string;\n /** The group kinds suggested; every kind with a page by default. */\n entity_kinds?: readonly string[];\n /** Per section: 8 by default, at most 20. */\n limit?: number;\n}\n\n// Comma-joined list parameters; `attribute` repeats instead.\nconst LISTS = new Set([\"groups\", \"exclude_groups\", \"creators\", \"access\", \"tiers\", \"traits\", \"card_entities\", \"entity_kinds\"]);\n\n/** A query with its list parameters comma-joined, as discovery routes read them. */\nexport function query(q: object): Record<string, string | number | boolean | readonly string[] | undefined> {\n const out: Record<string, string | number | boolean | readonly string[] | undefined> = {};\n for (const [k, v] of Object.entries(q)) out[k] = LISTS.has(k) && Array.isArray(v) ? (v.length ? v.join(\",\") : undefined) : v;\n return out;\n}\n\n/**\n * Discovery: lists, search, typeahead, similar and recommended contents,\n * release dates, the reader's content filters and history, signals and exposures.\n */\nexport class DiscoveryClient {\n /** Local anonymous history, isolated from authenticated server history. */\n readonly browserSearches: BrowserSearchHistory;\n\n constructor(private readonly http: Http) {\n this.browserSearches = browserSearchHistory(http.mount(\"discovery\"));\n }\n\n /** Contents as cards, one per content item with the version that fits the reader. */\n list(q: ContentQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents\", { query: query(q) as never, signal });\n }\n /** A first page is kept among the reader's recent searches. */\n async search(q: SearchQuery, signal?: AbortSignal): Promise<ContentPage> {\n const emit = q.cursor ? null : this.http.captureChanges();\n const out: ContentPage = await call(this.http, \"GET\", \"/search\", { query: query(q) as never, signal });\n emit?.({ type: \"searches.changed\" });\n return out;\n }\n /** The reader's recent searches, newest first, since they last cleared them. */\n recentSearches(q: RecentSearchesQuery = {}, signal?: AbortSignal): Promise<RecentSearches> {\n return call(this.http, \"GET\", \"/me/searches\", { query: q, signal });\n }\n /** Clears one recent search, or all of them. */\n async clearSearches(o: { query?: string; session?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/searches\", { query: o });\n emit({ type: \"searches.changed\" });\n }\n /** Contents and groups while the reader types. */\n typeahead(q: TypeaheadQuery, signal?: AbortSignal): Promise<Typeahead> {\n return call(this.http, \"GET\", \"/typeahead\", { query: query(q) as never, signal });\n }\n /** Contents like one, of its kind unless q.kind names another. */\n similar(id: string, q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents/{id}/similar\", { params: { id }, query: query(q) as never, signal });\n }\n /** For the signed-in reader. */\n recommendations(q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/recommendations\", { query: query(q) as never, signal });\n }\n /** Per month or day, newest first: how many contents the reader's listing shows released then, and how many are free. */\n releaseDates(q: ReleaseDatesQuery = {}, signal?: AbortSignal): Promise<ReleaseDates> {\n return call(this.http, \"GET\", \"/release-dates\", { query: query(q) as never, signal });\n }\n /** Every visible card in each day; opening or expanding a day needs no further request. */\n releases(q: DailyReleasesQuery = {}, signal?: AbortSignal): Promise<DailyReleases> {\n return call(this.http, \"GET\", \"/releases\", { query: query(q) as never, signal });\n }\n /** Only the current domain's reader-toggleable entities, named in the requested language. */\n async contentFilters(language?: string, signal?: AbortSignal): Promise<ContentFilters> {\n const result = await this.http.request<ContentFilters>(routeURL(this.http, \"GET\", \"/content-filters\", { query: { language } }), { signal, guestPreferences: false });\n this.http.acceptGuestFilters(result.kinds);\n return result;\n }\n /** Replaces this domain's reader settings; other domains' choices remain intact. */\n async setContentFilters(update: ContentFiltersUpdate, language?: string): Promise<ContentFilters> {\n const emit = this.http.captureChanges();\n const out: ContentFilters = await call(this.http, \"PUT\", \"/me/content-filters\", { query: { language }, body: update });\n emit({ type: \"contentFilters.changed\" });\n return out;\n }\n /** What the reader engaged with, most recent first. */\n history(q: HistoryQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/me/history\", { query: query(q) as never, signal });\n }\n /** Erases the reader's history: of one content item, one kind or everything. */\n async forgetHistory(o: { kind?: string; content_id?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/history\", { query: o });\n emit({ type: \"history.changed\" });\n }\n /** Capture server-owned access and eligibility at an observation's start. */\n activityContexts(targets: readonly ActivityTarget[], session?: string, language = this.http.language()): Promise<ActivityContexts> {\n const body: ActivityContextsInput = { targets: [...targets], session, language };\n return call(this.http, \"POST\", \"/activity-contexts\", { body });\n }\n /** Views and clicks; signed out, of the session named. */\n signals(signals: SignalInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Signals = { session, signals };\n return call(this.http, \"POST\", \"/signals\", { body, keepalive: o.keepalive });\n }\n /** Result lists served, rendered or shown, for click attribution. */\n exposures(exposures: ExposureInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Exposures = { session, exposures };\n return call(this.http, \"POST\", \"/exposures\", { body, keepalive: o.keepalive });\n }\n}\n"],"mappings":";;;AAsFA,SAAgB,EAAa,IAAwB,MAAM,IAAwB,CAAC,GAAiB;CACnG,OAAO;EAAE,GAAG;EAAS,MAAM,WAAW;CAAS;AACjD;AAGA,SAAgB,EAAe,GAAc,GAAe,GAAwD;CAClH,OAAO;EAAE,GAAG;EAAS,MAAM;EAAW,eAAe;EAAM,gBAAgB;CAAM;AACnF;AAkCA,IAAM,oBAAQ,IAAI,IAAI;CAAC;CAAU;CAAkB;CAAY;CAAU;CAAS;CAAU;CAAiB;AAAc,CAAC;AAG5H,SAAgB,EAAM,GAAsF;CAC1G,IAAM,IAAiF,CAAC;CACxF,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,CAAC,GAAG,EAAI,KAAK,EAAM,IAAI,CAAC,KAAK,MAAM,QAAQ,CAAC,IAAK,EAAE,SAAS,EAAE,KAAK,GAAG,IAAI,KAAA,IAAa;CAC3H,OAAO;AACT;AAMA,IAAa,IAAb,MAA6B;CAIE;CAF7B;CAEA,YAAY,GAA6B;EACvC,AAD2B,KAAA,OAAA,GAC3B,KAAK,kBAAkB,EAAqB,EAAK,MAAM,WAAW,CAAC;CACrE;CAGA,KAAK,IAAkB,CAAC,GAAG,GAA4C;EACrE,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACjF;CAEA,MAAM,OAAO,GAAgB,GAA4C;EACvE,IAAM,IAAO,EAAE,SAAS,OAAO,KAAK,KAAK,eAAe,GAClD,IAAmB,MAAM,EAAK,KAAK,MAAM,OAAO,WAAW;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;EAErG,OADA,IAAO,EAAE,MAAM,mBAAmB,CAAC,GAC5B;CACT;CAEA,eAAe,IAAyB,CAAC,GAAG,GAA+C;EACzF,OAAO,EAAK,KAAK,MAAM,OAAO,gBAAgB;GAAE,OAAO;GAAG;EAAO,CAAC;CACpE;CAEA,MAAM,cAAc,IAA0C,CAAC,GAAkB;EAC/E,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,gBAAgB,EAAE,OAAO,EAAE,CAAC,GAC5D,EAAK,EAAE,MAAM,mBAAmB,CAAC;CACnC;CAEA,UAAU,GAAmB,GAA0C;EACrE,OAAO,EAAK,KAAK,MAAM,OAAO,cAAc;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CAClF;CAEA,QAAQ,GAAY,IAAe,CAAC,GAAG,GAA4C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,0BAA0B;GAAE,QAAQ,EAAE,MAAG;GAAG,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CAC9G;CAEA,gBAAgB,IAAe,CAAC,GAAG,GAA4C;EAC7E,OAAO,EAAK,KAAK,MAAM,OAAO,oBAAoB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACxF;CAEA,aAAa,IAAuB,CAAC,GAAG,GAA6C;EACnF,OAAO,EAAK,KAAK,MAAM,OAAO,kBAAkB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACtF;CAEA,SAAS,IAAwB,CAAC,GAAG,GAA8C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACjF;CAEA,MAAM,eAAe,GAAmB,GAA+C;EACrF,IAAM,IAAS,MAAM,KAAK,KAAK,QAAwB,EAAS,KAAK,MAAM,OAAO,oBAAoB,EAAE,OAAO,EAAE,YAAS,EAAE,CAAC,GAAG;GAAE;GAAQ,kBAAkB;EAAM,CAAC;EAEnK,OADA,KAAK,KAAK,mBAAmB,EAAO,KAAK,GAClC;CACT;CAEA,MAAM,kBAAkB,GAA8B,GAA4C;EAChG,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAsB,MAAM,EAAK,KAAK,MAAM,OAAO,uBAAuB;GAAE,OAAO,EAAE,YAAS;GAAG,MAAM;EAAO,CAAC;EAErH,OADA,EAAK,EAAE,MAAM,yBAAyB,CAAC,GAChC;CACT;CAEA,QAAQ,IAAkB,CAAC,GAAG,GAA4C;EACxE,OAAO,EAAK,KAAK,MAAM,OAAO,eAAe;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACnF;CAEA,MAAM,cAAc,IAA4C,CAAC,GAAkB;EACjF,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,eAAe,EAAE,OAAO,EAAE,CAAC,GAC3D,EAAK,EAAE,MAAM,kBAAkB,CAAC;CAClC;CAEA,iBAAiB,GAAoC,GAAkB,IAAW,KAAK,KAAK,SAAS,GAA8B;EACjI,IAAM,IAA8B;GAAE,SAAS,CAAC,GAAG,CAAO;GAAG;GAAS;EAAS;EAC/E,OAAO,EAAK,KAAK,MAAM,QAAQ,sBAAsB,EAAE,QAAK,CAAC;CAC/D;CAEA,QAAQ,GAAwB,GAAkB,IAA6B,CAAC,GAAkB;EAChG,IAAM,IAAgB;GAAE;GAAS;EAAQ;EACzC,OAAO,EAAK,KAAK,MAAM,QAAQ,YAAY;GAAE;GAAM,WAAW,EAAE;EAAU,CAAC;CAC7E;CAEA,UAAU,GAA4B,GAAkB,IAA6B,CAAC,GAAkB;EACtG,IAAM,IAAkB;GAAE;GAAS;EAAU;EAC7C,OAAO,EAAK,KAAK,MAAM,QAAQ,cAAc;GAAE;GAAM,WAAW,EAAE;EAAU,CAAC;CAC/E;AACF"}
|
|
@@ -1852,6 +1852,19 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
1852
1852
|
};
|
|
1853
1853
|
readonly errors: readonly [];
|
|
1854
1854
|
readonly errorSets: readonly ["module:offers", "auth", "request"];
|
|
1855
|
+
}, {
|
|
1856
|
+
readonly method: "POST";
|
|
1857
|
+
readonly module: "discovery";
|
|
1858
|
+
readonly path: "/activity-contexts";
|
|
1859
|
+
readonly auth: "public";
|
|
1860
|
+
readonly permission: null;
|
|
1861
|
+
readonly query: readonly [];
|
|
1862
|
+
readonly request: "ActivityContextsInput";
|
|
1863
|
+
readonly responses: {
|
|
1864
|
+
readonly 200: "ActivityContexts";
|
|
1865
|
+
};
|
|
1866
|
+
readonly errors: readonly ["not_configured"];
|
|
1867
|
+
readonly errorSets: readonly ["module:discovery", "auth", "request"];
|
|
1855
1868
|
}, {
|
|
1856
1869
|
readonly method: "GET";
|
|
1857
1870
|
readonly module: "discovery";
|
|
@@ -1871,7 +1884,7 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
1871
1884
|
readonly path: "/contents";
|
|
1872
1885
|
readonly auth: "public";
|
|
1873
1886
|
readonly permission: null;
|
|
1874
|
-
readonly query: readonly ["kind", "groups", "exclude_groups", "owner_group", "creators", "access", "tiers", "traits", "attribute", "released_on", "published_within", "tz", "view_status", "language", "display_language", "mode", "sort", "card_entities", "cursor", "limit"];
|
|
1887
|
+
readonly query: readonly ["kind", "groups", "exclude_groups", "owner_group", "creators", "access", "tiers", "traits", "attribute", "released_on", "published_within", "tz", "view_status", "language", "display_language", "mode", "sort", "card_entities", "activity_from", "activity_until", "cursor", "limit"];
|
|
1875
1888
|
readonly request: null;
|
|
1876
1889
|
readonly responses: {
|
|
1877
1890
|
readonly 200: "ContentPage";
|
|
@@ -2573,6 +2573,22 @@ var e = {
|
|
|
2573
2573
|
"request"
|
|
2574
2574
|
]
|
|
2575
2575
|
},
|
|
2576
|
+
{
|
|
2577
|
+
method: "POST",
|
|
2578
|
+
module: "discovery",
|
|
2579
|
+
path: "/activity-contexts",
|
|
2580
|
+
auth: "public",
|
|
2581
|
+
permission: null,
|
|
2582
|
+
query: [],
|
|
2583
|
+
request: "ActivityContextsInput",
|
|
2584
|
+
responses: { 200: "ActivityContexts" },
|
|
2585
|
+
errors: ["not_configured"],
|
|
2586
|
+
errorSets: [
|
|
2587
|
+
"module:discovery",
|
|
2588
|
+
"auth",
|
|
2589
|
+
"request"
|
|
2590
|
+
]
|
|
2591
|
+
},
|
|
2576
2592
|
{
|
|
2577
2593
|
method: "GET",
|
|
2578
2594
|
module: "discovery",
|
|
@@ -2632,6 +2648,8 @@ var e = {
|
|
|
2632
2648
|
"mode",
|
|
2633
2649
|
"sort",
|
|
2634
2650
|
"card_entities",
|
|
2651
|
+
"activity_from",
|
|
2652
|
+
"activity_until",
|
|
2635
2653
|
"cursor",
|
|
2636
2654
|
"limit"
|
|
2637
2655
|
],
|