@runhalo/engine 0.1.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,254 @@
1
+ "use strict";
2
+ /**
3
+ * Age Gate Authentication Scaffold
4
+ * Addresses: coppa-auth-001 (CRITICAL)
5
+ * Generates an age verification gate that blocks users under 13
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.ageGateAuthTemplate = void 0;
9
+ function generateReact(typescript) {
10
+ const ext = typescript ? 'tsx' : 'jsx';
11
+ const typeAnnotation = typescript ? ': string' : '';
12
+ const stateType = typescript ? '<boolean>' : '';
13
+ const eventType = typescript ? ': React.FormEvent<HTMLFormElement>' : '';
14
+ const changeType = typescript ? ': React.ChangeEvent<HTMLInputElement>' : '';
15
+ const propsType = typescript
16
+ ? `\ninterface AgeGateProps {\n children: React.ReactNode;\n minimumAge?: number;\n onVerified?: () => void;\n onBlocked?: () => void;\n}\n`
17
+ : '';
18
+ const propsArg = typescript ? '{ children, minimumAge = 13, onVerified, onBlocked }: AgeGateProps' : '{ children, minimumAge = 13, onVerified, onBlocked }';
19
+ const component = `/**
20
+ * AgeGate — COPPA-compliant age verification component
21
+ *
22
+ * Blocks access for users under the minimum age (default: 13).
23
+ * Uses date-of-birth verification (not simple yes/no buttons).
24
+ * Stores verification in sessionStorage (not persistent — COPPA best practice).
25
+ *
26
+ * Usage:
27
+ * <AgeGate>
28
+ * <YourProtectedContent />
29
+ * </AgeGate>
30
+ *
31
+ * Generated by Halo (runhalo.dev) — COPPA compliance scaffold
32
+ */
33
+
34
+ import React, { useState, useCallback } from 'react';
35
+ ${propsType}
36
+ const AGE_GATE_KEY = 'halo_age_verified';
37
+
38
+ export function AgeGate(${propsArg}) {
39
+ const [verified, setVerified] = useState${stateType}(() => {
40
+ // Check sessionStorage (not localStorage — don't persist across sessions)
41
+ if (typeof window !== 'undefined') {
42
+ return sessionStorage.getItem(AGE_GATE_KEY) === 'true';
43
+ }
44
+ return false;
45
+ });
46
+ const [dob, setDob] = useState${typescript ? '<string>' : ''}('');
47
+ const [error, setError] = useState${typescript ? '<string>' : ''}('');
48
+ const [blocked, setBlocked] = useState${stateType}(false);
49
+
50
+ const handleSubmit = useCallback((e${eventType}) => {
51
+ e.preventDefault();
52
+ setError('');
53
+
54
+ if (!dob) {
55
+ setError('Please enter your date of birth.');
56
+ return;
57
+ }
58
+
59
+ const birthDate = new Date(dob);
60
+ const today = new Date();
61
+ let age = today.getFullYear() - birthDate.getFullYear();
62
+ const monthDiff = today.getMonth() - birthDate.getMonth();
63
+ if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
64
+ age--;
65
+ }
66
+
67
+ if (age >= minimumAge) {
68
+ sessionStorage.setItem(AGE_GATE_KEY, 'true');
69
+ setVerified(true);
70
+ onVerified?.();
71
+ } else {
72
+ setBlocked(true);
73
+ onBlocked?.();
74
+ }
75
+ }, [dob, minimumAge, onVerified, onBlocked]);
76
+
77
+ if (verified) {
78
+ return <>{children}</>;
79
+ }
80
+
81
+ if (blocked) {
82
+ return (
83
+ <div style={{ textAlign: 'center', padding: '2rem', maxWidth: '400px', margin: '0 auto' }}>
84
+ <h2>Access Restricted</h2>
85
+ <p>
86
+ Sorry, you must be at least {minimumAge} years old to access this content.
87
+ If you believe this is an error, please contact your parent or guardian.
88
+ </p>
89
+ </div>
90
+ );
91
+ }
92
+
93
+ return (
94
+ <div style={{ textAlign: 'center', padding: '2rem', maxWidth: '400px', margin: '0 auto' }}>
95
+ <h2>Age Verification Required</h2>
96
+ <p>Please enter your date of birth to continue.</p>
97
+ <form onSubmit={handleSubmit} style={{ marginTop: '1rem' }}>
98
+ <label htmlFor="halo-dob" style={{ display: 'block', marginBottom: '0.5rem' }}>
99
+ Date of Birth
100
+ </label>
101
+ <input
102
+ id="halo-dob"
103
+ type="date"
104
+ value={dob}
105
+ onChange={(e${changeType}) => setDob(e.target.value)}
106
+ required
107
+ max={new Date().toISOString().split('T')[0]}
108
+ style={{ padding: '0.5rem', fontSize: '1rem', width: '100%', boxSizing: 'border-box' }}
109
+ />
110
+ {error && <p style={{ color: 'red', marginTop: '0.5rem' }}>{error}</p>}
111
+ <button
112
+ type="submit"
113
+ style={{
114
+ marginTop: '1rem',
115
+ padding: '0.75rem 2rem',
116
+ fontSize: '1rem',
117
+ cursor: 'pointer',
118
+ width: '100%',
119
+ }}
120
+ >
121
+ Verify Age
122
+ </button>
123
+ </form>
124
+ </div>
125
+ );
126
+ }
127
+
128
+ export default AgeGate;
129
+ `;
130
+ return [
131
+ {
132
+ relativePath: `components/AgeGate.${ext}`,
133
+ content: component,
134
+ description: 'COPPA-compliant age gate component with DOB verification',
135
+ },
136
+ ];
137
+ }
138
+ function generatePlainJS() {
139
+ const code = `/**
140
+ * AgeGate — COPPA-compliant age verification
141
+ *
142
+ * Blocks access for users under 13.
143
+ * Uses date-of-birth verification (not simple yes/no).
144
+ * Stores verification in sessionStorage (not persistent).
145
+ *
146
+ * Usage:
147
+ * const ageGate = new AgeGate(document.getElementById('app'));
148
+ * ageGate.onVerified = () => { showProtectedContent(); };
149
+ *
150
+ * Generated by Halo (runhalo.dev) — COPPA compliance scaffold
151
+ */
152
+
153
+ class AgeGate {
154
+ constructor(container, options = {}) {
155
+ this.container = container;
156
+ this.minimumAge = options.minimumAge || 13;
157
+ this.onVerified = options.onVerified || null;
158
+ this.onBlocked = options.onBlocked || null;
159
+ this.storageKey = 'halo_age_verified';
160
+
161
+ // Check if already verified this session
162
+ if (sessionStorage.getItem(this.storageKey) === 'true') {
163
+ if (this.onVerified) this.onVerified();
164
+ return;
165
+ }
166
+
167
+ this.render();
168
+ }
169
+
170
+ render() {
171
+ const today = new Date().toISOString().split('T')[0];
172
+ this.container.innerHTML = \`
173
+ <div style="text-align: center; padding: 2rem; max-width: 400px; margin: 0 auto;">
174
+ <h2>Age Verification Required</h2>
175
+ <p>Please enter your date of birth to continue.</p>
176
+ <form id="halo-age-form" style="margin-top: 1rem;">
177
+ <label for="halo-dob" style="display: block; margin-bottom: 0.5rem;">Date of Birth</label>
178
+ <input id="halo-dob" type="date" required max="\${today}"
179
+ style="padding: 0.5rem; font-size: 1rem; width: 100%; box-sizing: border-box;" />
180
+ <div id="halo-age-error" style="color: red; margin-top: 0.5rem; display: none;"></div>
181
+ <button type="submit"
182
+ style="margin-top: 1rem; padding: 0.75rem 2rem; font-size: 1rem; cursor: pointer; width: 100%;">
183
+ Verify Age
184
+ </button>
185
+ </form>
186
+ </div>
187
+ \`;
188
+
189
+ this.container.querySelector('#halo-age-form').addEventListener('submit', (e) => {
190
+ e.preventDefault();
191
+ this.verify();
192
+ });
193
+ }
194
+
195
+ verify() {
196
+ const dobInput = this.container.querySelector('#halo-dob');
197
+ const errorDiv = this.container.querySelector('#halo-age-error');
198
+
199
+ if (!dobInput.value) {
200
+ errorDiv.textContent = 'Please enter your date of birth.';
201
+ errorDiv.style.display = 'block';
202
+ return;
203
+ }
204
+
205
+ const birthDate = new Date(dobInput.value);
206
+ const today = new Date();
207
+ let age = today.getFullYear() - birthDate.getFullYear();
208
+ const monthDiff = today.getMonth() - birthDate.getMonth();
209
+ if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
210
+ age--;
211
+ }
212
+
213
+ if (age >= this.minimumAge) {
214
+ sessionStorage.setItem(this.storageKey, 'true');
215
+ if (this.onVerified) this.onVerified();
216
+ } else {
217
+ this.container.innerHTML = \`
218
+ <div style="text-align: center; padding: 2rem; max-width: 400px; margin: 0 auto;">
219
+ <h2>Access Restricted</h2>
220
+ <p>Sorry, you must be at least \${this.minimumAge} years old to access this content.</p>
221
+ </div>
222
+ \`;
223
+ if (this.onBlocked) this.onBlocked();
224
+ }
225
+ }
226
+ }
227
+
228
+ // CommonJS + ESM compatibility
229
+ if (typeof module !== 'undefined') module.exports = { AgeGate };
230
+ `;
231
+ return [
232
+ {
233
+ relativePath: 'age-gate.js',
234
+ content: code,
235
+ description: 'COPPA-compliant age gate with DOB verification (vanilla JS)',
236
+ },
237
+ ];
238
+ }
239
+ exports.ageGateAuthTemplate = {
240
+ scaffoldId: 'age-gate-auth',
241
+ name: 'Age Gate Authentication',
242
+ description: 'COPPA-compliant age verification gate that blocks users under 13 using date-of-birth verification',
243
+ ruleIds: ['coppa-auth-001'],
244
+ generate(framework, typescript) {
245
+ switch (framework) {
246
+ case 'react':
247
+ case 'nextjs':
248
+ return generateReact(typescript);
249
+ default:
250
+ return generatePlainJS();
251
+ }
252
+ },
253
+ };
254
+ //# sourceMappingURL=age-gate-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age-gate-auth.js","sourceRoot":"","sources":["../../../src/scaffolds/templates/age-gate-auth.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAKH,SAAS,aAAa,CAAC,UAAmB;IACxC,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IACvC,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,MAAM,SAAS,GAAG,UAAU;QAC1B,CAAC,CAAC,8IAA8I;QAChJ,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,oEAAoE,CAAC,CAAC,CAAC,sDAAsD,CAAC;IAE5J,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;EAgBlB,SAAS;;;0BAGe,QAAQ;4CACU,SAAS;;;;;;;kCAOnB,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;sCACxB,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;0CACxB,SAAS;;uCAEZ,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAuDxB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;CAwBjC,CAAC;IAEA,OAAO;QACL;YACE,YAAY,EAAE,sBAAsB,GAAG,EAAE;YACzC,OAAO,EAAE,SAAS;YAClB,WAAW,EAAE,0DAA0D;SACxE;KACF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Fd,CAAC;IAEA,OAAO;QACL;YACE,YAAY,EAAE,aAAa;YAC3B,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,6DAA6D;SAC3E;KACF,CAAC;AACJ,CAAC;AAEY,QAAA,mBAAmB,GAAqB;IACnD,UAAU,EAAE,eAAe;IAC3B,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EAAE,mGAAmG;IAChH,OAAO,EAAE,CAAC,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,UAAU;QAC5B,QAAQ,SAAS,EAAE,CAAC;YAClB,KAAK,OAAO,CAAC;YACb,KAAK,QAAQ;gBACX,OAAO,aAAa,CAAC,UAAU,CAAC,CAAC;YACnC;gBACE,OAAO,eAAe,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Cookie Consent Banner Scaffold
3
+ * Addresses: coppa-cookies-016
4
+ * Generates a privacy-first cookie consent banner (deny by default)
5
+ */
6
+ import type { ScaffoldTemplate } from '../index';
7
+ export declare const consentCookiesTemplate: ScaffoldTemplate;
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ /**
3
+ * Cookie Consent Banner Scaffold
4
+ * Addresses: coppa-cookies-016
5
+ * Generates a privacy-first cookie consent banner (deny by default)
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.consentCookiesTemplate = void 0;
9
+ function generateReact(typescript) {
10
+ const ext = typescript ? 'tsx' : 'jsx';
11
+ const propsType = typescript
12
+ ? `\ninterface CookieConsentProps {\n onAccept?: () => void;\n onDecline?: () => void;\n privacyPolicyUrl?: string;\n}\n`
13
+ : '';
14
+ const propsArg = typescript
15
+ ? '{ onAccept, onDecline, privacyPolicyUrl = "/privacy" }: CookieConsentProps'
16
+ : '{ onAccept, onDecline, privacyPolicyUrl = "/privacy" }';
17
+ const component = `/**
18
+ * CookieConsentBanner — COPPA-compliant cookie consent
19
+ *
20
+ * Privacy-first: all non-essential cookies are OFF by default.
21
+ * No cookies are set until the user explicitly accepts.
22
+ * Consent is stored in localStorage (not a cookie itself).
23
+ *
24
+ * COPPA requirement: Children's sites must not use tracking cookies
25
+ * without verifiable parental consent.
26
+ *
27
+ * Usage:
28
+ * <CookieConsentBanner
29
+ * onAccept={() => enableAnalytics()}
30
+ * onDecline={() => console.log('User declined cookies')}
31
+ * />
32
+ *
33
+ * Generated by Halo (runhalo.dev) — COPPA compliance scaffold
34
+ */
35
+
36
+ import React, { useState, useEffect } from 'react';
37
+ ${propsType}
38
+ const CONSENT_KEY = 'halo_cookie_consent';
39
+
40
+ export function CookieConsentBanner(${propsArg}) {
41
+ const [visible, setVisible] = useState(false);
42
+
43
+ useEffect(() => {
44
+ // Only show if user hasn't made a choice yet
45
+ const stored = localStorage.getItem(CONSENT_KEY);
46
+ if (stored === null) {
47
+ setVisible(true);
48
+ }
49
+ }, []);
50
+
51
+ const handleAccept = () => {
52
+ localStorage.setItem(CONSENT_KEY, 'accepted');
53
+ setVisible(false);
54
+ onAccept?.();
55
+ };
56
+
57
+ const handleDecline = () => {
58
+ localStorage.setItem(CONSENT_KEY, 'declined');
59
+ setVisible(false);
60
+ onDecline?.();
61
+ };
62
+
63
+ if (!visible) return null;
64
+
65
+ return (
66
+ <div
67
+ role="dialog"
68
+ aria-label="Cookie consent"
69
+ style={{
70
+ position: 'fixed',
71
+ bottom: 0,
72
+ left: 0,
73
+ right: 0,
74
+ backgroundColor: '#1a1a2e',
75
+ color: '#e0e0e0',
76
+ padding: '1rem 1.5rem',
77
+ display: 'flex',
78
+ alignItems: 'center',
79
+ justifyContent: 'space-between',
80
+ flexWrap: 'wrap',
81
+ gap: '1rem',
82
+ zIndex: 9999,
83
+ boxShadow: '0 -2px 10px rgba(0, 0, 0, 0.3)',
84
+ }}
85
+ >
86
+ <p style={{ margin: 0, flex: 1, minWidth: '200px', fontSize: '0.9rem' }}>
87
+ We use cookies to improve your experience.{' '}
88
+ <a href={privacyPolicyUrl} style={{ color: '#818cf8', textDecoration: 'underline' }}>
89
+ Privacy Policy
90
+ </a>
91
+ </p>
92
+ <div style={{ display: 'flex', gap: '0.5rem' }}>
93
+ <button
94
+ onClick={handleDecline}
95
+ style={{
96
+ padding: '0.5rem 1.25rem',
97
+ border: '1px solid #555',
98
+ backgroundColor: 'transparent',
99
+ color: '#e0e0e0',
100
+ cursor: 'pointer',
101
+ borderRadius: '4px',
102
+ fontSize: '0.85rem',
103
+ }}
104
+ >
105
+ Decline
106
+ </button>
107
+ <button
108
+ onClick={handleAccept}
109
+ style={{
110
+ padding: '0.5rem 1.25rem',
111
+ border: 'none',
112
+ backgroundColor: '#6366f1',
113
+ color: '#fff',
114
+ cursor: 'pointer',
115
+ borderRadius: '4px',
116
+ fontSize: '0.85rem',
117
+ }}
118
+ >
119
+ Accept
120
+ </button>
121
+ </div>
122
+ </div>
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Check if cookies have been consented to.
128
+ * Use this before initializing any analytics or tracking.
129
+ *
130
+ * Example:
131
+ * if (hasCookieConsent()) {
132
+ * initializeAnalytics();
133
+ * }
134
+ */
135
+ export function hasCookieConsent()${typescript ? ': boolean' : ''} {
136
+ if (typeof window === 'undefined') return false;
137
+ return localStorage.getItem(CONSENT_KEY) === 'accepted';
138
+ }
139
+
140
+ export default CookieConsentBanner;
141
+ `;
142
+ return [
143
+ {
144
+ relativePath: `components/CookieConsentBanner.${ext}`,
145
+ content: component,
146
+ description: 'COPPA-compliant cookie consent banner with deny-by-default behavior',
147
+ },
148
+ ];
149
+ }
150
+ function generatePlainJS() {
151
+ const code = `/**
152
+ * CookieConsentBanner — COPPA-compliant cookie consent
153
+ *
154
+ * Privacy-first: all non-essential cookies are OFF by default.
155
+ * No cookies are set until the user explicitly accepts.
156
+ *
157
+ * Usage:
158
+ * const banner = new CookieConsentBanner({
159
+ * onAccept: () => enableAnalytics(),
160
+ * onDecline: () => console.log('User declined'),
161
+ * });
162
+ *
163
+ * Generated by Halo (runhalo.dev) — COPPA compliance scaffold
164
+ */
165
+
166
+ class CookieConsentBanner {
167
+ constructor(options = {}) {
168
+ this.onAccept = options.onAccept || null;
169
+ this.onDecline = options.onDecline || null;
170
+ this.privacyPolicyUrl = options.privacyPolicyUrl || '/privacy';
171
+ this.storageKey = 'halo_cookie_consent';
172
+
173
+ // Only show if user hasn't made a choice
174
+ const stored = localStorage.getItem(this.storageKey);
175
+ if (stored === null) {
176
+ this.render();
177
+ }
178
+ }
179
+
180
+ render() {
181
+ const banner = document.createElement('div');
182
+ banner.setAttribute('role', 'dialog');
183
+ banner.setAttribute('aria-label', 'Cookie consent');
184
+ banner.style.cssText = \`
185
+ position: fixed; bottom: 0; left: 0; right: 0;
186
+ background: #1a1a2e; color: #e0e0e0;
187
+ padding: 1rem 1.5rem; display: flex; align-items: center;
188
+ justify-content: space-between; flex-wrap: wrap; gap: 1rem;
189
+ z-index: 9999; box-shadow: 0 -2px 10px rgba(0,0,0,0.3);
190
+ \`;
191
+
192
+ banner.innerHTML = \`
193
+ <p style="margin:0; flex:1; min-width:200px; font-size:0.9rem;">
194
+ We use cookies to improve your experience.
195
+ <a href="\${this.privacyPolicyUrl}" style="color:#818cf8; text-decoration:underline;">Privacy Policy</a>
196
+ </p>
197
+ <div style="display:flex; gap:0.5rem;">
198
+ <button id="halo-cookie-decline" style="padding:0.5rem 1.25rem; border:1px solid #555; background:transparent; color:#e0e0e0; cursor:pointer; border-radius:4px; font-size:0.85rem;">Decline</button>
199
+ <button id="halo-cookie-accept" style="padding:0.5rem 1.25rem; border:none; background:#6366f1; color:#fff; cursor:pointer; border-radius:4px; font-size:0.85rem;">Accept</button>
200
+ </div>
201
+ \`;
202
+
203
+ banner.querySelector('#halo-cookie-decline').addEventListener('click', () => {
204
+ localStorage.setItem(this.storageKey, 'declined');
205
+ banner.remove();
206
+ if (this.onDecline) this.onDecline();
207
+ });
208
+
209
+ banner.querySelector('#halo-cookie-accept').addEventListener('click', () => {
210
+ localStorage.setItem(this.storageKey, 'accepted');
211
+ banner.remove();
212
+ if (this.onAccept) this.onAccept();
213
+ });
214
+
215
+ document.body.appendChild(banner);
216
+ this.element = banner;
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Check if cookies have been consented to.
222
+ * Use before initializing analytics or tracking.
223
+ */
224
+ function hasCookieConsent() {
225
+ return localStorage.getItem('halo_cookie_consent') === 'accepted';
226
+ }
227
+
228
+ if (typeof module !== 'undefined') module.exports = { CookieConsentBanner, hasCookieConsent };
229
+ `;
230
+ return [
231
+ {
232
+ relativePath: 'cookie-consent.js',
233
+ content: code,
234
+ description: 'COPPA-compliant cookie consent banner (vanilla JS)',
235
+ },
236
+ ];
237
+ }
238
+ exports.consentCookiesTemplate = {
239
+ scaffoldId: 'consent-cookies',
240
+ name: 'Cookie Consent Banner',
241
+ description: 'Privacy-first cookie consent banner with deny-by-default behavior',
242
+ ruleIds: ['coppa-cookies-016'],
243
+ generate(framework, typescript) {
244
+ switch (framework) {
245
+ case 'react':
246
+ case 'nextjs':
247
+ return generateReact(typescript);
248
+ default:
249
+ return generatePlainJS();
250
+ }
251
+ },
252
+ };
253
+ //# sourceMappingURL=consent-cookies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-cookies.js","sourceRoot":"","sources":["../../../src/scaffolds/templates/consent-cookies.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAKH,SAAS,aAAa,CAAC,UAAmB;IACxC,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IACvC,MAAM,SAAS,GAAG,UAAU;QAC1B,CAAC,CAAC,0HAA0H;QAC5H,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,QAAQ,GAAG,UAAU;QACzB,CAAC,CAAC,4EAA4E;QAC9E,CAAC,CAAC,wDAAwD,CAAC;IAE7D,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;EAoBlB,SAAS;;;sCAG2B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCA+FV,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;;;;;;CAMhE,CAAC;IAEA,OAAO;QACL;YACE,YAAY,EAAE,kCAAkC,GAAG,EAAE;YACrD,OAAO,EAAE,SAAS;YAClB,WAAW,EAAE,qEAAqE;SACnF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Ed,CAAC;IAEA,OAAO;QACL;YACE,YAAY,EAAE,mBAAmB;YACjC,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,oDAAoD;SAClE;KACF,CAAC;AACJ,CAAC;AAEY,QAAA,sBAAsB,GAAqB;IACtD,UAAU,EAAE,iBAAiB;IAC7B,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,mEAAmE;IAChF,OAAO,EAAE,CAAC,mBAAmB,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,UAAU;QAC5B,QAAQ,SAAS,EAAE,CAAC;YAClB,KAAK,OAAO,CAAC;YACb,KAAK,QAAQ;gBACX,OAAO,aAAa,CAAC,UAAU,CAAC,CAAC;YACnC;gBACE,OAAO,eAAe,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * PII Sanitizer Scaffold
3
+ * Addresses: coppa-data-002 (HIGH)
4
+ * Generates middleware/utility to strip PII from URL parameters
5
+ */
6
+ import type { ScaffoldTemplate } from '../index';
7
+ export declare const piiSanitizerTemplate: ScaffoldTemplate;