@tuwaio/docs-ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,88 @@
1
+ /** Slug of a TUWA policy: the path of its page on the TUWA sites and the name of its files in `TuwaIO/workflows/docs`. */
2
+ type PolicySlug = 'terms' | 'privacy' | 'cookie' | 'refund' | 'security' | 'dpa';
3
+ /** A TUWA policy, as listed in {@link policies}. */
4
+ interface Policy {
5
+ /** Slug of the policy. */
6
+ slug: PolicySlug;
7
+ /** Title shown in footers and on the page. */
8
+ title: string;
9
+ /** One sentence on what the policy covers, for policy lists. */
10
+ description: string;
11
+ /** Path of the policy page on the website and the Quasar dashboard. */
12
+ href: `/${PolicySlug}`;
13
+ /** Whether the policy is in force. Drafts stay `false` until they are approved. */
14
+ published: boolean;
15
+ /** Whether footers link the policy (default: `true`); documents linked from other policies set `false`. */
16
+ footer?: boolean;
17
+ }
18
+ /** A section of a policy: a level-2 heading with its anchor. */
19
+ interface PolicySection {
20
+ /** Anchor of the heading, without `#` (stable when sections are renumbered). */
21
+ id: string;
22
+ /** Text of the heading without its number. */
23
+ title: string;
24
+ }
25
+ /** Content of a policy page, generated next to its PDF by `generate_pdf.js` in `TuwaIO/workflows/docs`. */
26
+ interface PolicyContent {
27
+ /** Title of the document. */
28
+ title: string;
29
+ /** Date of the current version as written in the document (`October 8, 2026`). */
30
+ updated: string;
31
+ /** Level-2 sections in document order. */
32
+ sections: PolicySection[];
33
+ /** Body of the document as HTML, without the title and the date line; headings carry their anchors as `id`. */
34
+ html: string;
35
+ }
36
+ /** Where the policy files live: the `docs` folder of `TuwaIO/workflows` on GitHub, branch `main`. */
37
+ declare const POLICY_SOURCE = "https://raw.githubusercontent.com/TuwaIO/workflows/main/docs";
38
+ /** The site that hosts the policy pages; sites without their own policy pages (documentation sites) link there. */
39
+ declare const POLICY_SITE_URL = "https://tuwa.io";
40
+ /** The page that lists every TUWA policy in force: `/policies` of the docs hub. */
41
+ declare const POLICIES_INDEX_URL = "https://docs.tuwa.io/policies";
42
+ /**
43
+ * Every TUWA policy in the order footers list them. Footers of the website and the Quasar dashboard read
44
+ * {@link publishedPolicies}, so a policy appears everywhere once it is published.
45
+ */
46
+ declare const policies: readonly Policy[];
47
+ /** The policies in force, for policy lists: {@link policies} with `published: true`. */
48
+ declare const publishedPolicies: readonly Policy[];
49
+ /** The policies that footers link: {@link publishedPolicies} without those marked `footer: false`. */
50
+ declare const footerPolicies: readonly Policy[];
51
+ /**
52
+ * Returns the absolute URL of a policy page, for sites that do not host the policies themselves.
53
+ *
54
+ * @param slug - Slug of the policy.
55
+ * @param site - Origin of the site with the policy pages (default: {@link POLICY_SITE_URL}).
56
+ * @returns The URL of the page, for example `https://tuwa.io/terms`.
57
+ */
58
+ declare function getPolicyPageUrl(slug: PolicySlug, site?: string): string;
59
+ /**
60
+ * Returns the URL of a policy file.
61
+ *
62
+ * @param slug - Slug of the policy.
63
+ * @param format - `json` for the page content, `pdf` for the official document, `md` for the source text.
64
+ * @param source - Base URL of the policy files (default: {@link POLICY_SOURCE}).
65
+ * @returns The URL of the file.
66
+ */
67
+ declare function getPolicyFileUrl(slug: PolicySlug, format: 'json' | 'pdf' | 'md', source?: string): string;
68
+ /**
69
+ * Loads the content of a policy page (its `json` file). Call it on the server, for example in a Server Component of
70
+ * the Next.js App Router, and pass the result to `PolicyDocument`.
71
+ *
72
+ * Network: one request to `getPolicyFileUrl(slug, 'json', source)` per revalidation, cached by the Next.js `fetch`
73
+ * cache for `revalidate` seconds (outside Next.js, a plain request).
74
+ *
75
+ * @param slug - Slug of the policy.
76
+ * @param options - Optional settings.
77
+ * @param options.source - Base URL of the policy files (default: {@link POLICY_SOURCE}).
78
+ * @param options.revalidate - Seconds the Next.js `fetch` cache keeps the content, or `false` to cache it until the
79
+ * next deployment (default: 3600).
80
+ * @returns The content of the policy.
81
+ * @throws Error when the request fails, the response is not `2xx`, or the file is not a policy page.
82
+ */
83
+ declare function loadPolicy(slug: PolicySlug, options?: {
84
+ source?: string;
85
+ revalidate?: number | false;
86
+ }): Promise<PolicyContent>;
87
+
88
+ export { POLICIES_INDEX_URL, POLICY_SITE_URL, POLICY_SOURCE, type Policy, type PolicyContent, type PolicySection, type PolicySlug, footerPolicies, getPolicyFileUrl, getPolicyPageUrl, loadPolicy, policies, publishedPolicies };
@@ -0,0 +1,92 @@
1
+ const POLICY_SOURCE = "https://raw.githubusercontent.com/TuwaIO/workflows/main/docs";
2
+ const POLICY_SITE_URL = "https://tuwa.io";
3
+ const POLICIES_INDEX_URL = "https://docs.tuwa.io/policies";
4
+ const policies = [
5
+ {
6
+ slug: "terms",
7
+ title: "Terms of Service",
8
+ description: "The rules for using the TUWA websites and documentation, Quasar Cloud, Quasar Community Edition and the open-source packages.",
9
+ href: "/terms",
10
+ published: true
11
+ },
12
+ {
13
+ slug: "privacy",
14
+ title: "Privacy Policy",
15
+ description: "What data TUWA collects and why, how it is protected, and how to access or delete it.",
16
+ href: "/privacy",
17
+ published: true
18
+ },
19
+ {
20
+ slug: "cookie",
21
+ title: "Cookie Policy",
22
+ description: "The cookies and Local Storage that the TUWA sites and the Quasar dashboard use.",
23
+ href: "/cookie",
24
+ published: true
25
+ },
26
+ {
27
+ slug: "refund",
28
+ title: "Refund Policy",
29
+ description: "When and how payments for Quasar Cloud quota are refunded.",
30
+ href: "/refund",
31
+ // Quota purchases are paused; the policy is published again when they reopen
32
+ published: false
33
+ },
34
+ {
35
+ slug: "security",
36
+ title: "Security Policy",
37
+ description: "How to report a vulnerability, what TUWA promises in return, and who is responsible for what.",
38
+ href: "/security",
39
+ published: true
40
+ },
41
+ {
42
+ slug: "dpa",
43
+ title: "Data Processing Addendum",
44
+ description: "How we process the personal data of your app users on your behalf when you use Quasar Cloud.",
45
+ href: "/dpa",
46
+ published: true,
47
+ footer: false
48
+ }
49
+ ];
50
+ const publishedPolicies = policies.filter((policy) => policy.published);
51
+ const footerPolicies = publishedPolicies.filter((policy) => policy.footer !== false);
52
+ function getPolicyPageUrl(slug, site = POLICY_SITE_URL) {
53
+ return `${site.replace(/\/+$/, "")}/${slug}`;
54
+ }
55
+ function getPolicyFileUrl(slug, format, source = POLICY_SOURCE) {
56
+ return `${source.replace(/\/+$/, "")}/${slug}.${format}`;
57
+ }
58
+ function isPolicyContent(value) {
59
+ if (!value || typeof value !== "object") return false;
60
+ const content = value;
61
+ return typeof content.title === "string" && typeof content.updated === "string" && typeof content.html === "string" && Array.isArray(content.sections) && content.sections.every(
62
+ (section) => !!section && typeof section.id === "string" && typeof section.title === "string"
63
+ );
64
+ }
65
+ async function loadPolicy(slug, options = {}) {
66
+ const url = getPolicyFileUrl(slug, "json", options.source);
67
+ const response = await fetch(url, { next: { revalidate: options.revalidate ?? 3600 } });
68
+ if (!response.ok) {
69
+ throw new Error(`loadPolicy: ${url} answered ${response.status}`);
70
+ }
71
+ const content = await response.json();
72
+ if (!isPolicyContent(content)) {
73
+ throw new Error(`loadPolicy: ${url} is not a policy page`);
74
+ }
75
+ return {
76
+ title: content.title,
77
+ updated: content.updated,
78
+ sections: content.sections.map(({ id, title }) => ({ id, title })),
79
+ html: content.html
80
+ };
81
+ }
82
+ export {
83
+ POLICIES_INDEX_URL,
84
+ POLICY_SITE_URL,
85
+ POLICY_SOURCE,
86
+ footerPolicies,
87
+ getPolicyFileUrl,
88
+ getPolicyPageUrl,
89
+ loadPolicy,
90
+ policies,
91
+ publishedPolicies
92
+ };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tuwaio/docs-ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
7
- "description": "Shared UI of the TUWA documentation sites: Nextra navbar and footer, remote logo, theme switcher, background effects and styles.",
7
+ "description": "Shared UI of the TUWA documentation sites: Nextra navbar and footer, remote logo, theme switcher, background effects, policy pages and styles.",
8
8
  "main": "./dist/index.cjs",
9
9
  "module": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",