@scadable/privacy 0.1.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/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @scadable/privacy
2
+
3
+ Render your always-current privacy policy in a Next.js app. You publish the policy once
4
+ in the SCADABLE app; this component shows whatever version is currently published, so
5
+ updating your policy never means a redeploy on your side.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @scadable/privacy
11
+ ```
12
+
13
+ ## Use (App Router)
14
+
15
+ Drop the component on your privacy page. It is a Server Component, so the policy text is
16
+ server-rendered (good for SEO) and cached.
17
+
18
+ ```tsx
19
+ import { PrivacyPolicy } from '@scadable/privacy';
20
+
21
+ export default function PrivacyPage() {
22
+ return (
23
+ <main>
24
+ <PrivacyPolicy token="YOUR_PUBLIC_TOKEN" />
25
+ </main>
26
+ );
27
+ }
28
+ ```
29
+
30
+ Get `YOUR_PUBLIC_TOKEN` from the SCADABLE app after you publish a policy.
31
+
32
+ ### Options
33
+
34
+ | Prop | Type | Default | Notes |
35
+ | --- | --- | --- | --- |
36
+ | `token` | `string` | required | Your scope's public token. |
37
+ | `className` | `string` | none | Class on the wrapper element. |
38
+ | `showVersion` | `boolean` | `false` | Show a "Version N, last updated ..." line. |
39
+ | `revalidate` | `number \| false` | `3600` | Next.js ISR seconds. `false` = always fresh. |
40
+ | `docType` | `string` | `"privacy_policy"` | Which document to render. |
41
+ | `baseUrl` | `string` | `https://api.scadable.com` | Override the API base. |
42
+
43
+ ## Just the data
44
+
45
+ If you want to render it yourself:
46
+
47
+ ```ts
48
+ import { fetchPolicy } from '@scadable/privacy';
49
+
50
+ const policy = await fetchPolicy('YOUR_PUBLIC_TOKEN');
51
+ // { scope_name, domain, version, effective_date, updated_at, html }
52
+ ```
53
+
54
+ `policy.html` is an HTML content fragment with scoped styles (class `scadable-policy`),
55
+ safe to inject inline.
56
+
57
+ ## Notes
58
+
59
+ - This package only talks to the public SCADABLE API. It stores no secrets.
60
+ - The rendered HTML is your own published policy content from the SCADABLE API.
package/dist/index.cjs ADDED
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+
5
+ // src/client.ts
6
+ var DEFAULT_BASE_URL = "https://api.scadable.com";
7
+ async function fetchPolicy(token, options = {}) {
8
+ if (!token) {
9
+ throw new Error("@scadable/privacy: a policy token is required");
10
+ }
11
+ const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
12
+ const docType = options.docType ?? "privacy_policy";
13
+ const revalidate = options.revalidate ?? 3600;
14
+ const url = `${baseUrl}/policy/${encodeURIComponent(token)}?doc_type=${encodeURIComponent(docType)}&format=json`;
15
+ const init = revalidate === false ? { cache: "no-store" } : { next: { revalidate } };
16
+ const res = await fetch(url, init);
17
+ if (!res.ok) {
18
+ throw new Error(`@scadable/privacy: failed to load policy (${res.status}) for token "${token}"`);
19
+ }
20
+ return await res.json();
21
+ }
22
+ async function PrivacyPolicy({
23
+ token,
24
+ className,
25
+ showVersion = false,
26
+ ...options
27
+ }) {
28
+ const policy = await fetchPolicy(token, options);
29
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
30
+ /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: policy.html } }),
31
+ showVersion && policy.updated_at ? /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: 12, color: "#9ca3af", marginTop: 24 }, children: [
32
+ "Version ",
33
+ policy.version,
34
+ ". Last updated",
35
+ " ",
36
+ new Date(policy.updated_at).toLocaleDateString(),
37
+ "."
38
+ ] }) : null
39
+ ] });
40
+ }
41
+
42
+ exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
43
+ exports.PrivacyPolicy = PrivacyPolicy;
44
+ exports.fetchPolicy = fetchPolicy;
@@ -0,0 +1,66 @@
1
+ import * as React from 'react';
2
+
3
+ interface Policy {
4
+ /** The name you gave the scope (your company / site). */
5
+ scope_name: string;
6
+ domain: string;
7
+ /** "privacy_policy" today; more document types later. */
8
+ doc_type: string;
9
+ /** The published version number that is currently live. */
10
+ version: number;
11
+ effective_date: string;
12
+ /** ISO timestamp of when this version was published, or null. */
13
+ updated_at: string | null;
14
+ /** The rendered policy as an HTML content fragment (no <html> wrapper). */
15
+ html: string;
16
+ }
17
+ interface FetchPolicyOptions {
18
+ /** Which document to fetch. Default "privacy_policy". */
19
+ docType?: string;
20
+ /** Override the API base. Default "https://api.scadable.com". */
21
+ baseUrl?: string;
22
+ /**
23
+ * Next.js ISR revalidation, in seconds. The policy is server-rendered and
24
+ * cached for this long, then refreshed, so it stays current without a fetch
25
+ * on every request. Pass false to always fetch fresh. Default 3600 (1 hour).
26
+ */
27
+ revalidate?: number | false;
28
+ }
29
+
30
+ declare const DEFAULT_BASE_URL = "https://api.scadable.com";
31
+ /**
32
+ * Fetch the currently published policy for a public token.
33
+ *
34
+ * Works anywhere `fetch` is available. In a Next.js Server Component it uses ISR
35
+ * caching (the `revalidate` option) so the policy is server-rendered and cached,
36
+ * then refreshed, which keeps it both fast and current.
37
+ */
38
+ declare function fetchPolicy(token: string, options?: FetchPolicyOptions): Promise<Policy>;
39
+
40
+ interface PrivacyPolicyProps extends FetchPolicyOptions {
41
+ /** The public token from the SCADABLE app. */
42
+ token: string;
43
+ /** Optional wrapper class so you can style/position the policy. */
44
+ className?: string;
45
+ /** Show a small "Version N, last updated ..." line under the policy. Default false. */
46
+ showVersion?: boolean;
47
+ }
48
+ /**
49
+ * A React Server Component that renders your always-current privacy policy.
50
+ *
51
+ * It is server-rendered, so the legal text is in the initial HTML (crawlable),
52
+ * and cached via Next.js ISR (the `revalidate` option), so it stays current
53
+ * without fetching on every request. The HTML comes from the SCADABLE API
54
+ * (your own published, trusted content), injected as a content fragment.
55
+ *
56
+ * ```tsx
57
+ * import { PrivacyPolicy } from '@scadable/privacy';
58
+ *
59
+ * export default function Page() {
60
+ * return <PrivacyPolicy token="YOUR_PUBLIC_TOKEN" />;
61
+ * }
62
+ * ```
63
+ */
64
+ declare function PrivacyPolicy({ token, className, showVersion, ...options }: PrivacyPolicyProps): Promise<React.JSX.Element>;
65
+
66
+ export { DEFAULT_BASE_URL, type FetchPolicyOptions, type Policy, PrivacyPolicy, type PrivacyPolicyProps, fetchPolicy };
@@ -0,0 +1,66 @@
1
+ import * as React from 'react';
2
+
3
+ interface Policy {
4
+ /** The name you gave the scope (your company / site). */
5
+ scope_name: string;
6
+ domain: string;
7
+ /** "privacy_policy" today; more document types later. */
8
+ doc_type: string;
9
+ /** The published version number that is currently live. */
10
+ version: number;
11
+ effective_date: string;
12
+ /** ISO timestamp of when this version was published, or null. */
13
+ updated_at: string | null;
14
+ /** The rendered policy as an HTML content fragment (no <html> wrapper). */
15
+ html: string;
16
+ }
17
+ interface FetchPolicyOptions {
18
+ /** Which document to fetch. Default "privacy_policy". */
19
+ docType?: string;
20
+ /** Override the API base. Default "https://api.scadable.com". */
21
+ baseUrl?: string;
22
+ /**
23
+ * Next.js ISR revalidation, in seconds. The policy is server-rendered and
24
+ * cached for this long, then refreshed, so it stays current without a fetch
25
+ * on every request. Pass false to always fetch fresh. Default 3600 (1 hour).
26
+ */
27
+ revalidate?: number | false;
28
+ }
29
+
30
+ declare const DEFAULT_BASE_URL = "https://api.scadable.com";
31
+ /**
32
+ * Fetch the currently published policy for a public token.
33
+ *
34
+ * Works anywhere `fetch` is available. In a Next.js Server Component it uses ISR
35
+ * caching (the `revalidate` option) so the policy is server-rendered and cached,
36
+ * then refreshed, which keeps it both fast and current.
37
+ */
38
+ declare function fetchPolicy(token: string, options?: FetchPolicyOptions): Promise<Policy>;
39
+
40
+ interface PrivacyPolicyProps extends FetchPolicyOptions {
41
+ /** The public token from the SCADABLE app. */
42
+ token: string;
43
+ /** Optional wrapper class so you can style/position the policy. */
44
+ className?: string;
45
+ /** Show a small "Version N, last updated ..." line under the policy. Default false. */
46
+ showVersion?: boolean;
47
+ }
48
+ /**
49
+ * A React Server Component that renders your always-current privacy policy.
50
+ *
51
+ * It is server-rendered, so the legal text is in the initial HTML (crawlable),
52
+ * and cached via Next.js ISR (the `revalidate` option), so it stays current
53
+ * without fetching on every request. The HTML comes from the SCADABLE API
54
+ * (your own published, trusted content), injected as a content fragment.
55
+ *
56
+ * ```tsx
57
+ * import { PrivacyPolicy } from '@scadable/privacy';
58
+ *
59
+ * export default function Page() {
60
+ * return <PrivacyPolicy token="YOUR_PUBLIC_TOKEN" />;
61
+ * }
62
+ * ```
63
+ */
64
+ declare function PrivacyPolicy({ token, className, showVersion, ...options }: PrivacyPolicyProps): Promise<React.JSX.Element>;
65
+
66
+ export { DEFAULT_BASE_URL, type FetchPolicyOptions, type Policy, PrivacyPolicy, type PrivacyPolicyProps, fetchPolicy };
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+
3
+ // src/client.ts
4
+ var DEFAULT_BASE_URL = "https://api.scadable.com";
5
+ async function fetchPolicy(token, options = {}) {
6
+ if (!token) {
7
+ throw new Error("@scadable/privacy: a policy token is required");
8
+ }
9
+ const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
10
+ const docType = options.docType ?? "privacy_policy";
11
+ const revalidate = options.revalidate ?? 3600;
12
+ const url = `${baseUrl}/policy/${encodeURIComponent(token)}?doc_type=${encodeURIComponent(docType)}&format=json`;
13
+ const init = revalidate === false ? { cache: "no-store" } : { next: { revalidate } };
14
+ const res = await fetch(url, init);
15
+ if (!res.ok) {
16
+ throw new Error(`@scadable/privacy: failed to load policy (${res.status}) for token "${token}"`);
17
+ }
18
+ return await res.json();
19
+ }
20
+ async function PrivacyPolicy({
21
+ token,
22
+ className,
23
+ showVersion = false,
24
+ ...options
25
+ }) {
26
+ const policy = await fetchPolicy(token, options);
27
+ return /* @__PURE__ */ jsxs("div", { className, children: [
28
+ /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: policy.html } }),
29
+ showVersion && policy.updated_at ? /* @__PURE__ */ jsxs("p", { style: { fontSize: 12, color: "#9ca3af", marginTop: 24 }, children: [
30
+ "Version ",
31
+ policy.version,
32
+ ". Last updated",
33
+ " ",
34
+ new Date(policy.updated_at).toLocaleDateString(),
35
+ "."
36
+ ] }) : null
37
+ ] });
38
+ }
39
+
40
+ export { DEFAULT_BASE_URL, PrivacyPolicy, fetchPolicy };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@scadable/privacy",
3
+ "version": "0.1.0",
4
+ "description": "Render your always-current SCADABLE privacy policy in a Next.js app.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "dev": "tsup --watch",
25
+ "typecheck": "tsc --noEmit",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "keywords": [
29
+ "scadable",
30
+ "privacy",
31
+ "privacy-policy",
32
+ "compliance",
33
+ "gdpr",
34
+ "ccpa",
35
+ "nextjs",
36
+ "react"
37
+ ],
38
+ "peerDependencies": {
39
+ "next": ">=13",
40
+ "react": ">=18"
41
+ },
42
+ "devDependencies": {
43
+ "@types/react": "^18.3.0",
44
+ "next": "^14.2.0",
45
+ "react": "^18.3.0",
46
+ "tsup": "^8.3.0",
47
+ "typescript": "^5.6.0"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/scadable/sdk.git",
55
+ "directory": "next"
56
+ }
57
+ }