@tern-secure/nextjs 3.0.5 → 3.0.7
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/app-router/client/providers/ternSecureClientProvider.d.ts +1 -1
- package/dist/app-router/server/providers/TernSecureServerProvider.d.ts +1 -1
- package/dist/components/sign-in.d.ts +1 -1
- package/dist/index.cjs.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -342
- package/package.json +17 -12
|
@@ -2,5 +2,5 @@ import React from 'react';
|
|
|
2
2
|
interface TernSecureClientProps {
|
|
3
3
|
children: React.ReactNode;
|
|
4
4
|
}
|
|
5
|
-
export declare function TernSecureClientProvider({ children }: TernSecureClientProps):
|
|
5
|
+
export declare function TernSecureClientProvider({ children }: TernSecureClientProps): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export {};
|
|
@@ -2,5 +2,5 @@ import React, { ReactNode } from 'react';
|
|
|
2
2
|
interface TernSecureProviderProps {
|
|
3
3
|
children: ReactNode;
|
|
4
4
|
}
|
|
5
|
-
export declare function TernSecureProvider({ children }: TernSecureProviderProps):
|
|
5
|
+
export declare function TernSecureProvider({ children }: TernSecureProviderProps): import("react/jsx-runtime").JSX.Element | (string | number | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode>)[] | null | undefined;
|
|
6
6
|
export {};
|
|
@@ -18,4 +18,4 @@ export interface SignInProps {
|
|
|
18
18
|
label?: string;
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
export declare function SignIn({ onSuccess, onError, redirectUrl, className, style, customStyles }: SignInProps):
|
|
21
|
+
export declare function SignIn({ onSuccess, onError, redirectUrl, className, style, customStyles }: SignInProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var ae=Object.create;var P=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var ce=Object.getPrototypeOf,ue=Object.prototype.hasOwnProperty;var M=(e,r)=>()=>(e&&(r=e(e=0)),r);var O=(e,r)=>{for(var t in r)P(e,t,{get:r[t],enumerable:!0})},q=(e,r,t,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of le(r))!ue.call(e,n)&&n!==t&&P(e,n,{get:()=>r[n],enumerable:!(i=se(r,n))||i.enumerable});return e};var H=(e,r,t)=>(t=e!=null?ae(ce(e)):{},q(r||!e||!e.__esModule?P(t,"default",{value:e,enumerable:!0}):t,e)),me=e=>q(P({},"__esModule",{value:!0}),e);var $,fe,d,E,Y,F=M(()=>{"use strict";"use client";$=require("react"),fe=()=>(0,$.createContext)([{firebase:{initialized:!1,error:null},auth:{user:null,loading:!0,error:null,isSignedIn:!1}},()=>{}]),d=fe(),E=e=>{let r=(0,$.useContext)(d);if(!r)throw new Error(`${e} must be used within TernSecureProvider`);return r},Y={firebase:{initialized:!1,error:null},auth:{user:null,loading:!0,error:null,isSignedIn:!1}}});var Q={};O(Q,{TernSecureClientProvider:()=>y});function y({children:e}){let r=(0,Z.useState)(Y);return(0,ee.jsx)(d.Provider,{value:r,children:e})}var Z,ee,B=M(()=>{"use strict";"use client";Z=require("react");F();ee=require("react/jsx-runtime")});var he={};O(he,{SignIn:()=>j,TernSecureAuth:()=>u,TernSecureClientProvider:()=>y,TernSecureContext:()=>d,TernSecureFirestore:()=>_,TernSecureProvider:()=>D,TernSecureStorage:()=>w,loadFireConfig:()=>g,signInWithEmail:()=>h,useAuth:()=>U,useTernSecure:()=>E,validateConfig:()=>S});module.exports=me(he);var f=require("firebase/app"),m=require("firebase/auth"),G=require("firebase/firestore"),K=require("firebase/storage");var N=(()=>{let e=S(g());return(0,f.getApps)().length?(0,f.getApps)()[0]:(0,f.initializeApp)(e)})(),V=(0,m.getAuth)(N);(0,m.setPersistence)(V,m.browserSessionPersistence);var de=(0,G.getFirestore)(N),pe=(0,K.getStorage)(N),u=()=>V,_=()=>de,w=()=>pe;var J=require("firebase/auth");async function h({email:e,password:r}){let t=u();return(0,J.signInWithEmailAndPassword)(t,e,r)}var g=()=>({apiKey:process.env.NEXT_PUBLIC_FIREBASE_API_KEY,authDomain:process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,projectId:process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,storageBucket:process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,messagingSenderId:process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,appId:process.env.NEXT_PUBLIC_FIREBASE_APP_ID,measurementId:process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID}),S=e=>(Object.entries(e).forEach(([r,t])=>{if(!t)throw new Error(`Missing environment variable: NEXT_PUBLIC_FIREBASE_${r.toUpperCase()}`)}),e);F();B();var c=H(require("react"),1),te=H(require("next/dynamic"),1),W=require("react/jsx-runtime"),re=(0,te.default)(()=>Promise.resolve().then(()=>(B(),Q)).then(e=>e.TernSecureClientProvider),{loading:()=>null});function D({children:e}){return c.default.Children.toArray(e).some(t=>c.default.isValidElement(t)&&t.type==="html")?c.default.Children.map(e,t=>c.default.isValidElement(t)&&t.type==="html"?c.default.cloneElement(t,{},c.default.Children.map(t.props.children,i=>{if(c.default.isValidElement(i)&&i.type==="body"){let n=i.props;return c.default.cloneElement(i,{},(0,W.jsx)(re,{children:n.children}))}return i})):t):(0,W.jsx)(re,{children:e})}var ne=require("react");function U(){let[e,r]=E("useAuth");return(0,ne.useEffect)(()=>{try{let t=u();r(n=>({...n,firebase:{initialized:!0,error:null}}));let i=t.onAuthStateChanged(n=>{r(o=>({...o,auth:{user:n,loading:!1,error:null,isSignedIn:!!n}}))},n=>{r(o=>({...o,auth:{user:null,loading:!1,error:n,isSignedIn:!1}}))});return()=>i()}catch(t){r(i=>({...i,firebase:{initialized:!1,error:t},auth:{user:null,loading:!1,error:t,isSignedIn:!1}}))}},[]),e.auth}var C=require("react");var l="tern",L={isInjected:!1,styleElement:null},A={container:`${l}-container`,header:`${l}-header`,title:`${l}-title`,formWrapper:`${l}-formWrapper`,formContainer:`${l}-formContainer`,form:`${l}-form`,label:`${l}-label`,input:`${l}-input`,button:`${l}-button`,error:`${l}-error`};function ge(e){if(typeof window>"u"||L.isInjected)return A;let r=document.querySelector("[data-tern-secure]");r||(r=document.createElement("style"),r.setAttribute("data-tern-secure",""),document.head.appendChild(r),L.styleElement=r);let t=Object.entries(e).map(([i,n])=>{let o=A[i],T=Object.entries(n).map(([R,v])=>`${R.replace(/([A-Z])/g,"-$1").toLowerCase()}: ${v};`).join(" ");return`.${o} { ${T} }`}).join(`
|
|
2
|
+
`);return r.textContent=t,L.isInjected=!0,A}var Se={container:{display:"flex",minHeight:"100%",flex:"1",flexDirection:"column",justifyContent:"center",padding:"3rem 1.5rem"},header:{margin:"0 auto",width:"100%",maxWidth:"28rem"},title:{marginTop:"1.5rem",textAlign:"center",fontSize:"1.875rem",fontWeight:"700",lineHeight:"2.25rem",letterSpacing:"-0.025em",color:"var(--tern-text-primary, #111827)"},formWrapper:{marginTop:"2.5rem",margin:"0 auto",width:"100%",maxWidth:"30rem"},formContainer:{padding:"3rem 1.5rem",boxShadow:"0 1px 3px 0 rgb(0 0 0 / 0.1)",borderRadius:"0.5rem",backgroundColor:"var(--tern-background, white)"},form:{display:"flex",flexDirection:"column",gap:"1rem"},label:{display:"block",fontSize:"0.875rem",fontWeight:"500",color:"var(--tern-text-secondary, #374151)"},input:{marginTop:"0.25rem",display:"block",width:"100%",padding:"0.5rem 0.75rem",borderRadius:"0.375rem",border:"1px solid var(--tern-border, #D1D5DB)",backgroundColor:"var(--tern-input-background, white)",color:"var(--tern-text-primary, #111827)"},button:{display:"flex",width:"100%",justifyContent:"center",padding:"0.5rem 1rem",fontSize:"0.875rem",fontWeight:"500",color:"white",backgroundColor:"var(--tern-primary, #2563EB)",border:"none",borderRadius:"0.375rem",cursor:"pointer"},error:{color:"var(--tern-error, #DC2626)",fontSize:"0.875rem"}},s=ge(Se);var a=require("react/jsx-runtime");function j({onSuccess:e,onError:r,redirectUrl:t,className:i="",style:n,customStyles:o={}}){let[T,R]=(0,C.useState)(""),[v,k]=(0,C.useState)(""),[x,z]=(0,C.useState)(!1),[b,X]=(0,C.useState)(""),oe=async p=>{p.preventDefault(),z(!0),X("");try{await h({email:T,password:v}),e?.(),t&&(window.location.href=t)}catch(I){let ie=I instanceof Error?I.message:"Failed to sign in";X(ie),r?.(I instanceof Error?I:new Error("Failed to sign in"))}finally{z(!1)}};return(0,a.jsxs)("div",{className:`${s.container} ${o.container||""}`,style:n,children:[(0,a.jsx)("div",{className:`${s.header} ${o.header||""}`,children:(0,a.jsx)("h2",{className:`${s.title} ${o.title||""}`,children:"Sign in to your account"})}),(0,a.jsx)("div",{className:`${s.formWrapper} ${o.formWrapper||""}`,children:(0,a.jsx)("div",{className:`${s.formContainer} ${o.formContainer||""}`,children:(0,a.jsxs)("form",{onSubmit:oe,className:`${s.form} ${o.form||""} ${i}`,role:"form","aria-label":"Sign in form",children:[b&&(0,a.jsx)("div",{className:`${s.error} ${o.errorText||""}`,role:"alert","aria-live":"polite",children:b}),(0,a.jsxs)("div",{children:[(0,a.jsx)("label",{htmlFor:"email",className:`${s.label} ${o.label||""}`,children:"Email"}),(0,a.jsx)("input",{id:"email",type:"email",value:T,onChange:p=>R(p.target.value),placeholder:"Enter your email",required:!0,className:`${s.input} ${o.input||""}`,disabled:x,"aria-required":"true","aria-invalid":!!b})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("label",{htmlFor:"password",className:`${s.label} ${o.label||""}`,children:"Password"}),(0,a.jsx)("input",{id:"password",type:"password",value:v,onChange:p=>k(p.target.value),placeholder:"Enter your password",required:!0,className:`${s.input} ${o.input||""}`,disabled:x,"aria-required":"true","aria-invalid":!!b})]}),(0,a.jsx)("button",{type:"submit",disabled:x,className:`${s.button} ${o.button||""}`,"data-testid":"sign-in-submit",children:x?"Signing in...":"Sign in"})]})})})]})}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { TernSecureAuth, TernSecureFirestore, TernSecureStorage, signInWithEmail, loadFireConfig, validateConfig, TernSecureContext, useTernSecure, TernSecureClientProvider
|
|
1
|
+
export { TernSecureAuth, TernSecureFirestore, TernSecureStorage, signInWithEmail, loadFireConfig, validateConfig, TernSecureContext, useTernSecure, TernSecureClientProvider } from './app-router/client';
|
|
2
2
|
export { TernSecureProvider } from './app-router/server';
|
|
3
3
|
export { useAuth } from './hooks';
|
|
4
4
|
export { SignIn } from './components';
|
package/dist/index.js
CHANGED
|
@@ -1,342 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { getFirestore } from 'firebase/firestore';
|
|
4
|
-
import { getStorage } from 'firebase/storage';
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
import React__default, { createContext, useContext, useState, useEffect } from 'react';
|
|
7
|
-
import dynamic from 'next/dynamic';
|
|
8
|
-
|
|
9
|
-
// Initialize immediately
|
|
10
|
-
const app = (() => {
|
|
11
|
-
const config = validateConfig(loadFireConfig());
|
|
12
|
-
return getApps().length ? getApps()[0] : initializeApp(config);
|
|
13
|
-
})();
|
|
14
|
-
const auth = getAuth(app);
|
|
15
|
-
setPersistence(auth, browserSessionPersistence); //to change later user should be able to choose persistance
|
|
16
|
-
const firestore = getFirestore(app);
|
|
17
|
-
const storage = getStorage(app);
|
|
18
|
-
const TernSecureAuth = () => auth;
|
|
19
|
-
const TernSecureFirestore = () => firestore;
|
|
20
|
-
const TernSecureStorage = () => storage;
|
|
21
|
-
|
|
22
|
-
async function signInWithEmail({ email, password }) {
|
|
23
|
-
const auth = TernSecureAuth();
|
|
24
|
-
return signInWithEmailAndPassword(auth, email, password);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const loadFireConfig = () => ({
|
|
28
|
-
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
|
29
|
-
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
|
30
|
-
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
|
31
|
-
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
|
32
|
-
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
|
33
|
-
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
|
|
34
|
-
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
|
|
35
|
-
});
|
|
36
|
-
const validateConfig = (config) => {
|
|
37
|
-
Object.entries(config).forEach(([key, value]) => {
|
|
38
|
-
if (!value) {
|
|
39
|
-
throw new Error(`Missing environment variable: NEXT_PUBLIC_FIREBASE_${key.toUpperCase()}`);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
return config;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const createTernSecureContext = () => {
|
|
46
|
-
const initialState = {
|
|
47
|
-
firebase: {
|
|
48
|
-
initialized: false,
|
|
49
|
-
error: null
|
|
50
|
-
},
|
|
51
|
-
auth: {
|
|
52
|
-
user: null,
|
|
53
|
-
loading: true,
|
|
54
|
-
error: null,
|
|
55
|
-
isSignedIn: false
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
return createContext([initialState, () => { }]);
|
|
59
|
-
};
|
|
60
|
-
// Create context instance only when imported on client
|
|
61
|
-
const TernSecureContext = createTernSecureContext();
|
|
62
|
-
const useTernSecure = (hookname) => {
|
|
63
|
-
const context = useContext(TernSecureContext);
|
|
64
|
-
if (!context) {
|
|
65
|
-
throw new Error(`${hookname} must be used within TernSecureProvider`);
|
|
66
|
-
}
|
|
67
|
-
return context;
|
|
68
|
-
};
|
|
69
|
-
// Export initial state for reuse
|
|
70
|
-
const initialState = {
|
|
71
|
-
firebase: {
|
|
72
|
-
initialized: false,
|
|
73
|
-
error: null
|
|
74
|
-
},
|
|
75
|
-
auth: {
|
|
76
|
-
user: null,
|
|
77
|
-
loading: true,
|
|
78
|
-
error: null,
|
|
79
|
-
isSignedIn: false
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
function TernSecureClientProvider$1({ children }) {
|
|
84
|
-
const stateAndUpdater = useState(initialState);
|
|
85
|
-
return (React__default.createElement(TernSecureContext.Provider, { value: stateAndUpdater }, children));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
var ternSecureClientProvider = /*#__PURE__*/Object.freeze({
|
|
89
|
-
__proto__: null,
|
|
90
|
-
TernSecureClientProvider: TernSecureClientProvider$1
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Dynamically import the client provider with no SSR
|
|
94
|
-
const TernSecureClientProvider = dynamic(() => Promise.resolve().then(function () { return ternSecureClientProvider; }).then(mod => mod.TernSecureClientProvider), {
|
|
95
|
-
//ssr: false,
|
|
96
|
-
loading: () => null // Return null or a loading indicator
|
|
97
|
-
});
|
|
98
|
-
function TernSecureProvider({ children }) {
|
|
99
|
-
// Check if the children contain html/body tags
|
|
100
|
-
const isRootLayout = React__default.Children.toArray(children).some(child => React__default.isValidElement(child) && child.type === 'html');
|
|
101
|
-
if (isRootLayout) {
|
|
102
|
-
// If this is the root layout, inject our provider after the body tag
|
|
103
|
-
return React__default.Children.map(children, child => {
|
|
104
|
-
if (React__default.isValidElement(child) && child.type === 'html') {
|
|
105
|
-
return React__default.cloneElement(child, {}, React__default.Children.map(child.props.children, bodyChild => {
|
|
106
|
-
if (React__default.isValidElement(bodyChild) && bodyChild.type === 'body') {
|
|
107
|
-
// Type assertion to access props safely
|
|
108
|
-
const bodyProps = bodyChild.props;
|
|
109
|
-
return React__default.cloneElement(bodyChild, {}, React__default.createElement(TernSecureClientProvider, null, bodyProps.children));
|
|
110
|
-
}
|
|
111
|
-
return bodyChild;
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
|
-
return child;
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
// For non-root layouts, wrap normally
|
|
118
|
-
return React__default.createElement(TernSecureClientProvider, null, children);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function useAuth() {
|
|
122
|
-
const [state, setState] = useTernSecure('useAuth');
|
|
123
|
-
useEffect(() => {
|
|
124
|
-
try {
|
|
125
|
-
const auth = TernSecureAuth(); // This initializes Firebase
|
|
126
|
-
setState(prev => ({
|
|
127
|
-
...prev,
|
|
128
|
-
firebase: {
|
|
129
|
-
initialized: true,
|
|
130
|
-
error: null
|
|
131
|
-
}
|
|
132
|
-
}));
|
|
133
|
-
const unsubscribe = auth.onAuthStateChanged((user) => {
|
|
134
|
-
setState(prev => ({
|
|
135
|
-
...prev,
|
|
136
|
-
auth: {
|
|
137
|
-
user,
|
|
138
|
-
loading: false,
|
|
139
|
-
error: null,
|
|
140
|
-
isSignedIn: !!user
|
|
141
|
-
}
|
|
142
|
-
}));
|
|
143
|
-
}, (error) => {
|
|
144
|
-
setState(prev => ({
|
|
145
|
-
...prev,
|
|
146
|
-
auth: {
|
|
147
|
-
user: null,
|
|
148
|
-
loading: false,
|
|
149
|
-
error,
|
|
150
|
-
isSignedIn: false
|
|
151
|
-
}
|
|
152
|
-
}));
|
|
153
|
-
});
|
|
154
|
-
return () => unsubscribe();
|
|
155
|
-
}
|
|
156
|
-
catch (error) {
|
|
157
|
-
setState(prev => ({
|
|
158
|
-
...prev,
|
|
159
|
-
firebase: {
|
|
160
|
-
initialized: false,
|
|
161
|
-
error: error
|
|
162
|
-
},
|
|
163
|
-
auth: {
|
|
164
|
-
user: null,
|
|
165
|
-
loading: false,
|
|
166
|
-
error: error,
|
|
167
|
-
isSignedIn: false
|
|
168
|
-
}
|
|
169
|
-
}));
|
|
170
|
-
}
|
|
171
|
-
}, []); // Only run once on mount
|
|
172
|
-
return state.auth;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const PREFIX = 'tern';
|
|
176
|
-
// Singleton to track style injection
|
|
177
|
-
const styleInjection = {
|
|
178
|
-
isInjected: false,
|
|
179
|
-
styleElement: null
|
|
180
|
-
};
|
|
181
|
-
const defaultClassNames = {
|
|
182
|
-
container: `${PREFIX}-container`,
|
|
183
|
-
header: `${PREFIX}-header`,
|
|
184
|
-
title: `${PREFIX}-title`,
|
|
185
|
-
formWrapper: `${PREFIX}-formWrapper`,
|
|
186
|
-
formContainer: `${PREFIX}-formContainer`,
|
|
187
|
-
form: `${PREFIX}-form`,
|
|
188
|
-
label: `${PREFIX}-label`,
|
|
189
|
-
input: `${PREFIX}-input`,
|
|
190
|
-
button: `${PREFIX}-button`,
|
|
191
|
-
error: `${PREFIX}-error`
|
|
192
|
-
};
|
|
193
|
-
// Create styles once and cache them
|
|
194
|
-
function createStyleSheet(styles) {
|
|
195
|
-
if (typeof window === 'undefined')
|
|
196
|
-
return defaultClassNames;
|
|
197
|
-
// Return early if styles are already injected
|
|
198
|
-
if (styleInjection.isInjected) {
|
|
199
|
-
return defaultClassNames;
|
|
200
|
-
}
|
|
201
|
-
// Find existing style element or create new one
|
|
202
|
-
let styleElement = document.querySelector('[data-tern-secure]');
|
|
203
|
-
if (!styleElement) {
|
|
204
|
-
styleElement = document.createElement('style');
|
|
205
|
-
styleElement.setAttribute('data-tern-secure', '');
|
|
206
|
-
document.head.appendChild(styleElement);
|
|
207
|
-
styleInjection.styleElement = styleElement;
|
|
208
|
-
}
|
|
209
|
-
// Create CSS rules
|
|
210
|
-
const cssRules = Object.entries(styles).map(([key, rules]) => {
|
|
211
|
-
const className = defaultClassNames[key];
|
|
212
|
-
const cssProperties = Object.entries(rules).map(([prop, value]) => {
|
|
213
|
-
const cssProperty = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
214
|
-
return `${cssProperty}: ${value};`;
|
|
215
|
-
}).join(' ');
|
|
216
|
-
return `.${className} { ${cssProperties} }`;
|
|
217
|
-
}).join('\n');
|
|
218
|
-
// Insert styles only once
|
|
219
|
-
styleElement.textContent = cssRules;
|
|
220
|
-
styleInjection.isInjected = true;
|
|
221
|
-
return defaultClassNames;
|
|
222
|
-
}
|
|
223
|
-
// Style configuration
|
|
224
|
-
const styleConfig = {
|
|
225
|
-
container: {
|
|
226
|
-
display: 'flex',
|
|
227
|
-
minHeight: '100%',
|
|
228
|
-
flex: '1',
|
|
229
|
-
flexDirection: 'column',
|
|
230
|
-
justifyContent: 'center',
|
|
231
|
-
padding: '3rem 1.5rem'
|
|
232
|
-
},
|
|
233
|
-
header: {
|
|
234
|
-
margin: '0 auto',
|
|
235
|
-
width: '100%',
|
|
236
|
-
maxWidth: '28rem'
|
|
237
|
-
},
|
|
238
|
-
title: {
|
|
239
|
-
marginTop: '1.5rem',
|
|
240
|
-
textAlign: 'center',
|
|
241
|
-
fontSize: '1.875rem',
|
|
242
|
-
fontWeight: '700',
|
|
243
|
-
lineHeight: '2.25rem',
|
|
244
|
-
letterSpacing: '-0.025em',
|
|
245
|
-
color: 'var(--tern-text-primary, #111827)'
|
|
246
|
-
},
|
|
247
|
-
formWrapper: {
|
|
248
|
-
marginTop: '2.5rem',
|
|
249
|
-
margin: '0 auto',
|
|
250
|
-
width: '100%',
|
|
251
|
-
maxWidth: '30rem'
|
|
252
|
-
},
|
|
253
|
-
formContainer: {
|
|
254
|
-
padding: '3rem 1.5rem',
|
|
255
|
-
boxShadow: '0 1px 3px 0 rgb(0 0 0 / 0.1)',
|
|
256
|
-
borderRadius: '0.5rem',
|
|
257
|
-
backgroundColor: 'var(--tern-background, white)'
|
|
258
|
-
},
|
|
259
|
-
form: {
|
|
260
|
-
display: 'flex',
|
|
261
|
-
flexDirection: 'column',
|
|
262
|
-
gap: '1rem'
|
|
263
|
-
},
|
|
264
|
-
label: {
|
|
265
|
-
display: 'block',
|
|
266
|
-
fontSize: '0.875rem',
|
|
267
|
-
fontWeight: '500',
|
|
268
|
-
color: 'var(--tern-text-secondary, #374151)'
|
|
269
|
-
},
|
|
270
|
-
input: {
|
|
271
|
-
marginTop: '0.25rem',
|
|
272
|
-
display: 'block',
|
|
273
|
-
width: '100%',
|
|
274
|
-
padding: '0.5rem 0.75rem',
|
|
275
|
-
borderRadius: '0.375rem',
|
|
276
|
-
border: '1px solid var(--tern-border, #D1D5DB)',
|
|
277
|
-
backgroundColor: 'var(--tern-input-background, white)',
|
|
278
|
-
color: 'var(--tern-text-primary, #111827)'
|
|
279
|
-
},
|
|
280
|
-
button: {
|
|
281
|
-
display: 'flex',
|
|
282
|
-
width: '100%',
|
|
283
|
-
justifyContent: 'center',
|
|
284
|
-
padding: '0.5rem 1rem',
|
|
285
|
-
fontSize: '0.875rem',
|
|
286
|
-
fontWeight: '500',
|
|
287
|
-
color: 'white',
|
|
288
|
-
backgroundColor: 'var(--tern-primary, #2563EB)',
|
|
289
|
-
border: 'none',
|
|
290
|
-
borderRadius: '0.375rem',
|
|
291
|
-
cursor: 'pointer'
|
|
292
|
-
},
|
|
293
|
-
error: {
|
|
294
|
-
color: 'var(--tern-error, #DC2626)',
|
|
295
|
-
fontSize: '0.875rem'
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
// Export pre-created styles
|
|
299
|
-
const styles = createStyleSheet(styleConfig);
|
|
300
|
-
|
|
301
|
-
function SignIn({ onSuccess, onError, redirectUrl, className = '', style, customStyles = {} }) {
|
|
302
|
-
const [email, setEmail] = useState('');
|
|
303
|
-
const [password, setPassword] = useState('');
|
|
304
|
-
const [loading, setLoading] = useState(false);
|
|
305
|
-
const [error, setError] = useState('');
|
|
306
|
-
const handleSubmit = async (e) => {
|
|
307
|
-
e.preventDefault();
|
|
308
|
-
setLoading(true);
|
|
309
|
-
setError('');
|
|
310
|
-
try {
|
|
311
|
-
await signInWithEmail({ email, password });
|
|
312
|
-
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess();
|
|
313
|
-
if (redirectUrl) {
|
|
314
|
-
window.location.href = redirectUrl;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
catch (err) {
|
|
318
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to sign in';
|
|
319
|
-
setError(errorMessage);
|
|
320
|
-
onError === null || onError === void 0 ? void 0 : onError(err instanceof Error ? err : new Error('Failed to sign in'));
|
|
321
|
-
}
|
|
322
|
-
finally {
|
|
323
|
-
setLoading(false);
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
return (React.createElement("div", { className: `${styles.container} ${customStyles.container || ''}`, style: style },
|
|
327
|
-
React.createElement("div", { className: `${styles.header} ${customStyles.header || ''}` },
|
|
328
|
-
React.createElement("h2", { className: `${styles.title} ${customStyles.title || ''}` }, "Sign in to your account")),
|
|
329
|
-
React.createElement("div", { className: `${styles.formWrapper} ${customStyles.formWrapper || ''}` },
|
|
330
|
-
React.createElement("div", { className: `${styles.formContainer} ${customStyles.formContainer || ''}` },
|
|
331
|
-
React.createElement("form", { onSubmit: handleSubmit, className: `${styles.form} ${customStyles.form || ''} ${className}`, role: "form", "aria-label": "Sign in form" },
|
|
332
|
-
error && (React.createElement("div", { className: `${styles.error} ${customStyles.errorText || ''}`, role: "alert", "aria-live": "polite" }, error)),
|
|
333
|
-
React.createElement("div", null,
|
|
334
|
-
React.createElement("label", { htmlFor: "email", className: `${styles.label} ${customStyles.label || ''}` }, "Email"),
|
|
335
|
-
React.createElement("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), placeholder: "Enter your email", required: true, className: `${styles.input} ${customStyles.input || ''}`, disabled: loading, "aria-required": "true", "aria-invalid": !!error })),
|
|
336
|
-
React.createElement("div", null,
|
|
337
|
-
React.createElement("label", { htmlFor: "password", className: `${styles.label} ${customStyles.label || ''}` }, "Password"),
|
|
338
|
-
React.createElement("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), placeholder: "Enter your password", required: true, className: `${styles.input} ${customStyles.input || ''}`, disabled: loading, "aria-required": "true", "aria-invalid": !!error })),
|
|
339
|
-
React.createElement("button", { type: "submit", disabled: loading, className: `${styles.button} ${customStyles.button || ''}`, "data-testid": "sign-in-submit" }, loading ? 'Signing in...' : 'Sign in'))))));
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export { SignIn, TernSecureAuth, TernSecureClientProvider$1 as TernSecureClientProvider, TernSecureContext, TernSecureFirestore, TernSecureProvider, TernSecureStorage, loadFireConfig, signInWithEmail, useAuth, useTernSecure, validateConfig };
|
|
1
|
+
var K=Object.defineProperty;var B=(e,r)=>()=>(e&&(r=e(e=0)),r);var V=(e,r)=>{for(var t in r)K(e,t,{get:r[t],enumerable:!0})};import{createContext as ie,useContext as ae}from"react";var se,d,v,j,y=B(()=>{"use strict";"use client";se=()=>ie([{firebase:{initialized:!1,error:null},auth:{user:null,loading:!0,error:null,isSignedIn:!1}},()=>{}]),d=se(),v=e=>{let r=ae(d);if(!r)throw new Error(`${e} must be used within TernSecureProvider`);return r},j={firebase:{initialized:!1,error:null},auth:{user:null,loading:!0,error:null,isSignedIn:!1}}});var k={};V(k,{TernSecureClientProvider:()=>A});import{useState as le}from"react";import{jsx as ce}from"react/jsx-runtime";function A({children:e}){let r=le(j);return ce(d.Provider,{value:r,children:e})}var R=B(()=>{"use strict";"use client";y()});import{getApps as W,initializeApp as J}from"firebase/app";import{getAuth as Y,setPersistence as Z,browserSessionPersistence as Q}from"firebase/auth";import{getFirestore as ee}from"firebase/firestore";import{getStorage as re}from"firebase/storage";var $=(()=>{let e=C(E());return W().length?W()[0]:J(e)})(),D=Y($);Z(D,Q);var te=ee($),ne=re($),u=()=>D,U=()=>te,L=()=>ne;import{signInWithEmailAndPassword as oe}from"firebase/auth";async function T({email:e,password:r}){let t=u();return oe(t,e,r)}var E=()=>({apiKey:process.env.NEXT_PUBLIC_FIREBASE_API_KEY,authDomain:process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,projectId:process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,storageBucket:process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,messagingSenderId:process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,appId:process.env.NEXT_PUBLIC_FIREBASE_APP_ID,measurementId:process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID}),C=e=>(Object.entries(e).forEach(([r,t])=>{if(!t)throw new Error(`Missing environment variable: NEXT_PUBLIC_FIREBASE_${r.toUpperCase()}`)}),e);y();R();import c from"react";import ue from"next/dynamic";import{jsx as X}from"react/jsx-runtime";var z=ue(()=>Promise.resolve().then(()=>(R(),k)).then(e=>e.TernSecureClientProvider),{loading:()=>null});function M({children:e}){return c.Children.toArray(e).some(t=>c.isValidElement(t)&&t.type==="html")?c.Children.map(e,t=>c.isValidElement(t)&&t.type==="html"?c.cloneElement(t,{},c.Children.map(t.props.children,o=>{if(c.isValidElement(o)&&o.type==="body"){let a=o.props;return c.cloneElement(o,{},X(z,{children:a.children}))}return o})):t):X(z,{children:e})}import{useEffect as me}from"react";function O(){let[e,r]=v("useAuth");return me(()=>{try{let t=u();r(a=>({...a,firebase:{initialized:!0,error:null}}));let o=t.onAuthStateChanged(a=>{r(n=>({...n,auth:{user:a,loading:!1,error:null,isSignedIn:!!a}}))},a=>{r(n=>({...n,auth:{user:null,loading:!1,error:a,isSignedIn:!1}}))});return()=>o()}catch(t){r(o=>({...o,firebase:{initialized:!1,error:t},auth:{user:null,loading:!1,error:t,isSignedIn:!1}}))}},[]),e.auth}import{useState as b}from"react";var s="tern",N={isInjected:!1,styleElement:null},x={container:`${s}-container`,header:`${s}-header`,title:`${s}-title`,formWrapper:`${s}-formWrapper`,formContainer:`${s}-formContainer`,form:`${s}-form`,label:`${s}-label`,input:`${s}-input`,button:`${s}-button`,error:`${s}-error`};function de(e){if(typeof window>"u"||N.isInjected)return x;let r=document.querySelector("[data-tern-secure]");r||(r=document.createElement("style"),r.setAttribute("data-tern-secure",""),document.head.appendChild(r),N.styleElement=r);let t=Object.entries(e).map(([o,a])=>{let n=x[o],p=Object.entries(a).map(([P,f])=>`${P.replace(/([A-Z])/g,"-$1").toLowerCase()}: ${f};`).join(" ");return`.${n} { ${p} }`}).join(`
|
|
2
|
+
`);return r.textContent=t,N.isInjected=!0,x}var pe={container:{display:"flex",minHeight:"100%",flex:"1",flexDirection:"column",justifyContent:"center",padding:"3rem 1.5rem"},header:{margin:"0 auto",width:"100%",maxWidth:"28rem"},title:{marginTop:"1.5rem",textAlign:"center",fontSize:"1.875rem",fontWeight:"700",lineHeight:"2.25rem",letterSpacing:"-0.025em",color:"var(--tern-text-primary, #111827)"},formWrapper:{marginTop:"2.5rem",margin:"0 auto",width:"100%",maxWidth:"30rem"},formContainer:{padding:"3rem 1.5rem",boxShadow:"0 1px 3px 0 rgb(0 0 0 / 0.1)",borderRadius:"0.5rem",backgroundColor:"var(--tern-background, white)"},form:{display:"flex",flexDirection:"column",gap:"1rem"},label:{display:"block",fontSize:"0.875rem",fontWeight:"500",color:"var(--tern-text-secondary, #374151)"},input:{marginTop:"0.25rem",display:"block",width:"100%",padding:"0.5rem 0.75rem",borderRadius:"0.375rem",border:"1px solid var(--tern-border, #D1D5DB)",backgroundColor:"var(--tern-input-background, white)",color:"var(--tern-text-primary, #111827)"},button:{display:"flex",width:"100%",justifyContent:"center",padding:"0.5rem 1rem",fontSize:"0.875rem",fontWeight:"500",color:"white",backgroundColor:"var(--tern-primary, #2563EB)",border:"none",borderRadius:"0.375rem",cursor:"pointer"},error:{color:"var(--tern-error, #DC2626)",fontSize:"0.875rem"}},i=de(pe);import{jsx as l,jsxs as I}from"react/jsx-runtime";function q({onSuccess:e,onError:r,redirectUrl:t,className:o="",style:a,customStyles:n={}}){let[p,P]=b(""),[f,_]=b(""),[g,w]=b(!1),[S,F]=b(""),H=async m=>{m.preventDefault(),w(!0),F("");try{await T({email:p,password:f}),e?.(),t&&(window.location.href=t)}catch(h){let G=h instanceof Error?h.message:"Failed to sign in";F(G),r?.(h instanceof Error?h:new Error("Failed to sign in"))}finally{w(!1)}};return I("div",{className:`${i.container} ${n.container||""}`,style:a,children:[l("div",{className:`${i.header} ${n.header||""}`,children:l("h2",{className:`${i.title} ${n.title||""}`,children:"Sign in to your account"})}),l("div",{className:`${i.formWrapper} ${n.formWrapper||""}`,children:l("div",{className:`${i.formContainer} ${n.formContainer||""}`,children:I("form",{onSubmit:H,className:`${i.form} ${n.form||""} ${o}`,role:"form","aria-label":"Sign in form",children:[S&&l("div",{className:`${i.error} ${n.errorText||""}`,role:"alert","aria-live":"polite",children:S}),I("div",{children:[l("label",{htmlFor:"email",className:`${i.label} ${n.label||""}`,children:"Email"}),l("input",{id:"email",type:"email",value:p,onChange:m=>P(m.target.value),placeholder:"Enter your email",required:!0,className:`${i.input} ${n.input||""}`,disabled:g,"aria-required":"true","aria-invalid":!!S})]}),I("div",{children:[l("label",{htmlFor:"password",className:`${i.label} ${n.label||""}`,children:"Password"}),l("input",{id:"password",type:"password",value:f,onChange:m=>_(m.target.value),placeholder:"Enter your password",required:!0,className:`${i.input} ${n.input||""}`,disabled:g,"aria-required":"true","aria-invalid":!!S})]}),l("button",{type:"submit",disabled:g,className:`${i.button} ${n.button||""}`,"data-testid":"sign-in-submit",children:g?"Signing in...":"Sign in"})]})})})]})}export{q as SignIn,u as TernSecureAuth,A as TernSecureClientProvider,d as TernSecureContext,U as TernSecureFirestore,M as TernSecureProvider,L as TernSecureStorage,E as loadFireConfig,T as signInWithEmail,O as useAuth,v as useTernSecure,C as validateConfig};
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tern-secure/nextjs",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.7",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"publishConfig": {
|
|
5
6
|
"access": "public",
|
|
6
7
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -13,14 +14,17 @@
|
|
|
13
14
|
"url": "https://github.com/TernSecure/nextjs/issues"
|
|
14
15
|
},
|
|
15
16
|
"homepage": "https://github.com/tern-secure/nextjs#readme",
|
|
16
|
-
"main": "./dist/index.js",
|
|
17
|
+
"main": "./dist/index.cjs.js",
|
|
17
18
|
"module": "./dist/index.js",
|
|
18
|
-
|
|
19
|
-
"build": "
|
|
20
|
-
|
|
21
|
-
"
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "npm run build:types && npm run build:js",
|
|
21
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
22
|
+
"build:js": "node build.config.cjs",
|
|
23
|
+
"clean": "rimraf dist",
|
|
24
|
+
"dev": "npm run build -- --watch",
|
|
22
25
|
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
23
|
-
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
26
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
24
28
|
},
|
|
25
29
|
"keywords": [],
|
|
26
30
|
"author": "",
|
|
@@ -42,6 +46,8 @@
|
|
|
42
46
|
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
|
43
47
|
"@typescript-eslint/parser": "^8.15.0",
|
|
44
48
|
"autoprefixer": "^10.4.20",
|
|
49
|
+
"esbuild": "^0.24.0",
|
|
50
|
+
"esbuild-node-externals": "^1.15.0",
|
|
45
51
|
"eslint": "^9.15.0",
|
|
46
52
|
"eslint-plugin-react": "^7.37.2",
|
|
47
53
|
"firebase": "^11.0.2",
|
|
@@ -86,17 +92,16 @@
|
|
|
86
92
|
"optional": true
|
|
87
93
|
}
|
|
88
94
|
},
|
|
89
|
-
|
|
95
|
+
"exports": {
|
|
90
96
|
".": {
|
|
91
97
|
"types": "./dist/index.d.ts",
|
|
92
98
|
"import": "./dist/index.js",
|
|
93
|
-
"require": "./dist/index.js"
|
|
99
|
+
"require": "./dist/index.cjs.js"
|
|
94
100
|
},
|
|
95
101
|
"./server": {
|
|
96
102
|
"types": "./dist/server/index.d.ts",
|
|
97
103
|
"import": "./dist/server/index.js",
|
|
98
|
-
"require": "./dist/server/index.js"
|
|
99
|
-
}
|
|
100
|
-
"./styles": "./styles/index.css"
|
|
104
|
+
"require": "./dist/server/index.cjs.js"
|
|
105
|
+
}
|
|
101
106
|
}
|
|
102
107
|
}
|