@emplugins/emprivacy 1.0.0 → 2.0.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 +28 -18
- package/dist/index.d.mts +80 -4
- package/dist/index.mjs +876 -9
- package/docs/DEVELOPMENT.md +6 -10
- package/docs/GETTING_STARTED.md +11 -7
- package/docs/RELEASE_NOTES.md +3 -18
- package/docs/TESTING.md +9 -9
- package/package.json +11 -11
- package/dist/config-BJ1LHuri.mjs +0 -166
- package/dist/config-CqOtRoQR.d.mts +0 -63
- package/dist/sandbox-entry.d.mts +0 -283
- package/dist/sandbox-entry.mjs +0 -693
package/README.md
CHANGED
|
@@ -6,19 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
|
-
- **EmDash**
|
|
10
|
-
-
|
|
11
|
-
|
|
9
|
+
- **EmDash** `^0.38.0` (**tested with `0.38.0`**; re-test on your deployed minor when upgrading).
|
|
10
|
+
- **Node.js** `>= 22.16` (matches EmDash’s engine requirement).
|
|
11
|
+
- Register as a **native** plugin in **`astro.config`** via `plugins: []` (not `sandboxed: []`). EmPrivacy uses `page:fragments` for the public banner and scripts; that hook only runs for trusted in-process plugins. See [Page fragments](https://docs.emdashcms.com/plugins/creating-native-plugins/page-fragments/) and [Plugin overview](https://docs.emdashcms.com/plugins/overview/).
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
+
pnpm add @emplugins/emprivacy
|
|
17
|
+
# or
|
|
16
18
|
npm install @emplugins/emprivacy
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
Published under the [emplugins](https://www.npmjs.com/org/emplugins) npm org. Source: [github.com/EmPlugins/EmPrivacy](https://github.com/EmPlugins/EmPrivacy).
|
|
21
|
+
Published under the [emplugins](https://www.npmjs.com/org/emplugins) npm org. Source: [github.com/EmPlugins/EmPrivacy](https://github.com/EmPlugins/EmPrivacy). See [EMDASH_COMPAT.md](./EMDASH_COMPAT.md) for EmDash version mapping.
|
|
20
22
|
|
|
21
|
-
Use a **semver range** if you want controlled upgrades, for example `@emplugins/emprivacy@^1.0.0`. Versioning
|
|
23
|
+
Use a **semver range** if you want controlled upgrades, for example `@emplugins/emprivacy@^1.0.0`. Versioning: [docs/RELEASES.md](docs/RELEASES.md). Org publish: [docs/NPM_ORG_PUBLISH.md](docs/NPM_ORG_PUBLISH.md).
|
|
22
24
|
|
|
23
25
|
The legacy unscoped package `emprivacy` is deprecated; migrate imports to `@emplugins/emprivacy`.
|
|
24
26
|
|
|
@@ -28,7 +30,7 @@ The legacy unscoped package `emprivacy` is deprecated; migrate imports to `@empl
|
|
|
28
30
|
|
|
29
31
|
```ts
|
|
30
32
|
import { defineConfig } from "astro/config";
|
|
31
|
-
import
|
|
33
|
+
import emdash from "emdash/astro";
|
|
32
34
|
import { emprivacyPlugin } from "@emplugins/emprivacy";
|
|
33
35
|
|
|
34
36
|
export default defineConfig({
|
|
@@ -40,7 +42,9 @@ The legacy unscoped package `emprivacy` is deprecated; migrate imports to `@empl
|
|
|
40
42
|
});
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
Native descriptors belong in `plugins`, not `sandboxed`. EmDash loads the named `createPlugin()` export from the package at runtime.
|
|
46
|
+
|
|
47
|
+
2. **Use EmDash page integration** in your layout so fragments render: include `<EmDashHead />`, `<EmDashBodyStart />`, `<EmDashBodyEnd />` (or your theme’s equivalents), typically with a shared `createPublicPageContext({ Astro, … })`. See [EmDash page fragments](https://docs.emdashcms.com/plugins/creating-native-plugins/page-fragments/).
|
|
44
48
|
|
|
45
49
|
3. **Configure EmPrivacy in the admin** (shield → **EmPrivacy**):
|
|
46
50
|
- **Privacy policy** — Point to your existing EmDash **Page** using its **public path** (what you see in the address bar when that Page is open, e.g. `/privacy`), **or** a full `https://…` URL if the policy is hosted elsewhere. Root-relative paths are resolved with EmDash `ctx.url()` so links stay correct across environments.
|
|
@@ -64,6 +68,14 @@ Visitors see a banner on first visit (or when you bump **Policy / consent versio
|
|
|
64
68
|
| Optional server log | POST consent snapshots to `/_emdash/api/plugins/emprivacy/record` + optional storage rows (no IP in v1) |
|
|
65
69
|
| Google Consent Mode v2 | Optional denied defaults in `<head>` + `gtag('consent','update',…)` — validate with [Google’s docs](https://support.google.com/tagmanager/answer/13695607) |
|
|
66
70
|
|
|
71
|
+
## Capabilities
|
|
72
|
+
|
|
73
|
+
| Capability | Why |
|
|
74
|
+
|------------|-----|
|
|
75
|
+
| `hooks.page-fragments:register` | Public banner, styles, and consent bootstrap scripts |
|
|
76
|
+
|
|
77
|
+
Settings, KV, and declared plugin storage need no extra capability. Native plugins are not an isolation boundary: review and install this package like first-party site code.
|
|
78
|
+
|
|
67
79
|
## Legal disclaimer
|
|
68
80
|
|
|
69
81
|
EmPrivacy helps you implement **technical** consent UX and script loading patterns used for regulations such as **GDPR** and **CCPA/CIPA**. **You** remain responsible for:
|
|
@@ -81,16 +93,16 @@ Put **`emprivacyPlugin()` early** in the `plugins` array so `page:metadata` / `p
|
|
|
81
93
|
## Development
|
|
82
94
|
|
|
83
95
|
```bash
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
pnpm install
|
|
97
|
+
pnpm run typecheck # TypeScript
|
|
98
|
+
pnpm run build # ESM + types in dist/
|
|
99
|
+
pnpm test # Unit tests (see Testing)
|
|
100
|
+
pnpm run test:watch # Vitest in watch mode (optional)
|
|
89
101
|
```
|
|
90
102
|
|
|
91
|
-
Outputs ESM under `dist/` with typings
|
|
103
|
+
Outputs ESM under `dist/` with typings. Layout follows EmDash’s [native plugin packaging](https://docs.emdashcms.com/plugins/creating-native-plugins/distributing/) (`emprivacyPlugin()` descriptor + named `createPlugin()`).
|
|
92
104
|
|
|
93
|
-
Dependency, audit, and deprecation context
|
|
105
|
+
Dependency, audit, and deprecation context: [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md).
|
|
94
106
|
|
|
95
107
|
## Testing
|
|
96
108
|
|
|
@@ -132,13 +144,11 @@ Details: [docs/TESTING.md](docs/TESTING.md).
|
|
|
132
144
|
- [ ] Admin save updates the public banner
|
|
133
145
|
- [ ] Optional: server logging + recent records in admin
|
|
134
146
|
- [ ] Optional: Google Consent Mode (Tag Assistant / [Google](https://support.google.com/tagmanager/answer/13695607))
|
|
135
|
-
- [ ]
|
|
147
|
+
- [ ] Native `plugins: []` registration (see [Requirements](#requirements))
|
|
136
148
|
|
|
137
149
|
## Releases
|
|
138
150
|
|
|
139
|
-
npm releases follow **[Semantic Versioning](https://semver.org/)** (`MAJOR.MINOR.PATCH`). Tags are `v`-prefixed (e.g. `v0.1
|
|
140
|
-
|
|
141
|
-
**EmDash upgrades:** say `update to latest emdash release` in Cursor (skill: [`.cursor/skills/emdash-release`](.cursor/skills/emdash-release/SKILL.md)) to bump, test, and publish to npm + GitHub without a manual merge gate.
|
|
151
|
+
npm releases follow **[Semantic Versioning](https://semver.org/)** (`MAJOR.MINOR.PATCH`). Tags are `v`-prefixed (e.g. `v0.2.1`). See [docs/RELEASES.md](docs/RELEASES.md) for bump rules, `npm version` / `npm run release:*`, and publish checklist.
|
|
142
152
|
|
|
143
153
|
## License
|
|
144
154
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,87 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as emdash from "emdash";
|
|
2
2
|
import { PluginDescriptor } from "emdash";
|
|
3
3
|
|
|
4
|
+
//#region src/runtime.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Native EmDash runtime — loaded via the named `createPlugin` export.
|
|
7
|
+
* Uses `page:fragments`, which requires trusted in-process (native) execution.
|
|
8
|
+
*/
|
|
9
|
+
declare function createPlugin(): emdash.ResolvedPlugin<{
|
|
10
|
+
consentEvents: {
|
|
11
|
+
indexes: string[];
|
|
12
|
+
};
|
|
13
|
+
}>;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/config.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* EmPrivacy KV document (`consent:config`) and shared helpers.
|
|
18
|
+
*/
|
|
19
|
+
declare const KV_KEY: "consent:config";
|
|
20
|
+
declare const COOKIE_NAME: "emprivacy_cc";
|
|
21
|
+
/** How analytics scripts are chosen after the user consents to analytics. */
|
|
22
|
+
type AnalyticsProvider = "cloudflare" | "none" | "custom";
|
|
23
|
+
interface EmprivacyConfig {
|
|
24
|
+
bannerTitle: string;
|
|
25
|
+
bannerMessage: string;
|
|
26
|
+
/**
|
|
27
|
+
* Privacy policy location: full `https://…` URL **or** a root-relative path to an EmDash **Page**
|
|
28
|
+
* (e.g. `/privacy`) resolved with `ctx.url()` on the server.
|
|
29
|
+
*/
|
|
30
|
+
privacyPolicyUrl: string;
|
|
31
|
+
/** Optional cookie policy: same rules as `privacyPolicyUrl` (https URL or path like `/cookies`) */
|
|
32
|
+
cookiePolicyUrl: string;
|
|
33
|
+
/** When true, analytics/marketing require explicit opt-in in the UI */
|
|
34
|
+
strictDefaults: boolean;
|
|
35
|
+
/** Bump to invalidate client consent cookies and re-show the banner */
|
|
36
|
+
policyVersion: string;
|
|
37
|
+
/**
|
|
38
|
+
* Analytics when `cloudflare` — **site token** from Cloudflare → Web Analytics (injected with `data-cf-beacon`).
|
|
39
|
+
* Public in the same way as a normal site embed. Empty means no Cloudflare script until a token is saved.
|
|
40
|
+
*/
|
|
41
|
+
cloudflareWebAnalyticsToken: string;
|
|
42
|
+
/**
|
|
43
|
+
* Which analytics load path to use after consent. `cloudflare` = beacon + `cloudflareWebAnalyticsToken`;
|
|
44
|
+
* `custom` = `analyticsScriptUrls` only; `none` = no third-party analytics scripts.
|
|
45
|
+
*/
|
|
46
|
+
analyticsProvider: AnalyticsProvider;
|
|
47
|
+
/** When `analyticsProvider` is `custom`, these https script URLs load after analytics consent. */
|
|
48
|
+
analyticsScriptUrls: string[];
|
|
49
|
+
/** Third-party script URLs loaded only after marketing consent (https only) */
|
|
50
|
+
marketingScriptUrls: string[];
|
|
51
|
+
/** Emit Google Consent Mode v2 defaults (denied) in head; updates after choice */
|
|
52
|
+
googleConsentMode: boolean;
|
|
53
|
+
/** POST consent snapshots to the plugin record route and optional storage */
|
|
54
|
+
logConsentToServer: boolean;
|
|
55
|
+
}
|
|
56
|
+
declare const DEFAULT_CONFIG: EmprivacyConfig;
|
|
57
|
+
/** Reject characters that would break JSON or attributes; allow typical Cloudflare site token strings. */
|
|
58
|
+
declare function assertValidCloudflareToken(t: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Root-relative public path (EmDash page route), e.g. `/privacy`.
|
|
61
|
+
* Rejects protocol-relative URLs (`//…`) and whitespace.
|
|
62
|
+
*/
|
|
63
|
+
declare function isRootRelativeSitePath(s: string): boolean;
|
|
64
|
+
/** For hooks: turn stored path or absolute URL into a public absolute URL. */
|
|
65
|
+
declare function resolvePolicyHref(stored: string, ctx: {
|
|
66
|
+
url: (path: string) => string;
|
|
67
|
+
}): string;
|
|
68
|
+
declare function isValidPolicyHrefInput(s: string): boolean;
|
|
69
|
+
declare function normalizeConfig(raw: unknown): EmprivacyConfig;
|
|
70
|
+
interface ConsentRecordPayload {
|
|
71
|
+
createdAt: string;
|
|
72
|
+
policyVersion: string;
|
|
73
|
+
analytics: boolean;
|
|
74
|
+
marketing: boolean;
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
4
77
|
//#region src/index.d.ts
|
|
5
78
|
/**
|
|
6
|
-
* EmDash plugin descriptor — add to `plugins: []` in `emdash({ ... })` inside `astro.config`.
|
|
7
|
-
*
|
|
79
|
+
* EmDash native plugin descriptor — add to `plugins: []` in `emdash({ ... })` inside `astro.config`.
|
|
80
|
+
*
|
|
81
|
+
* EmPrivacy uses `page:fragments` (banner + consent scripts), which only runs for **native**
|
|
82
|
+
* plugins registered in `plugins: []`. Do not place this descriptor in `sandboxed: []`.
|
|
83
|
+
* See [Page fragments](https://docs.emdashcms.com/plugins/creating-native-plugins/page-fragments/).
|
|
8
84
|
*/
|
|
9
85
|
declare function emprivacyPlugin(): PluginDescriptor;
|
|
10
86
|
//#endregion
|
|
11
|
-
export { type AnalyticsProvider, COOKIE_NAME, type ConsentRecordPayload, DEFAULT_CONFIG, type EmprivacyConfig, KV_KEY, assertValidCloudflareToken, emprivacyPlugin, isRootRelativeSitePath, isValidPolicyHrefInput, normalizeConfig, resolvePolicyHref };
|
|
87
|
+
export { type AnalyticsProvider, COOKIE_NAME, type ConsentRecordPayload, DEFAULT_CONFIG, type EmprivacyConfig, KV_KEY, assertValidCloudflareToken, createPlugin, createPlugin as default, emprivacyPlugin, isRootRelativeSitePath, isValidPolicyHrefInput, normalizeConfig, resolvePolicyHref };
|