@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.
package/dist/index.cjs CHANGED
@@ -38,8 +38,10 @@ __reExport(index_exports, require("./components/Logo"), module.exports);
38
38
  __reExport(index_exports, require("./components/NavBar"), module.exports);
39
39
  var import_NoSSR = __toESM(require("./components/NoSSR"), 1);
40
40
  __reExport(index_exports, require("./components/Orb"), module.exports);
41
+ __reExport(index_exports, require("./components/PolicyDocument"), module.exports);
41
42
  var import_StarryBackground = __toESM(require("./components/StarryBackground"), 1);
42
43
  __reExport(index_exports, require("./components/ThemeSwitcher"), module.exports);
44
+ __reExport(index_exports, require("./policies"), module.exports);
43
45
  __reExport(index_exports, require("./utils"), module.exports);
44
46
  // Annotate the CommonJS export names for ESM import in node:
45
47
  0 && (module.exports = {
@@ -49,6 +51,8 @@ __reExport(index_exports, require("./utils"), module.exports);
49
51
  ...require("./components/Logo"),
50
52
  ...require("./components/NavBar"),
51
53
  ...require("./components/Orb"),
54
+ ...require("./components/PolicyDocument"),
52
55
  ...require("./components/ThemeSwitcher"),
56
+ ...require("./policies"),
53
57
  ...require("./utils")
54
58
  });
