firebase-login-custom 0.4.0 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.1](https://github.com/vergissberlin/firebase-login-custom/compare/v0.5.0...v0.5.1) (2026-03-17)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * update CI workflow to remove conditional check for FIREBASE_ID in integration tests ([58f0f02](https://github.com/vergissberlin/firebase-login-custom/commit/58f0f02655972025357492eb1ef2d5cfa19a5186))
9
+
10
+ ## [0.5.0](https://github.com/vergissberlin/firebase-login-custom/compare/v0.4.0...v0.5.0) (2026-03-17)
11
+
12
+
13
+ ### Features
14
+
15
+ * add promise-based API for firebaseLoginCustom and enhance documentation ([3cce996](https://github.com/vergissberlin/firebase-login-custom/commit/3cce9964d6852a0d5096d8c94e34c97946b9903c))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * correct typos in package.json and README.md, and update tsconfig.json include paths ([a12b223](https://github.com/vergissberlin/firebase-login-custom/commit/a12b223a6e33f72798e1c59b290c5cd31399c7ba))
21
+
3
22
  ## [0.4.0](https://github.com/vergissberlin/firebase-login-custom/compare/v0.3.0...v0.4.0) (2026-03-17)
4
23
 
5
24
 
package/README.md CHANGED
@@ -12,8 +12,10 @@ We provide several helper libraries for generating JWTs.
12
12
  Use a Firebase Secret to generate these tokens. Firebase Secrets can be found by logging into the
13
13
  Firebase account and clicking on the Security tab in the Firebase Dashboard.
14
14
 
15
+ **Security:** Never commit your Firebase secret or put it in frontend code. Load it from environment variables or a secure config (e.g. `process.env.FIREBASE_SECRET`) on the server only.
16
+
15
17
  This package is a wrapper to Firebase custom login including all dependencies
16
- with the exception of firebase it self.
18
+ with the exception of firebase itself.
17
19
 
18
20
  More information can be found in the [Firebase custom login documentation](https://www.firebase.com/docs/web/guide/login/custom.html).
19
21
 
@@ -51,11 +53,21 @@ FirebaseLoginCustom(firebaseRef, {
51
53
  );
52
54
  ```
53
55
 
56
+ ### Promise-based API
57
+
58
+ For async/await code, use `firebaseLoginCustomAsync` (same options and behaviour, returns a Promise):
59
+
60
+ ```javascript
61
+ const { firebaseLoginCustomAsync } = require('firebase-login-custom');
62
+
63
+ const { authData } = await firebaseLoginCustomAsync(firebaseRef, { uid: 'user-1' }, { secret: process.env.FIREBASE_SECRET });
64
+ ```
65
+
54
66
  ### Error handling
55
67
 
56
- - **Validation errors** (invalid `ref`, `data`, `option`, or `callback`): the constructor throws `FirebaseLoginCustomValidationError` (or the callable form throws it). You can check `error.code === 'FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR'` or `error instanceof FirebaseLoginCustomValidationError`.
57
- - **Token generation errors**: if token creation fails, the **callback** is invoked with a `FirebaseLoginCustomTokenError` (once, asynchronously). It has a `cause` property with the original thrown value.
58
- - **Auth errors** (from Firebase): the callback receives a user-facing string for known codes (`INVALID_EMAIL`, `INVALID_PASSWORD`, `INVALID_USER`) or a generic message including the original error for other failures.
68
+ - **Validation errors** (invalid `ref`, `data`, `option`, or `callback`): the constructor throws `FirebaseLoginCustomValidationError` (or the callable form throws it). With `firebaseLoginCustomAsync`, the Promise rejects. You can check `error.code === 'FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR'` or `error instanceof FirebaseLoginCustomValidationError`.
69
+ - **Token generation errors**: if token creation fails, the **callback** is invoked with a `FirebaseLoginCustomTokenError` (once, asynchronously). With `firebaseLoginCustomAsync`, the Promise rejects with the same error. It has a `cause` property with the original thrown value.
70
+ - **Auth errors** (from Firebase): the callback receives a user-facing string for known codes (`INVALID_EMAIL`, `INVALID_PASSWORD`, `INVALID_USER`) or a generic message including the original error for other failures. With `firebaseLoginCustomAsync`, the Promise rejects with that string.
59
71
 
60
72
  ## Issues
61
73
 
@@ -0,0 +1 @@
1
+ export {};
@@ -78,4 +78,12 @@ export declare class FirebaseLoginCustom {
78
78
  * Callable form: same as `new FirebaseLoginCustom(...)`. Use without `new` for backward compatibility.
79
79
  */
80
80
  declare function firebaseLoginCustom(ref: FirebaseRef, data?: AuthData, option?: FirebaseLoginOptionInput, callback?: FirebaseLoginCallback): void;
81
+ /**
82
+ * Promise-based API: same as `firebaseLoginCustom` but returns a Promise.
83
+ * Resolves with `{ authData }` on success, rejects with the same error type as the callback
84
+ * (string or `FirebaseLoginCustomTokenError` / auth error message).
85
+ */
86
+ export declare function firebaseLoginCustomAsync(ref: FirebaseRef, data?: AuthData, option?: FirebaseLoginOptionInput): Promise<{
87
+ authData: unknown;
88
+ }>;
81
89
  export default firebaseLoginCustom;
@@ -1,3 +1,3 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`firebase-token-generator`);c=s(c);var l=`FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR`,u=`FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR`,d=class e extends Error{constructor(t){super(t),this.code=l,this.name=`FirebaseLoginCustomValidationError`,Object.setPrototypeOf(this,e.prototype)}},f=class e extends Error{constructor(t,n){super(t),this.code=u,this.name=`FirebaseLoginCustomTokenError`,this.cause=n,Object.setPrototypeOf(this,e.prototype)}},p={admin:!1,debug:!1,expires:0,notBefore:0},m=86400,h={INVALID_EMAIL:`The specified user account email is invalid.`,INVALID_PASSWORD:`The specified user account password is incorrect.`,INVALID_USER:`The specified user account does not exist.`};function g(e){let t=Date.now()/1e3;return{admin:typeof e.admin==`boolean`?e.admin:p.admin,debug:typeof e.debug==`boolean`?e.debug:p.debug,expires:typeof e.expires==`number`?e.expires:t+m,notBefore:typeof e.notBefore==`number`?e.notBefore:t,secret:e.secret}}var _=class{constructor(e,t={uid:``},n={...p},r=()=>{}){if(typeof e!=`object`||!e)throw new d(`Ref must be an object!`);if(typeof t.uid!=`string`)throw new d(`Data object must have a "uid" field!`);if(typeof n.secret!=`string`)throw new d(`Option object must have a "secret" field!`);if(typeof r!=`function`)throw new d(`Callback must be a function!`);let i=g(n),a;try{a=new c.default(i.secret).createToken(t,{admin:i.admin,debug:i.debug,expires:i.expires,notBefore:i.notBefore})}catch(e){let t=e instanceof Error?new f(`Token generation failed: `+e.message,e):new f(`Token generation failed: `+String(e),e);process.nextTick(()=>r(t,void 0));return}e.authWithCustomToken(a,(e,t)=>{let n=null;if(e){let t=e,r=t?.code===void 0?void 0:h[t.code];n=r===void 0?`Error logging user in: `+String(e):r}r(n,t)})}};function v(e,t,n,r){new _(e,t??{uid:``},n??{...p},r??(()=>{}))}exports.FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR=u,exports.FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR=l,exports.FirebaseLoginCustom=_,exports.FirebaseLoginCustomTokenError=f,exports.FirebaseLoginCustomValidationError=d,exports.default=v;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`firebase-token-generator`);c=s(c);var l=`FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR`,u=`FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR`,d=class e extends Error{constructor(t){super(t),this.code=l,this.name=`FirebaseLoginCustomValidationError`,Object.setPrototypeOf(this,e.prototype)}},f=class e extends Error{constructor(t,n){super(t),this.code=u,this.name=`FirebaseLoginCustomTokenError`,this.cause=n,Object.setPrototypeOf(this,e.prototype)}},p={admin:!1,debug:!1,expires:0,notBefore:0},m=86400,h={INVALID_EMAIL:`The specified user account email is invalid.`,INVALID_PASSWORD:`The specified user account password is incorrect.`,INVALID_USER:`The specified user account does not exist.`};function g(e){let t=Date.now()/1e3;return{admin:typeof e.admin==`boolean`?e.admin:p.admin,debug:typeof e.debug==`boolean`?e.debug:p.debug,expires:typeof e.expires==`number`?e.expires:t+m,notBefore:typeof e.notBefore==`number`?e.notBefore:t,secret:e.secret}}var _=class{constructor(e,t={uid:``},n={...p},r=()=>{}){if(typeof e!=`object`||!e)throw new d(`Ref must be an object!`);if(typeof t.uid!=`string`)throw new d(`Data object must have a "uid" field!`);if(typeof n.secret!=`string`)throw new d(`Option object must have a "secret" field!`);if(typeof r!=`function`)throw new d(`Callback must be a function!`);let i=g(n),a;try{a=new c.default(i.secret).createToken(t,{admin:i.admin,debug:i.debug,expires:i.expires,notBefore:i.notBefore})}catch(e){let t=e instanceof Error?new f(`Token generation failed: `+e.message,e):new f(`Token generation failed: `+String(e),e);process.nextTick(()=>r(t,void 0));return}e.authWithCustomToken(a,(e,t)=>{let n=null;if(e){let t=e,r=t?.code===void 0?void 0:h[t.code];n=r===void 0?`Error logging user in: `+String(e):r}r(n,t)})}};function v(e,t,n,r){new _(e,t??{uid:``},n??{...p},r??(()=>{}))}function y(e,t={uid:``},n){return new Promise((r,i)=>{v(e,t,n??{...p},(e,t)=>{e==null?r({authData:t}):i(e)})})}exports.FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR=u,exports.FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR=l,exports.FirebaseLoginCustom=_,exports.FirebaseLoginCustomTokenError=f,exports.FirebaseLoginCustomValidationError=d,exports.default=v,exports.firebaseLoginCustomAsync=y;
2
2
  //# sourceMappingURL=firebase-login-custom.js.map
3
3
  if (typeof module !== 'undefined' && module.exports) { var _def = module.exports.default, _cls = module.exports.FirebaseLoginCustom; module.exports = _def; if (_def) { _def.default = _def; if (_cls !== undefined) _def.FirebaseLoginCustom = _cls; } }
@@ -1 +1 @@
1
- {"version":3,"file":"firebase-login-custom.js","names":[],"sources":["../src/firebase-login-custom.ts"],"sourcesContent":["/**\n * FirebaseLoginCustom\n *\n * Authenticating Users with Custom login\n * Firebase makes it easy to integrate email and password authentication\n * into your app. Firebase automatically stores your users' credentials\n * securely (using bcrypt) and redundantly (daily off-site backups).\n * This separates sensitive user credentials from your application data,\n * and lets you focus on the user interface and experience for your app.\n *\n * @author André Lademann <vergissberlin@googlemail.com>\n * @link https://www.firebase.com/docs/web/guide/login/password.html\n * @param ref Firebase object reference\n * @param data Authentication object with uid and secret\n * @param option Option object with admin, debug and expire settings\n * @param callback Callback function\n * @return FirebaseLoginCustom\n */\n\nimport FirebaseTokenGenerator from 'firebase-token-generator';\n\n/** Error code for validation failures (invalid ref, data, option, or callback). */\nexport const FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR = 'FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR';\n\n/** Error code for token generation failures (e.g. invalid claims or secret). */\nexport const FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR = 'FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR';\n\n/**\n * Thrown when constructor arguments are invalid (ref, data, option, or callback).\n * Consumers can use `error.code === FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR` or\n * `error instanceof FirebaseLoginCustomValidationError`.\n */\nexport class FirebaseLoginCustomValidationError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR;\n\n constructor(message: string) {\n super(message);\n this.name = 'FirebaseLoginCustomValidationError';\n Object.setPrototypeOf(this, FirebaseLoginCustomValidationError.prototype);\n }\n}\n\n/**\n * Thrown when token generation fails (e.g. invalid secret or claims).\n * Passed to the callback when createToken throws; not thrown from the constructor.\n */\nexport class FirebaseLoginCustomTokenError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR;\n readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'FirebaseLoginCustomTokenError';\n this.cause = cause;\n Object.setPrototypeOf(this, FirebaseLoginCustomTokenError.prototype);\n }\n}\n\nexport interface AuthData {\n uid: string;\n [key: string]: unknown;\n}\n\nexport interface FirebaseLoginOption {\n admin?: boolean;\n debug?: boolean;\n expires?: number;\n notBefore?: number;\n secret: string;\n}\n\n/** Option type for inputs where secret is not yet validated */\nexport type FirebaseLoginOptionInput = Omit<FirebaseLoginOption, 'secret'> & {\n secret?: string;\n};\n\nexport type FirebaseLoginCallback = (\n error: Error | string | null,\n authData?: unknown\n) => void;\n\nexport interface FirebaseRef {\n authWithCustomToken: (\n token: string,\n callback: FirebaseLoginCallback\n ) => void;\n}\n\n/** Shape of auth errors passed to the callback by Firebase (with optional code). */\nexport interface FirebaseAuthError extends Error {\n code?: string;\n}\n\nconst DEFAULT_OPTION: Required<Omit<FirebaseLoginOption, 'secret'>> & {\n secret?: string;\n} = {\n admin: false,\n debug: false,\n expires: 0,\n notBefore: 0,\n};\n\nconst SECONDS_PER_DAY = 86400;\n\n/** User-facing messages for known Firebase auth error codes */\nconst AUTH_ERROR_MESSAGES: Record<string, string> = {\n INVALID_EMAIL: 'The specified user account email is invalid.',\n INVALID_PASSWORD: 'The specified user account password is incorrect.',\n INVALID_USER: 'The specified user account does not exist.',\n};\n\nfunction resolveOption(\n input: FirebaseLoginOptionInput\n): Required<Omit<FirebaseLoginOption, 'secret'>> & { secret: string } {\n const now = Date.now() / 1000;\n return {\n admin: typeof input.admin === 'boolean' ? input.admin : DEFAULT_OPTION.admin,\n debug: typeof input.debug === 'boolean' ? input.debug : DEFAULT_OPTION.debug,\n expires: typeof input.expires === 'number' ? input.expires : now + SECONDS_PER_DAY,\n notBefore: typeof input.notBefore === 'number' ? input.notBefore : now,\n secret: input.secret as string,\n };\n}\n\n/**\n * Custom login helper: generates a Firebase custom token and authenticates via the given ref.\n * Validation errors throw synchronously; token or auth failures are reported to the callback.\n */\nexport class FirebaseLoginCustom {\n /**\n * @param ref - Firebase ref with `authWithCustomToken(token, callback)`\n * @param data - Auth payload; must include `uid` (string)\n * @param option - Options; must include `secret`. Optional: admin, debug, expires, notBefore\n * @param callback - Called with (error, authData) when auth completes or token generation fails\n */\n constructor(\n ref: FirebaseRef,\n data: AuthData = { uid: '' },\n option: FirebaseLoginOptionInput = { ...DEFAULT_OPTION },\n callback: FirebaseLoginCallback = () => {}\n ) {\n if (ref == null || typeof ref !== 'object') {\n throw new FirebaseLoginCustomValidationError('Ref must be an object!');\n }\n if (typeof data.uid !== 'string') {\n throw new FirebaseLoginCustomValidationError('Data object must have a \"uid\" field!');\n }\n if (typeof option.secret !== 'string') {\n throw new FirebaseLoginCustomValidationError('Option object must have a \"secret\" field!');\n }\n if (typeof callback !== 'function') {\n throw new FirebaseLoginCustomValidationError('Callback must be a function!');\n }\n\n const resolvedOption = resolveOption(option);\n\n let authToken: string;\n try {\n const tokenGenerator = new FirebaseTokenGenerator(resolvedOption.secret);\n authToken = tokenGenerator.createToken(data, {\n admin: resolvedOption.admin,\n debug: resolvedOption.debug,\n expires: resolvedOption.expires,\n notBefore: resolvedOption.notBefore,\n });\n } catch (err) {\n const callbackError =\n err instanceof Error\n ? new FirebaseLoginCustomTokenError('Token generation failed: ' + err.message, err)\n : new FirebaseLoginCustomTokenError('Token generation failed: ' + String(err), err);\n process.nextTick(() => callback(callbackError, undefined));\n return;\n }\n\n ref.authWithCustomToken(authToken, (error, authData) => {\n let callbackError: Error | string | null = null;\n if (error) {\n const authErr = error as FirebaseAuthError;\n const knownMessage =\n authErr?.code !== undefined ? AUTH_ERROR_MESSAGES[authErr.code] : undefined;\n callbackError =\n knownMessage !== undefined ? knownMessage : 'Error logging user in: ' + String(error);\n }\n callback(callbackError, authData);\n });\n }\n}\n\n/**\n * Callable form: same as `new FirebaseLoginCustom(...)`. Use without `new` for backward compatibility.\n */\nfunction firebaseLoginCustom(\n ref: FirebaseRef,\n data?: AuthData,\n option?: FirebaseLoginOptionInput,\n callback?: FirebaseLoginCallback\n): void {\n new FirebaseLoginCustom(\n ref,\n data ?? { uid: '' },\n option ?? { ...DEFAULT_OPTION },\n callback ?? (() => {})\n );\n}\n\nexport default firebaseLoginCustom;\n"],"mappings":"8mBAsBA,IAAa,EAAyC,yCAGzC,EAAoC,oCAOpC,EAAb,MAAa,UAA2C,KAAM,CAG5D,YAAY,EAAiB,CAC3B,MAAM,EAAQ,WAHA,EAId,KAAK,KAAO,qCACZ,OAAO,eAAe,KAAM,EAAmC,UAAU,GAQhE,EAAb,MAAa,UAAsC,KAAM,CAIvD,YAAY,EAAiB,EAAiB,CAC5C,MAAM,EAAQ,WAJA,EAKd,KAAK,KAAO,gCACZ,KAAK,MAAQ,EACb,OAAO,eAAe,KAAM,EAA8B,UAAU,GAuClE,EAEF,CACF,MAAO,GACP,MAAO,GACP,QAAS,EACT,UAAW,EACZ,CAEK,EAAkB,MAGlB,EAA8C,CAClD,cAAe,+CACf,iBAAkB,oDAClB,aAAc,6CACf,CAED,SAAS,EACP,EACoE,CACpE,IAAM,EAAM,KAAK,KAAK,CAAG,IACzB,MAAO,CACL,MAAO,OAAO,EAAM,OAAU,UAAY,EAAM,MAAQ,EAAe,MACvE,MAAO,OAAO,EAAM,OAAU,UAAY,EAAM,MAAQ,EAAe,MACvE,QAAS,OAAO,EAAM,SAAY,SAAW,EAAM,QAAU,EAAM,EACnE,UAAW,OAAO,EAAM,WAAc,SAAW,EAAM,UAAY,EACnE,OAAQ,EAAM,OACf,CAOH,IAAa,EAAb,KAAiC,CAO/B,YACE,EACA,EAAiB,CAAE,IAAK,GAAI,CAC5B,EAAmC,CAAE,GAAG,EAAgB,CACxD,MAAwC,GACxC,CACA,GAAmB,OAAO,GAAQ,WAA9B,EACF,MAAM,IAAI,EAAmC,yBAAyB,CAExE,GAAI,OAAO,EAAK,KAAQ,SACtB,MAAM,IAAI,EAAmC,uCAAuC,CAEtF,GAAI,OAAO,EAAO,QAAW,SAC3B,MAAM,IAAI,EAAmC,4CAA4C,CAE3F,GAAI,OAAO,GAAa,WACtB,MAAM,IAAI,EAAmC,+BAA+B,CAG9E,IAAM,EAAiB,EAAc,EAAO,CAExC,EACJ,GAAI,CAEF,EADuB,IAAI,EAAA,QAAuB,EAAe,OAAO,CAC7C,YAAY,EAAM,CAC3C,MAAO,EAAe,MACtB,MAAO,EAAe,MACtB,QAAS,EAAe,QACxB,UAAW,EAAe,UAC3B,CAAC,OACK,EAAK,CACZ,IAAM,EACJ,aAAe,MACX,IAAI,EAA8B,4BAA8B,EAAI,QAAS,EAAI,CACjF,IAAI,EAA8B,4BAA8B,OAAO,EAAI,CAAE,EAAI,CACvF,QAAQ,aAAe,EAAS,EAAe,IAAA,GAAU,CAAC,CAC1D,OAGF,EAAI,oBAAoB,GAAY,EAAO,IAAa,CACtD,IAAI,EAAuC,KAC3C,GAAI,EAAO,CACT,IAAM,EAAU,EACV,EACJ,GAAS,OAAS,IAAA,GAAgD,IAAA,GAApC,EAAoB,EAAQ,MAC5D,EACE,IAAiB,IAAA,GAA2B,0BAA4B,OAAO,EAAM,CAAxD,EAEjC,EAAS,EAAe,EAAS,EACjC,GAON,SAAS,EACP,EACA,EACA,EACA,EACM,CACN,IAAI,EACF,EACA,GAAQ,CAAE,IAAK,GAAI,CACnB,GAAU,CAAE,GAAG,EAAgB,CAC/B,QAAmB,IACpB"}
1
+ {"version":3,"file":"firebase-login-custom.js","names":[],"sources":["../src/firebase-login-custom.ts"],"sourcesContent":["/**\n * FirebaseLoginCustom\n *\n * Authenticating Users with Custom login\n * Firebase makes it easy to integrate email and password authentication\n * into your app. Firebase automatically stores your users' credentials\n * securely (using bcrypt) and redundantly (daily off-site backups).\n * This separates sensitive user credentials from your application data,\n * and lets you focus on the user interface and experience for your app.\n *\n * @author André Lademann <vergissberlin@googlemail.com>\n * @link https://www.firebase.com/docs/web/guide/login/password.html\n * @param ref Firebase object reference\n * @param data Authentication object with uid and secret\n * @param option Option object with admin, debug and expire settings\n * @param callback Callback function\n * @return FirebaseLoginCustom\n */\n\nimport FirebaseTokenGenerator from 'firebase-token-generator';\n\n/** Error code for validation failures (invalid ref, data, option, or callback). */\nexport const FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR = 'FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR';\n\n/** Error code for token generation failures (e.g. invalid claims or secret). */\nexport const FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR = 'FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR';\n\n/**\n * Thrown when constructor arguments are invalid (ref, data, option, or callback).\n * Consumers can use `error.code === FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR` or\n * `error instanceof FirebaseLoginCustomValidationError`.\n */\nexport class FirebaseLoginCustomValidationError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR;\n\n constructor(message: string) {\n super(message);\n this.name = 'FirebaseLoginCustomValidationError';\n Object.setPrototypeOf(this, FirebaseLoginCustomValidationError.prototype);\n }\n}\n\n/**\n * Thrown when token generation fails (e.g. invalid secret or claims).\n * Passed to the callback when createToken throws; not thrown from the constructor.\n */\nexport class FirebaseLoginCustomTokenError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR;\n readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'FirebaseLoginCustomTokenError';\n this.cause = cause;\n Object.setPrototypeOf(this, FirebaseLoginCustomTokenError.prototype);\n }\n}\n\nexport interface AuthData {\n uid: string;\n [key: string]: unknown;\n}\n\nexport interface FirebaseLoginOption {\n admin?: boolean;\n debug?: boolean;\n expires?: number;\n notBefore?: number;\n secret: string;\n}\n\n/** Option type for inputs where secret is not yet validated */\nexport type FirebaseLoginOptionInput = Omit<FirebaseLoginOption, 'secret'> & {\n secret?: string;\n};\n\nexport type FirebaseLoginCallback = (\n error: Error | string | null,\n authData?: unknown\n) => void;\n\nexport interface FirebaseRef {\n authWithCustomToken: (\n token: string,\n callback: FirebaseLoginCallback\n ) => void;\n}\n\n/** Shape of auth errors passed to the callback by Firebase (with optional code). */\nexport interface FirebaseAuthError extends Error {\n code?: string;\n}\n\nconst DEFAULT_OPTION: Required<Omit<FirebaseLoginOption, 'secret'>> & {\n secret?: string;\n} = {\n admin: false,\n debug: false,\n expires: 0,\n notBefore: 0,\n};\n\nconst SECONDS_PER_DAY = 86400;\n\n/** User-facing messages for known Firebase auth error codes */\nconst AUTH_ERROR_MESSAGES: Record<string, string> = {\n INVALID_EMAIL: 'The specified user account email is invalid.',\n INVALID_PASSWORD: 'The specified user account password is incorrect.',\n INVALID_USER: 'The specified user account does not exist.',\n};\n\nfunction resolveOption(\n input: FirebaseLoginOptionInput\n): Required<Omit<FirebaseLoginOption, 'secret'>> & { secret: string } {\n const now = Date.now() / 1000;\n return {\n admin: typeof input.admin === 'boolean' ? input.admin : DEFAULT_OPTION.admin,\n debug: typeof input.debug === 'boolean' ? input.debug : DEFAULT_OPTION.debug,\n expires: typeof input.expires === 'number' ? input.expires : now + SECONDS_PER_DAY,\n notBefore: typeof input.notBefore === 'number' ? input.notBefore : now,\n secret: input.secret as string,\n };\n}\n\n/**\n * Custom login helper: generates a Firebase custom token and authenticates via the given ref.\n * Validation errors throw synchronously; token or auth failures are reported to the callback.\n */\nexport class FirebaseLoginCustom {\n /**\n * @param ref - Firebase ref with `authWithCustomToken(token, callback)`\n * @param data - Auth payload; must include `uid` (string)\n * @param option - Options; must include `secret`. Optional: admin, debug, expires, notBefore\n * @param callback - Called with (error, authData) when auth completes or token generation fails\n */\n constructor(\n ref: FirebaseRef,\n data: AuthData = { uid: '' },\n option: FirebaseLoginOptionInput = { ...DEFAULT_OPTION },\n callback: FirebaseLoginCallback = () => {}\n ) {\n if (ref == null || typeof ref !== 'object') {\n throw new FirebaseLoginCustomValidationError('Ref must be an object!');\n }\n if (typeof data.uid !== 'string') {\n throw new FirebaseLoginCustomValidationError('Data object must have a \"uid\" field!');\n }\n if (typeof option.secret !== 'string') {\n throw new FirebaseLoginCustomValidationError('Option object must have a \"secret\" field!');\n }\n if (typeof callback !== 'function') {\n throw new FirebaseLoginCustomValidationError('Callback must be a function!');\n }\n\n const resolvedOption = resolveOption(option);\n\n let authToken: string;\n try {\n const tokenGenerator = new FirebaseTokenGenerator(resolvedOption.secret);\n authToken = tokenGenerator.createToken(data, {\n admin: resolvedOption.admin,\n debug: resolvedOption.debug,\n expires: resolvedOption.expires,\n notBefore: resolvedOption.notBefore,\n });\n } catch (err) {\n const callbackError =\n err instanceof Error\n ? new FirebaseLoginCustomTokenError('Token generation failed: ' + err.message, err)\n : new FirebaseLoginCustomTokenError('Token generation failed: ' + String(err), err);\n process.nextTick(() => callback(callbackError, undefined));\n return;\n }\n\n ref.authWithCustomToken(authToken, (error, authData) => {\n let callbackError: Error | string | null = null;\n if (error) {\n const authErr = error as FirebaseAuthError;\n const knownMessage =\n authErr?.code !== undefined ? AUTH_ERROR_MESSAGES[authErr.code] : undefined;\n callbackError =\n knownMessage !== undefined ? knownMessage : 'Error logging user in: ' + String(error);\n }\n callback(callbackError, authData);\n });\n }\n}\n\n/**\n * Callable form: same as `new FirebaseLoginCustom(...)`. Use without `new` for backward compatibility.\n */\nfunction firebaseLoginCustom(\n ref: FirebaseRef,\n data?: AuthData,\n option?: FirebaseLoginOptionInput,\n callback?: FirebaseLoginCallback\n): void {\n new FirebaseLoginCustom(\n ref,\n data ?? { uid: '' },\n option ?? { ...DEFAULT_OPTION },\n callback ?? (() => {})\n );\n}\n\n/**\n * Promise-based API: same as `firebaseLoginCustom` but returns a Promise.\n * Resolves with `{ authData }` on success, rejects with the same error type as the callback\n * (string or `FirebaseLoginCustomTokenError` / auth error message).\n */\nexport function firebaseLoginCustomAsync(\n ref: FirebaseRef,\n data: AuthData = { uid: '' },\n option?: FirebaseLoginOptionInput\n): Promise<{ authData: unknown }> {\n return new Promise((resolve, reject) => {\n firebaseLoginCustom(ref, data, option ?? { ...DEFAULT_OPTION }, (error, authData) => {\n if (error !== null && error !== undefined) {\n reject(error);\n } else {\n resolve({ authData });\n }\n });\n });\n}\n\nexport default firebaseLoginCustom;\n"],"mappings":"8mBAsBA,IAAa,EAAyC,yCAGzC,EAAoC,oCAOpC,EAAb,MAAa,UAA2C,KAAM,CAG5D,YAAY,EAAiB,CAC3B,MAAM,EAAQ,WAHA,EAId,KAAK,KAAO,qCACZ,OAAO,eAAe,KAAM,EAAmC,UAAU,GAQhE,EAAb,MAAa,UAAsC,KAAM,CAIvD,YAAY,EAAiB,EAAiB,CAC5C,MAAM,EAAQ,WAJA,EAKd,KAAK,KAAO,gCACZ,KAAK,MAAQ,EACb,OAAO,eAAe,KAAM,EAA8B,UAAU,GAuClE,EAEF,CACF,MAAO,GACP,MAAO,GACP,QAAS,EACT,UAAW,EACZ,CAEK,EAAkB,MAGlB,EAA8C,CAClD,cAAe,+CACf,iBAAkB,oDAClB,aAAc,6CACf,CAED,SAAS,EACP,EACoE,CACpE,IAAM,EAAM,KAAK,KAAK,CAAG,IACzB,MAAO,CACL,MAAO,OAAO,EAAM,OAAU,UAAY,EAAM,MAAQ,EAAe,MACvE,MAAO,OAAO,EAAM,OAAU,UAAY,EAAM,MAAQ,EAAe,MACvE,QAAS,OAAO,EAAM,SAAY,SAAW,EAAM,QAAU,EAAM,EACnE,UAAW,OAAO,EAAM,WAAc,SAAW,EAAM,UAAY,EACnE,OAAQ,EAAM,OACf,CAOH,IAAa,EAAb,KAAiC,CAO/B,YACE,EACA,EAAiB,CAAE,IAAK,GAAI,CAC5B,EAAmC,CAAE,GAAG,EAAgB,CACxD,MAAwC,GACxC,CACA,GAAmB,OAAO,GAAQ,WAA9B,EACF,MAAM,IAAI,EAAmC,yBAAyB,CAExE,GAAI,OAAO,EAAK,KAAQ,SACtB,MAAM,IAAI,EAAmC,uCAAuC,CAEtF,GAAI,OAAO,EAAO,QAAW,SAC3B,MAAM,IAAI,EAAmC,4CAA4C,CAE3F,GAAI,OAAO,GAAa,WACtB,MAAM,IAAI,EAAmC,+BAA+B,CAG9E,IAAM,EAAiB,EAAc,EAAO,CAExC,EACJ,GAAI,CAEF,EADuB,IAAI,EAAA,QAAuB,EAAe,OAAO,CAC7C,YAAY,EAAM,CAC3C,MAAO,EAAe,MACtB,MAAO,EAAe,MACtB,QAAS,EAAe,QACxB,UAAW,EAAe,UAC3B,CAAC,OACK,EAAK,CACZ,IAAM,EACJ,aAAe,MACX,IAAI,EAA8B,4BAA8B,EAAI,QAAS,EAAI,CACjF,IAAI,EAA8B,4BAA8B,OAAO,EAAI,CAAE,EAAI,CACvF,QAAQ,aAAe,EAAS,EAAe,IAAA,GAAU,CAAC,CAC1D,OAGF,EAAI,oBAAoB,GAAY,EAAO,IAAa,CACtD,IAAI,EAAuC,KAC3C,GAAI,EAAO,CACT,IAAM,EAAU,EACV,EACJ,GAAS,OAAS,IAAA,GAAgD,IAAA,GAApC,EAAoB,EAAQ,MAC5D,EACE,IAAiB,IAAA,GAA2B,0BAA4B,OAAO,EAAM,CAAxD,EAEjC,EAAS,EAAe,EAAS,EACjC,GAON,SAAS,EACP,EACA,EACA,EACA,EACM,CACN,IAAI,EACF,EACA,GAAQ,CAAE,IAAK,GAAI,CACnB,GAAU,CAAE,GAAG,EAAgB,CAC/B,QAAmB,IACpB,CAQH,SAAgB,EACd,EACA,EAAiB,CAAE,IAAK,GAAI,CAC5B,EACgC,CAChC,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,EAAoB,EAAK,EAAM,GAAU,CAAE,GAAG,EAAgB,EAAG,EAAO,IAAa,CAC/E,GAAU,KAGZ,EAAQ,CAAE,WAAU,CAAC,CAFrB,EAAO,EAAM,EAIf,EACF"}
@@ -60,7 +60,14 @@ var l = class {
60
60
  function u(e, t, n, r) {
61
61
  new l(e, t ?? { uid: "" }, n ?? { ...a }, r ?? (() => {}));
62
62
  }
63
+ function d(e, t = { uid: "" }, n) {
64
+ return new Promise((r, i) => {
65
+ u(e, t, n ?? { ...a }, (e, t) => {
66
+ e == null ? r({ authData: t }) : i(e);
67
+ });
68
+ });
69
+ }
63
70
  //#endregion
64
- export { n as FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR, t as FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR, l as FirebaseLoginCustom, i as FirebaseLoginCustomTokenError, r as FirebaseLoginCustomValidationError, u as default };
71
+ export { n as FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR, t as FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR, l as FirebaseLoginCustom, i as FirebaseLoginCustomTokenError, r as FirebaseLoginCustomValidationError, u as default, d as firebaseLoginCustomAsync };
65
72
 
66
73
  //# sourceMappingURL=firebase-login-custom.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"firebase-login-custom.mjs","names":[],"sources":["../src/firebase-login-custom.ts"],"sourcesContent":["/**\n * FirebaseLoginCustom\n *\n * Authenticating Users with Custom login\n * Firebase makes it easy to integrate email and password authentication\n * into your app. Firebase automatically stores your users' credentials\n * securely (using bcrypt) and redundantly (daily off-site backups).\n * This separates sensitive user credentials from your application data,\n * and lets you focus on the user interface and experience for your app.\n *\n * @author André Lademann <vergissberlin@googlemail.com>\n * @link https://www.firebase.com/docs/web/guide/login/password.html\n * @param ref Firebase object reference\n * @param data Authentication object with uid and secret\n * @param option Option object with admin, debug and expire settings\n * @param callback Callback function\n * @return FirebaseLoginCustom\n */\n\nimport FirebaseTokenGenerator from 'firebase-token-generator';\n\n/** Error code for validation failures (invalid ref, data, option, or callback). */\nexport const FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR = 'FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR';\n\n/** Error code for token generation failures (e.g. invalid claims or secret). */\nexport const FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR = 'FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR';\n\n/**\n * Thrown when constructor arguments are invalid (ref, data, option, or callback).\n * Consumers can use `error.code === FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR` or\n * `error instanceof FirebaseLoginCustomValidationError`.\n */\nexport class FirebaseLoginCustomValidationError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR;\n\n constructor(message: string) {\n super(message);\n this.name = 'FirebaseLoginCustomValidationError';\n Object.setPrototypeOf(this, FirebaseLoginCustomValidationError.prototype);\n }\n}\n\n/**\n * Thrown when token generation fails (e.g. invalid secret or claims).\n * Passed to the callback when createToken throws; not thrown from the constructor.\n */\nexport class FirebaseLoginCustomTokenError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR;\n readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'FirebaseLoginCustomTokenError';\n this.cause = cause;\n Object.setPrototypeOf(this, FirebaseLoginCustomTokenError.prototype);\n }\n}\n\nexport interface AuthData {\n uid: string;\n [key: string]: unknown;\n}\n\nexport interface FirebaseLoginOption {\n admin?: boolean;\n debug?: boolean;\n expires?: number;\n notBefore?: number;\n secret: string;\n}\n\n/** Option type for inputs where secret is not yet validated */\nexport type FirebaseLoginOptionInput = Omit<FirebaseLoginOption, 'secret'> & {\n secret?: string;\n};\n\nexport type FirebaseLoginCallback = (\n error: Error | string | null,\n authData?: unknown\n) => void;\n\nexport interface FirebaseRef {\n authWithCustomToken: (\n token: string,\n callback: FirebaseLoginCallback\n ) => void;\n}\n\n/** Shape of auth errors passed to the callback by Firebase (with optional code). */\nexport interface FirebaseAuthError extends Error {\n code?: string;\n}\n\nconst DEFAULT_OPTION: Required<Omit<FirebaseLoginOption, 'secret'>> & {\n secret?: string;\n} = {\n admin: false,\n debug: false,\n expires: 0,\n notBefore: 0,\n};\n\nconst SECONDS_PER_DAY = 86400;\n\n/** User-facing messages for known Firebase auth error codes */\nconst AUTH_ERROR_MESSAGES: Record<string, string> = {\n INVALID_EMAIL: 'The specified user account email is invalid.',\n INVALID_PASSWORD: 'The specified user account password is incorrect.',\n INVALID_USER: 'The specified user account does not exist.',\n};\n\nfunction resolveOption(\n input: FirebaseLoginOptionInput\n): Required<Omit<FirebaseLoginOption, 'secret'>> & { secret: string } {\n const now = Date.now() / 1000;\n return {\n admin: typeof input.admin === 'boolean' ? input.admin : DEFAULT_OPTION.admin,\n debug: typeof input.debug === 'boolean' ? input.debug : DEFAULT_OPTION.debug,\n expires: typeof input.expires === 'number' ? input.expires : now + SECONDS_PER_DAY,\n notBefore: typeof input.notBefore === 'number' ? input.notBefore : now,\n secret: input.secret as string,\n };\n}\n\n/**\n * Custom login helper: generates a Firebase custom token and authenticates via the given ref.\n * Validation errors throw synchronously; token or auth failures are reported to the callback.\n */\nexport class FirebaseLoginCustom {\n /**\n * @param ref - Firebase ref with `authWithCustomToken(token, callback)`\n * @param data - Auth payload; must include `uid` (string)\n * @param option - Options; must include `secret`. Optional: admin, debug, expires, notBefore\n * @param callback - Called with (error, authData) when auth completes or token generation fails\n */\n constructor(\n ref: FirebaseRef,\n data: AuthData = { uid: '' },\n option: FirebaseLoginOptionInput = { ...DEFAULT_OPTION },\n callback: FirebaseLoginCallback = () => {}\n ) {\n if (ref == null || typeof ref !== 'object') {\n throw new FirebaseLoginCustomValidationError('Ref must be an object!');\n }\n if (typeof data.uid !== 'string') {\n throw new FirebaseLoginCustomValidationError('Data object must have a \"uid\" field!');\n }\n if (typeof option.secret !== 'string') {\n throw new FirebaseLoginCustomValidationError('Option object must have a \"secret\" field!');\n }\n if (typeof callback !== 'function') {\n throw new FirebaseLoginCustomValidationError('Callback must be a function!');\n }\n\n const resolvedOption = resolveOption(option);\n\n let authToken: string;\n try {\n const tokenGenerator = new FirebaseTokenGenerator(resolvedOption.secret);\n authToken = tokenGenerator.createToken(data, {\n admin: resolvedOption.admin,\n debug: resolvedOption.debug,\n expires: resolvedOption.expires,\n notBefore: resolvedOption.notBefore,\n });\n } catch (err) {\n const callbackError =\n err instanceof Error\n ? new FirebaseLoginCustomTokenError('Token generation failed: ' + err.message, err)\n : new FirebaseLoginCustomTokenError('Token generation failed: ' + String(err), err);\n process.nextTick(() => callback(callbackError, undefined));\n return;\n }\n\n ref.authWithCustomToken(authToken, (error, authData) => {\n let callbackError: Error | string | null = null;\n if (error) {\n const authErr = error as FirebaseAuthError;\n const knownMessage =\n authErr?.code !== undefined ? AUTH_ERROR_MESSAGES[authErr.code] : undefined;\n callbackError =\n knownMessage !== undefined ? knownMessage : 'Error logging user in: ' + String(error);\n }\n callback(callbackError, authData);\n });\n }\n}\n\n/**\n * Callable form: same as `new FirebaseLoginCustom(...)`. Use without `new` for backward compatibility.\n */\nfunction firebaseLoginCustom(\n ref: FirebaseRef,\n data?: AuthData,\n option?: FirebaseLoginOptionInput,\n callback?: FirebaseLoginCallback\n): void {\n new FirebaseLoginCustom(\n ref,\n data ?? { uid: '' },\n option ?? { ...DEFAULT_OPTION },\n callback ?? (() => {})\n );\n}\n\nexport default firebaseLoginCustom;\n"],"mappings":";;AAsBA,IAAa,IAAyC,0CAGzC,IAAoC,qCAOpC,IAAb,MAAa,UAA2C,MAAM;CAG5D,YAAY,GAAiB;AAG3B,EAFA,MAAM,EAAQ,cAHA,GAId,KAAK,OAAO,sCACZ,OAAO,eAAe,MAAM,EAAmC,UAAU;;GAQhE,IAAb,MAAa,UAAsC,MAAM;CAIvD,YAAY,GAAiB,GAAiB;AAI5C,EAHA,MAAM,EAAQ,cAJA,GAKd,KAAK,OAAO,iCACZ,KAAK,QAAQ,GACb,OAAO,eAAe,MAAM,EAA8B,UAAU;;GAuClE,IAEF;CACF,OAAO;CACP,OAAO;CACP,SAAS;CACT,WAAW;CACZ,EAEK,IAAkB,OAGlB,IAA8C;CAClD,eAAe;CACf,kBAAkB;CAClB,cAAc;CACf;AAED,SAAS,EACP,GACoE;CACpE,IAAM,IAAM,KAAK,KAAK,GAAG;AACzB,QAAO;EACL,OAAO,OAAO,EAAM,SAAU,YAAY,EAAM,QAAQ,EAAe;EACvE,OAAO,OAAO,EAAM,SAAU,YAAY,EAAM,QAAQ,EAAe;EACvE,SAAS,OAAO,EAAM,WAAY,WAAW,EAAM,UAAU,IAAM;EACnE,WAAW,OAAO,EAAM,aAAc,WAAW,EAAM,YAAY;EACnE,QAAQ,EAAM;EACf;;AAOH,IAAa,IAAb,MAAiC;CAO/B,YACE,GACA,IAAiB,EAAE,KAAK,IAAI,EAC5B,IAAmC,EAAE,GAAG,GAAgB,EACxD,UAAwC,IACxC;AACA,MAAmB,OAAO,KAAQ,aAA9B,EACF,OAAM,IAAI,EAAmC,yBAAyB;AAExE,MAAI,OAAO,EAAK,OAAQ,SACtB,OAAM,IAAI,EAAmC,yCAAuC;AAEtF,MAAI,OAAO,EAAO,UAAW,SAC3B,OAAM,IAAI,EAAmC,8CAA4C;AAE3F,MAAI,OAAO,KAAa,WACtB,OAAM,IAAI,EAAmC,+BAA+B;EAG9E,IAAM,IAAiB,EAAc,EAAO,EAExC;AACJ,MAAI;AAEF,OADuB,IAAI,EAAuB,EAAe,OAAO,CAC7C,YAAY,GAAM;IAC3C,OAAO,EAAe;IACtB,OAAO,EAAe;IACtB,SAAS,EAAe;IACxB,WAAW,EAAe;IAC3B,CAAC;WACK,GAAK;GACZ,IAAM,IACJ,aAAe,QACX,IAAI,EAA8B,8BAA8B,EAAI,SAAS,EAAI,GACjF,IAAI,EAA8B,8BAA8B,OAAO,EAAI,EAAE,EAAI;AACvF,WAAQ,eAAe,EAAS,GAAe,KAAA,EAAU,CAAC;AAC1D;;AAGF,IAAI,oBAAoB,IAAY,GAAO,MAAa;GACtD,IAAI,IAAuC;AAC3C,OAAI,GAAO;IACT,IAAM,IAAU,GACV,IACJ,GAAS,SAAS,KAAA,IAAgD,KAAA,IAApC,EAAoB,EAAQ;AAC5D,QACE,MAAiB,KAAA,IAA2B,4BAA4B,OAAO,EAAM,GAAxD;;AAEjC,KAAS,GAAe,EAAS;IACjC;;;AAON,SAAS,EACP,GACA,GACA,GACA,GACM;AACN,KAAI,EACF,GACA,KAAQ,EAAE,KAAK,IAAI,EACnB,KAAU,EAAE,GAAG,GAAgB,EAC/B,YAAmB,IACpB"}
1
+ {"version":3,"file":"firebase-login-custom.mjs","names":[],"sources":["../src/firebase-login-custom.ts"],"sourcesContent":["/**\n * FirebaseLoginCustom\n *\n * Authenticating Users with Custom login\n * Firebase makes it easy to integrate email and password authentication\n * into your app. Firebase automatically stores your users' credentials\n * securely (using bcrypt) and redundantly (daily off-site backups).\n * This separates sensitive user credentials from your application data,\n * and lets you focus on the user interface and experience for your app.\n *\n * @author André Lademann <vergissberlin@googlemail.com>\n * @link https://www.firebase.com/docs/web/guide/login/password.html\n * @param ref Firebase object reference\n * @param data Authentication object with uid and secret\n * @param option Option object with admin, debug and expire settings\n * @param callback Callback function\n * @return FirebaseLoginCustom\n */\n\nimport FirebaseTokenGenerator from 'firebase-token-generator';\n\n/** Error code for validation failures (invalid ref, data, option, or callback). */\nexport const FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR = 'FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR';\n\n/** Error code for token generation failures (e.g. invalid claims or secret). */\nexport const FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR = 'FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR';\n\n/**\n * Thrown when constructor arguments are invalid (ref, data, option, or callback).\n * Consumers can use `error.code === FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR` or\n * `error instanceof FirebaseLoginCustomValidationError`.\n */\nexport class FirebaseLoginCustomValidationError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_VALIDATION_ERROR;\n\n constructor(message: string) {\n super(message);\n this.name = 'FirebaseLoginCustomValidationError';\n Object.setPrototypeOf(this, FirebaseLoginCustomValidationError.prototype);\n }\n}\n\n/**\n * Thrown when token generation fails (e.g. invalid secret or claims).\n * Passed to the callback when createToken throws; not thrown from the constructor.\n */\nexport class FirebaseLoginCustomTokenError extends Error {\n readonly code = FIREBASE_LOGIN_CUSTOM_TOKEN_ERROR;\n readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'FirebaseLoginCustomTokenError';\n this.cause = cause;\n Object.setPrototypeOf(this, FirebaseLoginCustomTokenError.prototype);\n }\n}\n\nexport interface AuthData {\n uid: string;\n [key: string]: unknown;\n}\n\nexport interface FirebaseLoginOption {\n admin?: boolean;\n debug?: boolean;\n expires?: number;\n notBefore?: number;\n secret: string;\n}\n\n/** Option type for inputs where secret is not yet validated */\nexport type FirebaseLoginOptionInput = Omit<FirebaseLoginOption, 'secret'> & {\n secret?: string;\n};\n\nexport type FirebaseLoginCallback = (\n error: Error | string | null,\n authData?: unknown\n) => void;\n\nexport interface FirebaseRef {\n authWithCustomToken: (\n token: string,\n callback: FirebaseLoginCallback\n ) => void;\n}\n\n/** Shape of auth errors passed to the callback by Firebase (with optional code). */\nexport interface FirebaseAuthError extends Error {\n code?: string;\n}\n\nconst DEFAULT_OPTION: Required<Omit<FirebaseLoginOption, 'secret'>> & {\n secret?: string;\n} = {\n admin: false,\n debug: false,\n expires: 0,\n notBefore: 0,\n};\n\nconst SECONDS_PER_DAY = 86400;\n\n/** User-facing messages for known Firebase auth error codes */\nconst AUTH_ERROR_MESSAGES: Record<string, string> = {\n INVALID_EMAIL: 'The specified user account email is invalid.',\n INVALID_PASSWORD: 'The specified user account password is incorrect.',\n INVALID_USER: 'The specified user account does not exist.',\n};\n\nfunction resolveOption(\n input: FirebaseLoginOptionInput\n): Required<Omit<FirebaseLoginOption, 'secret'>> & { secret: string } {\n const now = Date.now() / 1000;\n return {\n admin: typeof input.admin === 'boolean' ? input.admin : DEFAULT_OPTION.admin,\n debug: typeof input.debug === 'boolean' ? input.debug : DEFAULT_OPTION.debug,\n expires: typeof input.expires === 'number' ? input.expires : now + SECONDS_PER_DAY,\n notBefore: typeof input.notBefore === 'number' ? input.notBefore : now,\n secret: input.secret as string,\n };\n}\n\n/**\n * Custom login helper: generates a Firebase custom token and authenticates via the given ref.\n * Validation errors throw synchronously; token or auth failures are reported to the callback.\n */\nexport class FirebaseLoginCustom {\n /**\n * @param ref - Firebase ref with `authWithCustomToken(token, callback)`\n * @param data - Auth payload; must include `uid` (string)\n * @param option - Options; must include `secret`. Optional: admin, debug, expires, notBefore\n * @param callback - Called with (error, authData) when auth completes or token generation fails\n */\n constructor(\n ref: FirebaseRef,\n data: AuthData = { uid: '' },\n option: FirebaseLoginOptionInput = { ...DEFAULT_OPTION },\n callback: FirebaseLoginCallback = () => {}\n ) {\n if (ref == null || typeof ref !== 'object') {\n throw new FirebaseLoginCustomValidationError('Ref must be an object!');\n }\n if (typeof data.uid !== 'string') {\n throw new FirebaseLoginCustomValidationError('Data object must have a \"uid\" field!');\n }\n if (typeof option.secret !== 'string') {\n throw new FirebaseLoginCustomValidationError('Option object must have a \"secret\" field!');\n }\n if (typeof callback !== 'function') {\n throw new FirebaseLoginCustomValidationError('Callback must be a function!');\n }\n\n const resolvedOption = resolveOption(option);\n\n let authToken: string;\n try {\n const tokenGenerator = new FirebaseTokenGenerator(resolvedOption.secret);\n authToken = tokenGenerator.createToken(data, {\n admin: resolvedOption.admin,\n debug: resolvedOption.debug,\n expires: resolvedOption.expires,\n notBefore: resolvedOption.notBefore,\n });\n } catch (err) {\n const callbackError =\n err instanceof Error\n ? new FirebaseLoginCustomTokenError('Token generation failed: ' + err.message, err)\n : new FirebaseLoginCustomTokenError('Token generation failed: ' + String(err), err);\n process.nextTick(() => callback(callbackError, undefined));\n return;\n }\n\n ref.authWithCustomToken(authToken, (error, authData) => {\n let callbackError: Error | string | null = null;\n if (error) {\n const authErr = error as FirebaseAuthError;\n const knownMessage =\n authErr?.code !== undefined ? AUTH_ERROR_MESSAGES[authErr.code] : undefined;\n callbackError =\n knownMessage !== undefined ? knownMessage : 'Error logging user in: ' + String(error);\n }\n callback(callbackError, authData);\n });\n }\n}\n\n/**\n * Callable form: same as `new FirebaseLoginCustom(...)`. Use without `new` for backward compatibility.\n */\nfunction firebaseLoginCustom(\n ref: FirebaseRef,\n data?: AuthData,\n option?: FirebaseLoginOptionInput,\n callback?: FirebaseLoginCallback\n): void {\n new FirebaseLoginCustom(\n ref,\n data ?? { uid: '' },\n option ?? { ...DEFAULT_OPTION },\n callback ?? (() => {})\n );\n}\n\n/**\n * Promise-based API: same as `firebaseLoginCustom` but returns a Promise.\n * Resolves with `{ authData }` on success, rejects with the same error type as the callback\n * (string or `FirebaseLoginCustomTokenError` / auth error message).\n */\nexport function firebaseLoginCustomAsync(\n ref: FirebaseRef,\n data: AuthData = { uid: '' },\n option?: FirebaseLoginOptionInput\n): Promise<{ authData: unknown }> {\n return new Promise((resolve, reject) => {\n firebaseLoginCustom(ref, data, option ?? { ...DEFAULT_OPTION }, (error, authData) => {\n if (error !== null && error !== undefined) {\n reject(error);\n } else {\n resolve({ authData });\n }\n });\n });\n}\n\nexport default firebaseLoginCustom;\n"],"mappings":";;AAsBA,IAAa,IAAyC,0CAGzC,IAAoC,qCAOpC,IAAb,MAAa,UAA2C,MAAM;CAG5D,YAAY,GAAiB;AAG3B,EAFA,MAAM,EAAQ,cAHA,GAId,KAAK,OAAO,sCACZ,OAAO,eAAe,MAAM,EAAmC,UAAU;;GAQhE,IAAb,MAAa,UAAsC,MAAM;CAIvD,YAAY,GAAiB,GAAiB;AAI5C,EAHA,MAAM,EAAQ,cAJA,GAKd,KAAK,OAAO,iCACZ,KAAK,QAAQ,GACb,OAAO,eAAe,MAAM,EAA8B,UAAU;;GAuClE,IAEF;CACF,OAAO;CACP,OAAO;CACP,SAAS;CACT,WAAW;CACZ,EAEK,IAAkB,OAGlB,IAA8C;CAClD,eAAe;CACf,kBAAkB;CAClB,cAAc;CACf;AAED,SAAS,EACP,GACoE;CACpE,IAAM,IAAM,KAAK,KAAK,GAAG;AACzB,QAAO;EACL,OAAO,OAAO,EAAM,SAAU,YAAY,EAAM,QAAQ,EAAe;EACvE,OAAO,OAAO,EAAM,SAAU,YAAY,EAAM,QAAQ,EAAe;EACvE,SAAS,OAAO,EAAM,WAAY,WAAW,EAAM,UAAU,IAAM;EACnE,WAAW,OAAO,EAAM,aAAc,WAAW,EAAM,YAAY;EACnE,QAAQ,EAAM;EACf;;AAOH,IAAa,IAAb,MAAiC;CAO/B,YACE,GACA,IAAiB,EAAE,KAAK,IAAI,EAC5B,IAAmC,EAAE,GAAG,GAAgB,EACxD,UAAwC,IACxC;AACA,MAAmB,OAAO,KAAQ,aAA9B,EACF,OAAM,IAAI,EAAmC,yBAAyB;AAExE,MAAI,OAAO,EAAK,OAAQ,SACtB,OAAM,IAAI,EAAmC,yCAAuC;AAEtF,MAAI,OAAO,EAAO,UAAW,SAC3B,OAAM,IAAI,EAAmC,8CAA4C;AAE3F,MAAI,OAAO,KAAa,WACtB,OAAM,IAAI,EAAmC,+BAA+B;EAG9E,IAAM,IAAiB,EAAc,EAAO,EAExC;AACJ,MAAI;AAEF,OADuB,IAAI,EAAuB,EAAe,OAAO,CAC7C,YAAY,GAAM;IAC3C,OAAO,EAAe;IACtB,OAAO,EAAe;IACtB,SAAS,EAAe;IACxB,WAAW,EAAe;IAC3B,CAAC;WACK,GAAK;GACZ,IAAM,IACJ,aAAe,QACX,IAAI,EAA8B,8BAA8B,EAAI,SAAS,EAAI,GACjF,IAAI,EAA8B,8BAA8B,OAAO,EAAI,EAAE,EAAI;AACvF,WAAQ,eAAe,EAAS,GAAe,KAAA,EAAU,CAAC;AAC1D;;AAGF,IAAI,oBAAoB,IAAY,GAAO,MAAa;GACtD,IAAI,IAAuC;AAC3C,OAAI,GAAO;IACT,IAAM,IAAU,GACV,IACJ,GAAS,SAAS,KAAA,IAAgD,KAAA,IAApC,EAAoB,EAAQ;AAC5D,QACE,MAAiB,KAAA,IAA2B,4BAA4B,OAAO,EAAM,GAAxD;;AAEjC,KAAS,GAAe,EAAS;IACjC;;;AAON,SAAS,EACP,GACA,GACA,GACA,GACM;AACN,KAAI,EACF,GACA,KAAQ,EAAE,KAAK,IAAI,EACnB,KAAU,EAAE,GAAG,GAAgB,EAC/B,YAAmB,IACpB;;AAQH,SAAgB,EACd,GACA,IAAiB,EAAE,KAAK,IAAI,EAC5B,GACgC;AAChC,QAAO,IAAI,SAAS,GAAS,MAAW;AACtC,IAAoB,GAAK,GAAM,KAAU,EAAE,GAAG,GAAgB,GAAG,GAAO,MAAa;AACnF,GAAI,KAAU,OAGZ,EAAQ,EAAE,aAAU,CAAC,GAFrB,EAAO,EAAM;IAIf;GACF"}
package/package.json CHANGED
@@ -1,13 +1,26 @@
1
1
  {
2
2
  "name": "firebase-login-custom",
3
- "version": "0.4.0",
4
- "description": "This package is a wrapper to firebase custom login including all dependencies with the exception of firebase it self.",
3
+ "version": "0.5.1",
4
+ "description": "This package is a wrapper to firebase custom login including all dependencies with the exception of firebase itself.",
5
5
  "engines": {
6
6
  "node": ">=20"
7
7
  },
8
8
  "main": "dist/firebase-login-custom.js",
9
9
  "module": "dist/firebase-login-custom.es.js",
10
10
  "types": "dist/firebase-login-custom.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/firebase-login-custom.d.ts",
14
+ "import": "./dist/firebase-login-custom.es.js",
15
+ "require": "./dist/firebase-login-custom.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE",
22
+ "CHANGELOG.md"
23
+ ],
11
24
  "directories": {
12
25
  "test": "tests"
13
26
  },
@@ -57,7 +70,7 @@
57
70
  "dev": "vite build --watch",
58
71
  "watch": "vite build --watch",
59
72
  "typecheck": "tsc --noEmit",
60
- "lint": "pnpm exec eslint src/",
73
+ "lint": "pnpm exec eslint src/ tests/",
61
74
  "test": "pnpm run test:unit && pnpm run test:integration",
62
75
  "test:unit": "vitest run",
63
76
  "test:integration": "node -e \"const fs=require('fs'); if(!fs.existsSync('dist/firebase-login-custom.js')){ const {execSync}=require('child_process'); execSync('pnpm run build',{stdio:'inherit'}); }\" && node tests/run-integration.js",
package/.husky/pre-commit DELETED
@@ -1 +0,0 @@
1
- pnpm run lint && pnpm run test
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.4.0"
3
- }
package/CONTRIBUTING.md DELETED
@@ -1,70 +0,0 @@
1
- # Contributing
2
-
3
- 1. Fork it
4
- 2. Create your feature branch (`git flow feature start my-new-feature`)
5
- 3. Commit your changes (`git commit -am 'Add code'`)
6
- 4. Finish your implementation (`git flow feature finish my-new-feature`)
7
- 5. Push to origin (`git push origin`)
8
- 6. Create new Pull Request
9
-
10
- ## Install locally and test
11
-
12
- Tests use a **Firebase mock** by default (no credentials needed). With env vars set, they use real Firebase.
13
-
14
- ```bash
15
- cd /path/to/firebase-login-custom
16
- pnpm install
17
- pnpm run build
18
- pnpm test
19
- ```
20
-
21
- - **Unit tests** (Vitest): `pnpm run test:unit` (no build required). Watch mode: `pnpm run test:watch`.
22
- - **Integration tests**: `pnpm run test:integration` (builds first if needed). `pnpm test` runs unit then integration.
23
-
24
- **Pre-commit hooks (Husky):** Before each commit, `pnpm run lint` and `pnpm run test` run automatically. If either fails, the commit is aborted. Hooks are installed when you run `pnpm install` (via the `prepare` script).
25
-
26
- To run against real Firebase:
27
-
28
- ```bash
29
- export FIREBASE_ID=<YOUR_TEST_ID>
30
- export FIREBASE_UID=<YOUR_USER_ID>
31
- export FIREBASE_SECRET=<YOUR_SECRET>
32
- pnpm test
33
- ```
34
-
35
- For CI, optional: set repository secrets `FIREBASE_ID`, `FIREBASE_UID`, and `FIREBASE_SECRET` to run integration tests against real Firebase on push/PR.
36
-
37
- ## Releasing
38
-
39
- Releases are automated via GitHub Actions and [Release Please](https://github.com/googleapis/release-please).
40
-
41
- - **Release Please** (workflow `release-please`): On every push to `main`, it opens or updates a release PR based on [Conventional Commits](https://www.conventionalcommits.org/). Merge that PR; Release Please then creates the version tag and GitHub Release.
42
- - **Release** (workflow `Release`): Triggered when a GitHub Release is published (e.g. by Release Please), when a version tag (`v*`) is pushed, or **manually**. It builds, **publishes to npm** (requires `NPM_TOKEN` secret), and creates/updates the GitHub Release when triggered by a tag push.
43
-
44
- ### First-time publish (Release workflow never ran)
45
-
46
- If the Release workflow has never run and nothing is on [npm](https://www.npmjs.com/package/firebase-login-custom) yet:
47
-
48
- 1. **Add `NPM_TOKEN`** (Settings → Secrets and variables → Actions): Create an npm [Access Token](https://www.npmjs.com/settings/~youruser/tokens) with **Automation** or **Publish** scope and add it as repository secret `NPM_TOKEN`.
49
- 2. **Run the Release workflow once**: In the repo go to **Actions → Release → Run workflow** (use "Run workflow" on the default branch). This publishes the current `package.json` version to npm. No GitHub Release is created when run manually.
50
- 3. After that, use either Release Please (conventional commits + merge release PR) or manual tag push (`git tag v0.1.0 && git push origin v0.1.0`) so future releases also trigger the workflow automatically.
51
-
52
- ### Regular releases
53
-
54
- 1. **Secrets** (Settings → Secrets and variables → Actions):
55
- - **NPM_TOKEN** (required): npm auth token with publish permission. Create at [npmjs.com → Access Tokens](https://www.npmjs.com/settings/~youruser/tokens) (Automation or Publish).
56
- - **GH_PAT** (optional): GitHub Personal Access Token with `repo` scope. Only needed if the default `GITHUB_TOKEN` cannot create releases (e.g. in some org settings). If you use it, set the Release workflow's "Create GitHub Release" step to `GITHUB_TOKEN: ${{ secrets.GH_PAT }}`.
57
-
58
- 2. **Version and tag (with Release Please)**: Use conventional commits (e.g. `feat:`, `fix:`, `chore:`). After pushing to `main`, Release Please will open or update a release PR. Merge that PR; Release Please creates the tag and GitHub Release. The Release workflow runs on **release published** (and on tag push), so it will build and publish to npm—ensure **NPM_TOKEN** is set in repository secrets.
59
-
60
- **Without Release Please** (manual): Bump version in `package.json`, commit, push a version tag:
61
-
62
- ```bash
63
- pnpm version patch # or minor / major
64
- git push origin main
65
- git push origin v0.0.4 # use the new version number
66
- ```
67
-
68
- Pushing a tag `v*` triggers the Release workflow.
69
-
70
- 3. **Manual run**: You can also trigger the Release workflow manually (Actions → Release → Run workflow). It will publish the current version from `package.json` to npm; no GitHub Release is created unless a tag is pushed.
@@ -1,8 +0,0 @@
1
- {
2
- "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3
- "release-type": "node",
4
- "include-component-in-tag": false,
5
- "packages": {
6
- ".": {}
7
- }
8
- }
package/renovate.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
- "extends": [
4
- "config:recommended"
5
- ]
6
- }
package/vitest.config.ts DELETED
@@ -1,17 +0,0 @@
1
- import { defineConfig } from 'vitest/config';
2
- import { resolve } from 'path';
3
-
4
- export default defineConfig({
5
- test: {
6
- globals: true,
7
- environment: 'node',
8
- include: ['src/**/*.test.ts', 'src/**/*.spec.ts'],
9
- testTimeout: 5000,
10
- hookTimeout: 5000,
11
- },
12
- resolve: {
13
- alias: {
14
- '@': resolve(__dirname, 'src'),
15
- },
16
- },
17
- });