@nowline/embed 0.4.2 → 0.5.1
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 +14 -26
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -19
- package/dist/index.js.map +1 -1
- package/dist/meta.json +78 -48
- package/dist/nowline.esm.js +396 -109
- package/dist/nowline.esm.js.map +4 -4
- package/dist/nowline.min.js +76 -76
- package/dist/nowline.min.js.map +4 -4
- package/dist/share.d.ts +0 -1
- package/dist/share.d.ts.map +1 -1
- package/dist/share.js +0 -1
- package/dist/share.js.map +1 -1
- package/dist/theme.d.ts +3 -3
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +5 -3
- package/dist/theme.js.map +1 -1
- package/package.json +5 -7
- package/src/index.ts +12 -31
- package/src/share.ts +0 -1
- package/src/theme.ts +7 -5
- package/dist/auth/allowlist.d.ts +0 -20
- package/dist/auth/allowlist.d.ts.map +0 -1
- package/dist/auth/allowlist.js +0 -33
- package/dist/auth/allowlist.js.map +0 -1
- package/dist/auth/env.d.ts +0 -23
- package/dist/auth/env.d.ts.map +0 -1
- package/dist/auth/env.js +0 -24
- package/dist/auth/env.js.map +0 -1
- package/dist/auth/firebase-auth.client.d.ts +0 -21
- package/dist/auth/firebase-auth.client.d.ts.map +0 -1
- package/dist/auth/firebase-auth.client.js +0 -146
- package/dist/auth/firebase-auth.client.js.map +0 -1
- package/src/auth/allowlist.ts +0 -32
- package/src/auth/env.ts +0 -37
- package/src/auth/firebase-auth.client.ts +0 -178
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client-side Firebase Auth gate for the dev embed bundle.
|
|
3
|
-
*
|
|
4
|
-
* Mirrors the commercial site's `firebase-auth.client.ts` so the
|
|
5
|
-
* two Lolay dev surfaces share one allowlist UX. Loaded only on the
|
|
6
|
-
* dev build (when `__NOWLINE_EMBED_ENV__ === 'dev'`); the prod build
|
|
7
|
-
* tree-shakes the dynamic import in `src/index.ts` and never pulls
|
|
8
|
-
* `firebase/app` or `firebase/auth` into the IIFE.
|
|
9
|
-
*
|
|
10
|
-
* Renders a full-viewport overlay with z-index 2147483647 so it sits
|
|
11
|
-
* above any host-page content. Until the visitor signs in with an
|
|
12
|
-
* allowlisted Google account, the overlay stays put; once allowlisted,
|
|
13
|
-
* it removes itself and the embed's auto-scan reaches the rendered
|
|
14
|
-
* SVG underneath. The host page is told nothing — the gate is purely
|
|
15
|
-
* client-side, opaque to the embedder.
|
|
16
|
-
*
|
|
17
|
-
* See specs/embed.md § Bootstrap status (dev auth gate) and
|
|
18
|
-
* the infrastructure deploy runbook § 4 for the deploy-side wiring.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { type FirebaseApp, initializeApp } from 'firebase/app';
|
|
22
|
-
import {
|
|
23
|
-
type Auth,
|
|
24
|
-
GoogleAuthProvider,
|
|
25
|
-
getAuth,
|
|
26
|
-
onAuthStateChanged,
|
|
27
|
-
signInWithPopup,
|
|
28
|
-
signOut,
|
|
29
|
-
type User,
|
|
30
|
-
} from 'firebase/auth';
|
|
31
|
-
import { isAllowlisted } from './allowlist.js';
|
|
32
|
-
|
|
33
|
-
// esbuild-substituted at build time from PUBLIC_FIREBASE_* env vars in
|
|
34
|
-
// .github/workflows/embed-cdn.yml (sourced from the `embed-dev` GitHub
|
|
35
|
-
// environment-scoped variables — see the infrastructure deploy runbook § 2.5).
|
|
36
|
-
declare const __NOWLINE_FIREBASE_API_KEY__: string;
|
|
37
|
-
declare const __NOWLINE_FIREBASE_AUTH_DOMAIN__: string;
|
|
38
|
-
declare const __NOWLINE_FIREBASE_PROJECT_ID__: string;
|
|
39
|
-
declare const __NOWLINE_FIREBASE_APP_ID__: string;
|
|
40
|
-
|
|
41
|
-
const config = {
|
|
42
|
-
apiKey: typeof __NOWLINE_FIREBASE_API_KEY__ !== 'undefined' ? __NOWLINE_FIREBASE_API_KEY__ : '',
|
|
43
|
-
authDomain:
|
|
44
|
-
typeof __NOWLINE_FIREBASE_AUTH_DOMAIN__ !== 'undefined'
|
|
45
|
-
? __NOWLINE_FIREBASE_AUTH_DOMAIN__
|
|
46
|
-
: '',
|
|
47
|
-
projectId:
|
|
48
|
-
typeof __NOWLINE_FIREBASE_PROJECT_ID__ !== 'undefined'
|
|
49
|
-
? __NOWLINE_FIREBASE_PROJECT_ID__
|
|
50
|
-
: '',
|
|
51
|
-
appId: typeof __NOWLINE_FIREBASE_APP_ID__ !== 'undefined' ? __NOWLINE_FIREBASE_APP_ID__ : '',
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const OVERLAY_ID = 'nowline-embed-dev-auth-overlay';
|
|
55
|
-
|
|
56
|
-
let app: FirebaseApp | null = null;
|
|
57
|
-
let auth: Auth | null = null;
|
|
58
|
-
|
|
59
|
-
function getOrCreateOverlay(): HTMLDivElement {
|
|
60
|
-
let overlay = document.getElementById(OVERLAY_ID) as HTMLDivElement | null;
|
|
61
|
-
if (overlay) return overlay;
|
|
62
|
-
|
|
63
|
-
overlay = document.createElement('div');
|
|
64
|
-
overlay.id = OVERLAY_ID;
|
|
65
|
-
overlay.setAttribute('role', 'dialog');
|
|
66
|
-
overlay.setAttribute('aria-modal', 'true');
|
|
67
|
-
overlay.setAttribute('aria-label', 'Internal preview sign-in');
|
|
68
|
-
overlay.style.cssText = [
|
|
69
|
-
'position: fixed',
|
|
70
|
-
'inset: 0',
|
|
71
|
-
'z-index: 2147483647',
|
|
72
|
-
'background-color: #ffffff',
|
|
73
|
-
'color: #1a1a2e',
|
|
74
|
-
'display: flex',
|
|
75
|
-
'align-items: center',
|
|
76
|
-
'justify-content: center',
|
|
77
|
-
'padding: 1.5rem',
|
|
78
|
-
'font-family: system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
79
|
-
].join(';');
|
|
80
|
-
document.body.appendChild(overlay);
|
|
81
|
-
return overlay;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function removeOverlay(): void {
|
|
85
|
-
const overlay = document.getElementById(OVERLAY_ID);
|
|
86
|
-
overlay?.remove();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function renderSignIn(overlay: HTMLDivElement, onClick: () => void): void {
|
|
90
|
-
overlay.innerHTML = `
|
|
91
|
-
<div style="max-width: 28rem; text-align: center;">
|
|
92
|
-
<div style="font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; color: #5a5a6a; margin-bottom: 0.75rem;">embed.nowline.dev — internal preview</div>
|
|
93
|
-
<h1 style="font-size: 1.875rem; font-weight: 700; margin: 0 0 0.75rem;">Sign in to continue</h1>
|
|
94
|
-
<p style="margin: 0 0 1.5rem; color: #5a5a6a;">Access is limited to allowlisted Lolay accounts. Production embed is at <a href="https://embed.nowline.io" style="color: #1a4ed8;">embed.nowline.io</a>.</p>
|
|
95
|
-
<button type="button" id="nowline-embed-dev-signin-btn" style="display: inline-block; padding: 0.75rem 1.5rem; border-radius: 8px; background-color: #e53e3e; color: #ffffff; font-weight: 700; border: 1px solid transparent; cursor: pointer; font-size: 1rem;">Sign in with Google</button>
|
|
96
|
-
</div>
|
|
97
|
-
`;
|
|
98
|
-
const btn = overlay.querySelector<HTMLButtonElement>('#nowline-embed-dev-signin-btn');
|
|
99
|
-
btn?.addEventListener('click', onClick);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function renderDenied(overlay: HTMLDivElement, email: string, onSignOut: () => void): void {
|
|
103
|
-
overlay.innerHTML = `
|
|
104
|
-
<div style="max-width: 28rem; text-align: center;">
|
|
105
|
-
<div style="font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; color: #5a5a6a; margin-bottom: 0.75rem;">embed.nowline.dev — internal preview</div>
|
|
106
|
-
<h1 style="font-size: 1.875rem; font-weight: 700; margin: 0 0 0.75rem;">Access denied</h1>
|
|
107
|
-
<p style="margin: 0 0 1.5rem; color: #5a5a6a;">${escapeHtml(email)} is not on the allowlist for this preview environment. Production embed is publicly available at <a href="https://embed.nowline.io" style="color: #1a4ed8;">embed.nowline.io</a>.</p>
|
|
108
|
-
<button type="button" id="nowline-embed-dev-signout-btn" style="display: inline-block; padding: 0.75rem 1.5rem; border-radius: 8px; background-color: transparent; color: #1a1a2e; font-weight: 700; border: 1px solid #c0c0c0; cursor: pointer; font-size: 1rem;">Sign out</button>
|
|
109
|
-
</div>
|
|
110
|
-
`;
|
|
111
|
-
const btn = overlay.querySelector<HTMLButtonElement>('#nowline-embed-dev-signout-btn');
|
|
112
|
-
btn?.addEventListener('click', onSignOut);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function escapeHtml(value: string): string {
|
|
116
|
-
return value
|
|
117
|
-
.replace(/&/g, '&')
|
|
118
|
-
.replace(/</g, '<')
|
|
119
|
-
.replace(/>/g, '>')
|
|
120
|
-
.replace(/"/g, '"')
|
|
121
|
-
.replace(/'/g, ''');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function startDevAuthGate(): void {
|
|
125
|
-
if (typeof window === 'undefined' || typeof document === 'undefined') return;
|
|
126
|
-
if (!config.apiKey || !config.authDomain || !config.projectId || !config.appId) {
|
|
127
|
-
// No firebase config baked in. Likely a local `pnpm bundle` without
|
|
128
|
-
// PUBLIC_FIREBASE_* exported (CI deploys always set them). Skip the
|
|
129
|
-
// overlay rather than render an unrecoverable dialog so devs aren't
|
|
130
|
-
// locked out of their own local builds.
|
|
131
|
-
console.warn(
|
|
132
|
-
'[nowline-embed-dev-auth-gate] Missing PUBLIC_FIREBASE_* env vars at build time; gate is disabled. Configure them in .github/workflows/embed-cdn.yml or your local environment to enable.',
|
|
133
|
-
);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Create the overlay up front so it covers content while Firebase
|
|
138
|
-
// initialises; subsequent renders call getOrCreateOverlay() again
|
|
139
|
-
// to find the same element.
|
|
140
|
-
getOrCreateOverlay();
|
|
141
|
-
|
|
142
|
-
app ??= initializeApp(config);
|
|
143
|
-
auth ??= getAuth(app);
|
|
144
|
-
|
|
145
|
-
const provider = new GoogleAuthProvider();
|
|
146
|
-
|
|
147
|
-
const handleSignIn = (): void => {
|
|
148
|
-
void (async () => {
|
|
149
|
-
try {
|
|
150
|
-
await signInWithPopup(auth as Auth, provider);
|
|
151
|
-
} catch (err) {
|
|
152
|
-
console.error('[nowline-embed-dev-auth-gate] Sign-in failed:', err);
|
|
153
|
-
}
|
|
154
|
-
})();
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const handleSignOut = (): void => {
|
|
158
|
-
void (async () => {
|
|
159
|
-
try {
|
|
160
|
-
await signOut(auth as Auth);
|
|
161
|
-
} catch (err) {
|
|
162
|
-
console.error('[nowline-embed-dev-auth-gate] Sign-out failed:', err);
|
|
163
|
-
}
|
|
164
|
-
})();
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
onAuthStateChanged(auth as Auth, (user: User | null) => {
|
|
168
|
-
if (!user) {
|
|
169
|
-
renderSignIn(getOrCreateOverlay(), handleSignIn);
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (!isAllowlisted(user.email)) {
|
|
173
|
-
renderDenied(getOrCreateOverlay(), user.email ?? 'unknown', handleSignOut);
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
removeOverlay();
|
|
177
|
-
});
|
|
178
|
-
}
|