package/dist/index.css CHANGED
@@ -568,6 +568,7 @@ html {
568
568
  --tuwadocs-font-weight-bold: 700;
569
569
  --tuwadocs-font-weight-extrabold: 800;
570
570
  --tuwadocs-tracking-tight: -0.025em;
571
+ --tuwadocs-tracking-widest: 0.1em;
571
572
  --tuwadocs-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
572
573
  --tuwadocs-animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
573
574
  --tuwadocs-blur-sm: 8px;
@@ -609,15 +610,27 @@ html {
609
610
  .tuwadocs\:mt-4 {
610
611
  margin-top: calc(var(--tuwadocs-spacing) * 4);
611
612
  }
613
+ .tuwadocs\:mb-3 {
614
+ margin-bottom: calc(var(--tuwadocs-spacing) * 3);
615
+ }
612
616
  .tuwadocs\:mb-6 {
613
617
  margin-bottom: calc(var(--tuwadocs-spacing) * 6);
614
618
  }
619
+ .tuwadocs\:mb-8 {
620
+ margin-bottom: calc(var(--tuwadocs-spacing) * 8);
621
+ }
615
622
  .tuwadocs\:flex {
616
623
  display: flex;
617
624
  }
625
+ .tuwadocs\:grid {
626
+ display: grid;
627
+ }
618
628
  .tuwadocs\:hidden {
619
629
  display: none;
620
630
  }
631
+ .tuwadocs\:inline-flex {
632
+ display: inline-flex;
633
+ }
621
634
  .tuwadocs\:h-4 {
622
635
  height: calc(var(--tuwadocs-spacing) * 4);
623
636
  }
@@ -654,12 +667,21 @@ html {
654
667
  .tuwadocs\:w-full {
655
668
  width: 100%;
656
669
  }
670
+ .tuwadocs\:min-w-0 {
671
+ min-width: 0px;
672
+ }
657
673
  .tuwadocs\:flex-1 {
658
674
  flex: 1;
659
675
  }
660
676
  .tuwadocs\:cursor-pointer {
661
677
  cursor: pointer;
662
678
  }
679
+ .tuwadocs\:list-none {
680
+ list-style-type: none;
681
+ }
682
+ .tuwadocs\:grid-cols-1 {
683
+ grid-template-columns: repeat(1, minmax(0, 1fr));
684
+ }
663
685
  .tuwadocs\:flex-col {
664
686
  flex-direction: column;
665
687
  }
@@ -669,9 +691,6 @@ html {
669
691
  .tuwadocs\:items-center {
670
692
  align-items: center;
671
693
  }
672
- .tuwadocs\:items-start {
673
- align-items: flex-start;
674
- }
675
694
  .tuwadocs\:justify-between {
676
695
  justify-content: space-between;
677
696
  }
@@ -681,12 +700,25 @@ html {
681
700
  .tuwadocs\:gap-1 {
682
701
  gap: var(--tuwadocs-spacing);
683
702
  }
703
+ .tuwadocs\:gap-2 {
704
+ gap: calc(var(--tuwadocs-spacing) * 2);
705
+ }
684
706
  .tuwadocs\:gap-3 {
685
707
  gap: calc(var(--tuwadocs-spacing) * 3);
686
708
  }
687
709
  .tuwadocs\:gap-4 {
688
710
  gap: calc(var(--tuwadocs-spacing) * 4);
689
711
  }
712
+ .tuwadocs\:gap-10 {
713
+ gap: calc(var(--tuwadocs-spacing) * 10);
714
+ }
715
+ .tuwadocs\:gap-x-4 {
716
+ -moz-column-gap: calc(var(--tuwadocs-spacing) * 4);
717
+ column-gap: calc(var(--tuwadocs-spacing) * 4);
718
+ }
719
+ .tuwadocs\:gap-y-2 {
720
+ row-gap: calc(var(--tuwadocs-spacing) * 2);
721
+ }
690
722
  .tuwadocs\:overflow-hidden {
691
723
  overflow: hidden;
692
724
  }
@@ -700,6 +732,17 @@ html {
700
732
  border-style: var(--tw-border-style);
701
733
  border-width: 1px;
702
734
  }
735
+ .tuwadocs\:border-b {
736
+ border-bottom-style: var(--tw-border-style);
737
+ border-bottom-width: 1px;
738
+ }
739
+ .tuwadocs\:border-l {
740
+ border-left-style: var(--tw-border-style);
741
+ border-left-width: 1px;
742
+ }
743
+ .tuwadocs\:border-\[var\(--tuwa-border-primary\)\] {
744
+ border-color: var(--tuwa-border-primary);
745
+ }
703
746
  .tuwadocs\:border-black\/5 {
704
747
  border-color: var(--tuwadocs-color-black);
705
748
  @supports (color: color-mix(in lab, red, red)) {
@@ -729,6 +772,9 @@ html {
729
772
  .tuwadocs\:px-3 {
730
773
  padding-inline: calc(var(--tuwadocs-spacing) * 3);
731
774
  }
775
+ .tuwadocs\:px-4 {
776
+ padding-inline: calc(var(--tuwadocs-spacing) * 4);
777
+ }
732
778
  .tuwadocs\:py-1\.5 {
733
779
  padding-block: calc(var(--tuwadocs-spacing) * 1.5);
734
780
  }
@@ -738,17 +784,60 @@ html {
738
784
  .tuwadocs\:pt-8 {
739
785
  padding-top: calc(var(--tuwadocs-spacing) * 8);
740
786
  }
787
+ .tuwadocs\:pb-6 {
788
+ padding-bottom: calc(var(--tuwadocs-spacing) * 6);
789
+ }
790
+ .tuwadocs\:pl-4 {
791
+ padding-left: calc(var(--tuwadocs-spacing) * 4);
792
+ }
793
+ .tuwadocs\:text-center {
794
+ text-align: center;
795
+ }
796
+ .tuwadocs\:text-3xl {
797
+ font-size: var(--tuwadocs-text-3xl);
798
+ line-height: var(--tw-leading, var(--tuwadocs-text-3xl--line-height));
799
+ }
741
800
  .tuwadocs\:text-sm {
742
801
  font-size: var(--tuwadocs-text-sm);
743
802
  line-height: var(--tw-leading, var(--tuwadocs-text-sm--line-height));
744
803
  }
804
+ .tuwadocs\:text-xs {
805
+ font-size: var(--tuwadocs-text-xs);
806
+ line-height: var(--tw-leading, var(--tuwadocs-text-xs--line-height));
807
+ }
808
+ .tuwadocs\:font-bold {
809
+ --tw-font-weight: var(--tuwadocs-font-weight-bold);
810
+ font-weight: var(--tuwadocs-font-weight-bold);
811
+ }
812
+ .tuwadocs\:font-extrabold {
813
+ --tw-font-weight: var(--tuwadocs-font-weight-extrabold);
814
+ font-weight: var(--tuwadocs-font-weight-extrabold);
815
+ }
745
816
  .tuwadocs\:font-medium {
746
817
  --tw-font-weight: var(--tuwadocs-font-weight-medium);
747
818
  font-weight: var(--tuwadocs-font-weight-medium);
748
819
  }
820
+ .tuwadocs\:font-semibold {
821
+ --tw-font-weight: var(--tuwadocs-font-weight-semibold);
822
+ font-weight: var(--tuwadocs-font-weight-semibold);
823
+ }
824
+ .tuwadocs\:tracking-tight {
825
+ --tw-tracking: var(--tuwadocs-tracking-tight);
826
+ letter-spacing: var(--tuwadocs-tracking-tight);
827
+ }
828
+ .tuwadocs\:tracking-widest {
829
+ --tw-tracking: var(--tuwadocs-tracking-widest);
830
+ letter-spacing: var(--tuwadocs-tracking-widest);
831
+ }
749
832
  .tuwadocs\:text-\[var\(--tuwa-text-primary\)\] {
750
833
  color: var(--tuwa-text-primary);
751
834
  }
835
+ .tuwadocs\:text-\[var\(--tuwa-text-secondary\)\] {
836
+ color: var(--tuwa-text-secondary);
837
+ }
838
+ .tuwadocs\:text-\[var\(--tuwa-text-tertiary\)\] {
839
+ color: var(--tuwa-text-tertiary);
840
+ }
752
841
  .tuwadocs\:text-indigo-400 {
753
842
  color: var(--tuwadocs-color-indigo-400);
754
843
  }
@@ -758,6 +847,12 @@ html {
758
847
  .tuwadocs\:text-yellow-500 {
759
848
  color: var(--tuwadocs-color-yellow-500);
760
849
  }
850
+ .tuwadocs\:uppercase {
851
+ text-transform: uppercase;
852
+ }
853
+ .tuwadocs\:no-underline {
854
+ text-decoration-line: none;
855
+ }
761
856
  .tuwadocs\:opacity-0 {
762
857
  opacity: 0%;
763
858
  }
@@ -794,6 +889,9 @@ html {
794
889
  .tuwadocs\:group-hover\:text-yellow-400:is(:where(.tuwadocs\:group):hover *) {
795
890
  color: var(--tuwadocs-color-yellow-400);
796
891
  }
892
+ .tuwadocs\:hover\:bg-\[var\(--tuwa-bg-muted\)\]:hover {
893
+ background-color: var(--tuwa-bg-muted);
894
+ }
797
895
  .tuwadocs\:hover\:bg-black\/10:hover {
798
896
  background-color: var(--tuwadocs-color-black);
799
897
  }
@@ -802,6 +900,9 @@ html {
802
900
  background-color: color-mix(in oklab, var(--tuwadocs-color-black) 10%, transparent);
803
901
  }
804
902
  }
903
+ .tuwadocs\:hover\:text-\[var\(--tuwa-text-primary\)\]:hover {
904
+ color: var(--tuwa-text-primary);
905
+ }
805
906
  .tuwadocs\:hover\:text-red-600:hover {
806
907
  color: var(--tuwadocs-color-red-600);
807
908
  }
@@ -816,12 +917,19 @@ html {
816
917
  .tuwadocs\:sm\:flex-row {
817
918
  flex-direction: row;
818
919
  }
819
- .tuwadocs\:sm\:items-center {
820
- align-items: center;
821
- }
822
920
  .tuwadocs\:sm\:items-start {
823
921
  align-items: flex-start;
824
922
  }
923
+ .tuwadocs\:sm\:justify-end {
924
+ justify-content: flex-end;
925
+ }
926
+ .tuwadocs\:sm\:text-left {
927
+ text-align: left;
928
+ }
929
+ .tuwadocs\:sm\:text-4xl {
930
+ font-size: var(--tuwadocs-text-4xl);
931
+ line-height: var(--tw-leading, var(--tuwadocs-text-4xl--line-height));
932
+ }
825
933
  }
826
934
  @media (width >= 48rem) {
827
935
  .tuwadocs\:md\:block {
@@ -849,6 +957,23 @@ html {
849
957
  width: calc(var(--tuwadocs-spacing) * 16);
850
958
  }
851
959
  }
960
+ @media (width >= 64rem) {
961
+ .tuwadocs\:lg\:sticky {
962
+ position: sticky;
963
+ }
964
+ .tuwadocs\:lg\:top-24 {
965
+ top: calc(var(--tuwadocs-spacing) * 24);
966
+ }
967
+ .tuwadocs\:lg\:block {
968
+ display: block;
969
+ }
970
+ .tuwadocs\:lg\:grid-cols-\[minmax\(0\,1fr\)_14rem\] {
971
+ grid-template-columns: minmax(0,1fr) 14rem;
972
+ }
973
+ .tuwadocs\:lg\:self-start {
974
+ align-self: flex-start;
975
+ }
976
+ }
852
977
  @media (width >= 96rem) {
853
978
  .tuwadocs\:2xl\:h-6 {
854
979
  height: calc(var(--tuwadocs-spacing) * 6);
@@ -1168,6 +1293,93 @@ article .nextra-border a:hover {
1168
1293
  .nextra-toc .nextra-border a:hover {
1169
1294
  color: var(--tuwa-secondary) !important;
1170
1295
  }
1296
+ .tuwadocs-policy-title {
1297
+ font-family: var(--font-geist-mono, ui-monospace), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1298
+ }
1299
+ .tuwadocs-policy {
1300
+ color: var(--tuwa-text-secondary);
1301
+ font-size: 1rem;
1302
+ line-height: 1.75;
1303
+ }
1304
+ .tuwadocs-policy > * + * {
1305
+ margin-top: 1rem;
1306
+ }
1307
+ .tuwadocs-policy h2,
1308
+ .tuwadocs-policy h3 {
1309
+ color: var(--tuwa-text-primary);
1310
+ font-family: var(--font-geist-mono, ui-monospace), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1311
+ font-weight: 700;
1312
+ letter-spacing: -0.01em;
1313
+ scroll-margin-top: 6rem;
1314
+ }
1315
+ .tuwadocs-policy h2 {
1316
+ margin-top: 2.5rem;
1317
+ font-size: 1.25rem;
1318
+ line-height: 1.4;
1319
+ }
1320
+ .tuwadocs-policy h3 {
1321
+ margin-top: 1.75rem;
1322
+ font-size: 1.05rem;
1323
+ line-height: 1.5;
1324
+ }
1325
+ .tuwadocs-policy ul,
1326
+ .tuwadocs-policy ol {
1327
+ padding-left: 1.25rem;
1328
+ }
1329
+ .tuwadocs-policy ul {
1330
+ list-style: disc;
1331
+ }
1332
+ .tuwadocs-policy ol {
1333
+ list-style: decimal;
1334
+ }
1335
+ .tuwadocs-policy li + li {
1336
+ margin-top: 0.5rem;
1337
+ }
1338
+ .tuwadocs-policy strong {
1339
+ color: var(--tuwa-text-primary);
1340
+ font-weight: 600;
1341
+ }
1342
+ .tuwadocs-policy a {
1343
+ text-decoration: underline;
1344
+ text-underline-offset: 2px;
1345
+ overflow-wrap: anywhere;
1346
+ }
1347
+ .tuwadocs-policy table {
1348
+ display: block;
1349
+ max-width: 100%;
1350
+ overflow-x: auto;
1351
+ border-collapse: collapse;
1352
+ font-size: 0.875rem;
1353
+ line-height: 1.5;
1354
+ }
1355
+ .tuwadocs-policy th,
1356
+ .tuwadocs-policy td {
1357
+ border: 1px solid var(--tuwa-border-primary);
1358
+ padding: 0.5rem 0.75rem;
1359
+ text-align: left;
1360
+ vertical-align: top;
1361
+ }
1362
+ .tuwadocs-policy th {
1363
+ background: var(--tuwa-bg-muted);
1364
+ color: var(--tuwa-text-primary);
1365
+ font-weight: 600;
1366
+ }
1367
+ .tuwadocs-policy blockquote {
1368
+ border-left: 3px solid var(--tuwa-border-primary);
1369
+ border-radius: var(--tuwa-rounded-corners);
1370
+ background: var(--tuwa-bg-muted);
1371
+ padding: 0.75rem 1rem;
1372
+ }
1373
+ .tuwadocs-policy blockquote > * + * {
1374
+ margin-top: 0.5rem;
1375
+ }
1376
+ .tuwadocs-policy code {
1377
+ border-radius: var(--tuwa-rounded-corners);
1378
+ background: var(--tuwa-bg-muted);
1379
+ padding: 0.1em 0.35em;
1380
+ font-family: var(--font-geist-mono, ui-monospace), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1381
+ font-size: 0.875em;
1382
+ }
1171
1383
  .tuwa-button {
1172
1384
  display: inline-flex;
1173
1385
  align-items: center;
package/dist/index.d.cts CHANGED
@@ -3,7 +3,9 @@ export { RemoteLogo, RemoteLogoProps } from './components/Logo.cjs';
3
3
  export { NavProps, Navbar, SocialLink } from './components/NavBar.cjs';
4
4
  export { default as NoSSR } from './components/NoSSR.cjs';
5
5
  export { Orb, OrbProps, PackageType } from './components/Orb.cjs';
6
+ export { PolicyDocument, PolicyDocumentProps } from './components/PolicyDocument.cjs';
6
7
  export { default as StarryBackground } from './components/StarryBackground.cjs';
7
8
  export { ThemeSwitcher, ThemeSwitcherProps } from './components/ThemeSwitcher.cjs';
9
+ export { POLICIES_INDEX_URL, POLICY_SITE_URL, POLICY_SOURCE, Policy, PolicyContent, PolicySection, PolicySlug, footerPolicies, getPolicyFileUrl, getPolicyPageUrl, loadPolicy, policies, publishedPolicies } from './policies.cjs';
8
10
  export { baseFooterLinks, baseNavLinks } from './utils.cjs';
9
11
  import 'react';
package/dist/index.d.ts CHANGED
@@ -3,7 +3,9 @@ export { RemoteLogo, RemoteLogoProps } from './components/Logo.js';
3
3
  export { NavProps, Navbar, SocialLink } from './components/NavBar.js';
4
4
  export { default as NoSSR } from './components/NoSSR.js';
5
5
  export { Orb, OrbProps, PackageType } from './components/Orb.js';
6
+ export { PolicyDocument, PolicyDocumentProps } from './components/PolicyDocument.js';
6
7
  export { default as StarryBackground } from './components/StarryBackground.js';
7
8
  export { ThemeSwitcher, ThemeSwitcherProps } from './components/ThemeSwitcher.js';
9
+ export { POLICIES_INDEX_URL, POLICY_SITE_URL, POLICY_SOURCE, Policy, PolicyContent, PolicySection, PolicySlug, footerPolicies, getPolicyFileUrl, getPolicyPageUrl, loadPolicy, policies, publishedPolicies } from './policies.js';
8
10
  export { baseFooterLinks, baseNavLinks } from './utils.js';
9
11
  import 'react';
package/dist/index.js CHANGED
@@ -3,8 +3,10 @@ export * from "./components/Logo";
3
3
  export * from "./components/NavBar";
4
4
  import { default as default2 } from "./components/NoSSR";
5
5
  export * from "./components/Orb";
6
+ export * from "./components/PolicyDocument";
6
7
  import { default as default3 } from "./components/StarryBackground";
7
8
  export * from "./components/ThemeSwitcher";
9
+ export * from "./policies";
8
10
  export * from "./utils";
9
11
  export {
10
12
  default2 as NoSSR,
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var policies_exports = {};
20
+ __export(policies_exports, {
21
+ POLICIES_INDEX_URL: () => POLICIES_INDEX_URL,
22
+ POLICY_SITE_URL: () => POLICY_SITE_URL,
23
+ POLICY_SOURCE: () => POLICY_SOURCE,
24
+ footerPolicies: () => footerPolicies,
25
+ getPolicyFileUrl: () => getPolicyFileUrl,
26
+ getPolicyPageUrl: () => getPolicyPageUrl,
27
+ loadPolicy: () => loadPolicy,
28
+ policies: () => policies,
29
+ publishedPolicies: () => publishedPolicies
30
+ });
31
+ module.exports = __toCommonJS(policies_exports);
32
+ const POLICY_SOURCE = "https://raw.githubusercontent.com/TuwaIO/workflows/main/docs";
33
+ const POLICY_SITE_URL = "https://tuwa.io";
34
+ const POLICIES_INDEX_URL = "https://docs.tuwa.io/policies";
35
+ const policies = [
36
+ {
37
+ slug: "terms",
38
+ title: "Terms of Service",
39
+ description: "The rules for using the TUWA websites and documentation, Quasar Cloud, Quasar Community Edition and the open-source packages.",
40
+ href: "/terms",
41
+ published: true
42
+ },
43
+ {
44
+ slug: "privacy",
45
+ title: "Privacy Policy",
46
+ description: "What data TUWA collects and why, how it is protected, and how to access or delete it.",
47
+ href: "/privacy",
48
+ published: true
49
+ },
50
+ {
51
+ slug: "cookie",
52
+ title: "Cookie Policy",
53
+ description: "The cookies and Local Storage that the TUWA sites and the Quasar dashboard use.",
54
+ href: "/cookie",
55
+ published: true
56
+ },
57
+ {
58
+ slug: "refund",
59
+ title: "Refund Policy",
60
+ description: "When and how payments for Quasar Cloud quota are refunded.",
61
+ href: "/refund",
62
+ // Quota purchases are paused; the policy is published again when they reopen
63
+ published: false
64
+ },
65
+ {
66
+ slug: "security",
67
+ title: "Security Policy",
68
+ description: "How to report a vulnerability, what TUWA promises in return, and who is responsible for what.",
69
+ href: "/security",
70
+ published: true
71
+ },
72
+ {
73
+ slug: "dpa",
74
+ title: "Data Processing Addendum",
75
+ description: "How we process the personal data of your app users on your behalf when you use Quasar Cloud.",
76
+ href: "/dpa",
77
+ published: true,
78
+ footer: false
79
+ }
80
+ ];
81
+ const publishedPolicies = policies.filter((policy) => policy.published);
82
+ const footerPolicies = publishedPolicies.filter((policy) => policy.footer !== false);
83
+ function getPolicyPageUrl(slug, site = POLICY_SITE_URL) {
84
+ return `${site.replace(/\/+$/, "")}/${slug}`;
85
+ }
86
+ function getPolicyFileUrl(slug, format, source = POLICY_SOURCE) {
87
+ return `${source.replace(/\/+$/, "")}/${slug}.${format}`;
88
+ }
89
+ function isPolicyContent(value) {
90
+ if (!value || typeof value !== "object") return false;
91
+ const content = value;
92
+ return typeof content.title === "string" && typeof content.updated === "string" && typeof content.html === "string" && Array.isArray(content.sections) && content.sections.every(
93
+ (section) => !!section && typeof section.id === "string" && typeof section.title === "string"
94
+ );
95
+ }
96
+ async function loadPolicy(slug, options = {}) {
97
+ const url = getPolicyFileUrl(slug, "json", options.source);
98
+ const response = await fetch(url, { next: { revalidate: options.revalidate ?? 3600 } });
99
+ if (!response.ok) {
100
+ throw new Error(`loadPolicy: ${url} answered ${response.status}`);
101
+ }
102
+ const content = await response.json();
103
+ if (!isPolicyContent(content)) {
104
+ throw new Error(`loadPolicy: ${url} is not a policy page`);
105
+ }
106
+ return {
107
+ title: content.title,
108
+ updated: content.updated,
109
+ sections: content.sections.map(({ id, title }) => ({ id, title })),
110
+ html: content.html
111
+ };
112
+ }
113
+ // Annotate the CommonJS export names for ESM import in node:
114
+ 0 && (module.exports = {
115
+ POLICIES_INDEX_URL,
116
+ POLICY_SITE_URL,
117
+ POLICY_SOURCE,
118
+ footerPolicies,
119
+ getPolicyFileUrl,
120
+ getPolicyPageUrl,
121
+ loadPolicy,
122
+ policies,
123
+ publishedPolicies
124
+ });
@@ -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 };