@sentroy-co/client-sdk 2.13.7 → 2.13.8
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/auth/admin/index.d.ts +52 -0
- package/dist/auth/admin/index.d.ts.map +1 -0
- package/dist/auth/admin/index.js +123 -0
- package/dist/auth/admin/index.js.map +1 -0
- package/dist/auth/client.d.ts +86 -0
- package/dist/auth/client.d.ts.map +1 -0
- package/dist/auth/client.js +265 -0
- package/dist/auth/client.js.map +1 -0
- package/dist/auth/http.d.ts +19 -0
- package/dist/auth/http.d.ts.map +1 -0
- package/dist/auth/http.js +74 -0
- package/dist/auth/http.js.map +1 -0
- package/dist/auth/index.d.ts +16 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +20 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/react/index.d.ts +41 -0
- package/dist/auth/react/index.d.ts.map +1 -0
- package/dist/auth/react/index.js +52 -0
- package/dist/auth/react/index.js.map +1 -0
- package/dist/auth/types.d.ts +50 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +21 -0
- package/dist/auth/types.js.map +1 -0
- package/package.json +16 -1
- package/src/auth/admin/index.ts +191 -0
- package/src/auth/client.ts +344 -0
- package/src/auth/http.ts +101 -0
- package/src/auth/index.ts +26 -0
- package/src/auth/react/index.tsx +100 -0
- package/src/auth/types.ts +60 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentroy Auth-as-a-Service — browser/server SDK entry.
|
|
3
|
+
*
|
|
4
|
+
* import { SentroyAuth } from "@sentroy-co/client-sdk/auth"
|
|
5
|
+
* const auth = new SentroyAuth({ projectSlug: "my-app" })
|
|
6
|
+
*
|
|
7
|
+
* For server admin operations (verifyIdToken, etc):
|
|
8
|
+
* import { SentroyAuthAdmin } from "@sentroy-co/client-sdk/auth/admin"
|
|
9
|
+
*
|
|
10
|
+
* For React integration:
|
|
11
|
+
* import { SentroyAuthProvider, useAuth } from "@sentroy-co/client-sdk/auth/react"
|
|
12
|
+
*/
|
|
13
|
+
export { SentroyAuth } from "./client";
|
|
14
|
+
export type { SentroyAuthOptions, AuthStateChangeListener, AuthStorageAdapter, } from "./client";
|
|
15
|
+
export { SentroyAuthError, type SentroyAuthUser, type SignupResponse, type LoginResponse, type AuthTokensResponse, } from "./types";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Sentroy Auth-as-a-Service — browser/server SDK entry.
|
|
4
|
+
*
|
|
5
|
+
* import { SentroyAuth } from "@sentroy-co/client-sdk/auth"
|
|
6
|
+
* const auth = new SentroyAuth({ projectSlug: "my-app" })
|
|
7
|
+
*
|
|
8
|
+
* For server admin operations (verifyIdToken, etc):
|
|
9
|
+
* import { SentroyAuthAdmin } from "@sentroy-co/client-sdk/auth/admin"
|
|
10
|
+
*
|
|
11
|
+
* For React integration:
|
|
12
|
+
* import { SentroyAuthProvider, useAuth } from "@sentroy-co/client-sdk/auth/react"
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SentroyAuthError = exports.SentroyAuth = void 0;
|
|
16
|
+
var client_1 = require("./client");
|
|
17
|
+
Object.defineProperty(exports, "SentroyAuth", { enumerable: true, get: function () { return client_1.SentroyAuth; } });
|
|
18
|
+
var types_1 = require("./types");
|
|
19
|
+
Object.defineProperty(exports, "SentroyAuthError", { enumerable: true, get: function () { return types_1.SentroyAuthError; } });
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAEH,mCAAsC;AAA7B,qGAAA,WAAW,OAAA;AAMpB,iCAMgB;AALd,yGAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { SentroyAuth, type SentroyAuthOptions } from "../client";
|
|
3
|
+
import type { SentroyAuthUser } from "../types";
|
|
4
|
+
/**
|
|
5
|
+
* Sentroy Auth React integration.
|
|
6
|
+
*
|
|
7
|
+
* <SentroyAuthProvider projectSlug="my-app">
|
|
8
|
+
* <App />
|
|
9
|
+
* </SentroyAuthProvider>
|
|
10
|
+
*
|
|
11
|
+
* const { user, loading, signIn, signOut } = useAuth()
|
|
12
|
+
*
|
|
13
|
+
* Provider içeride tek bir `SentroyAuth` instance tutar (mount/unmount
|
|
14
|
+
* arasında stable), `onAuthStateChanged` ile React state'i senkron tutar.
|
|
15
|
+
* `loading` ilk render → restore tamam mı henüz değil ayrımı için.
|
|
16
|
+
*/
|
|
17
|
+
interface AuthContextValue {
|
|
18
|
+
auth: SentroyAuth;
|
|
19
|
+
user: SentroyAuthUser | null;
|
|
20
|
+
/** True iken provider ilk state'i restore etmiş değil — UI'da
|
|
21
|
+
* "spinner" göster, "redirect to /login" tetikleme. */
|
|
22
|
+
loading: boolean;
|
|
23
|
+
/** Convenience proxies — caller `auth.signIn(...)` yerine doğrudan
|
|
24
|
+
* `signIn(...)` kullanabilir. */
|
|
25
|
+
signIn: SentroyAuth["signIn"];
|
|
26
|
+
signUp: SentroyAuth["signUp"];
|
|
27
|
+
signOut: SentroyAuth["signOut"];
|
|
28
|
+
sendPasswordReset: SentroyAuth["sendPasswordReset"];
|
|
29
|
+
verifyEmail: SentroyAuth["verifyEmail"];
|
|
30
|
+
}
|
|
31
|
+
export declare function SentroyAuthProvider({ children, ...opts }: SentroyAuthOptions & {
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export declare function useAuth(): AuthContextValue;
|
|
35
|
+
/**
|
|
36
|
+
* Convenience: yalnızca current user istenirse. `loading` durumunda null
|
|
37
|
+
* dönerken bekleyebilirsin.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useUser(): SentroyAuthUser | null;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/react/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C;;;;;;;;;;;;GAYG;AAEH,UAAU,gBAAgB;IACxB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,eAAe,GAAG,IAAI,CAAA;IAC5B;4DACwD;IACxD,OAAO,EAAE,OAAO,CAAA;IAChB;sCACkC;IAClC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC7B,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC7B,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IAC/B,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAAC,CAAA;IACnD,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,CAAA;CACxC;AAID,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,kBAAkB,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAkC9C;AAED,wBAAgB,OAAO,IAAI,gBAAgB,CAQ1C;AAED;;;GAGG;AACH,wBAAgB,OAAO,IAAI,eAAe,GAAG,IAAI,CAEhD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.SentroyAuthProvider = SentroyAuthProvider;
|
|
5
|
+
exports.useAuth = useAuth;
|
|
6
|
+
exports.useUser = useUser;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const client_1 = require("../client");
|
|
10
|
+
const AuthContext = (0, react_1.createContext)(null);
|
|
11
|
+
function SentroyAuthProvider({ children, ...opts }) {
|
|
12
|
+
// Single instance — opts deep-compare'a girersek dependency drift'i
|
|
13
|
+
// restart'a yol açar. Caller `projectSlug` değiştirmemeli runtime'da.
|
|
14
|
+
const auth = (0, react_1.useMemo)(() => new client_1.SentroyAuth(opts),
|
|
15
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
16
|
+
[opts.projectSlug, opts.authBaseUrl, opts.apiKey]);
|
|
17
|
+
const [user, setUser] = (0, react_1.useState)(auth.user);
|
|
18
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
19
|
+
(0, react_1.useEffect)(() => {
|
|
20
|
+
const unsubscribe = auth.onAuthStateChanged((u) => {
|
|
21
|
+
setUser(u);
|
|
22
|
+
setLoading(false);
|
|
23
|
+
});
|
|
24
|
+
return unsubscribe;
|
|
25
|
+
}, [auth]);
|
|
26
|
+
const value = (0, react_1.useMemo)(() => ({
|
|
27
|
+
auth,
|
|
28
|
+
user,
|
|
29
|
+
loading,
|
|
30
|
+
signIn: (i) => auth.signIn(i),
|
|
31
|
+
signUp: (i) => auth.signUp(i),
|
|
32
|
+
signOut: () => auth.signOut(),
|
|
33
|
+
sendPasswordReset: (e) => auth.sendPasswordReset(e),
|
|
34
|
+
verifyEmail: (t) => auth.verifyEmail(t),
|
|
35
|
+
}), [auth, user, loading]);
|
|
36
|
+
return (0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: value, children: children });
|
|
37
|
+
}
|
|
38
|
+
function useAuth() {
|
|
39
|
+
const ctx = (0, react_1.useContext)(AuthContext);
|
|
40
|
+
if (!ctx) {
|
|
41
|
+
throw new Error("useAuth must be used inside <SentroyAuthProvider> — wrap your app root.");
|
|
42
|
+
}
|
|
43
|
+
return ctx;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Convenience: yalnızca current user istenirse. `loading` durumunda null
|
|
47
|
+
* dönerken bekleyebilirsin.
|
|
48
|
+
*/
|
|
49
|
+
function useUser() {
|
|
50
|
+
return useAuth().user;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/react/index.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAA;;AA4CZ,kDAqCC;AAED,0BAQC;AAMD,0BAEC;;AAjGD,iCAOc;AACd,sCAAgE;AAgChE,MAAM,WAAW,GAAG,IAAA,qBAAa,EAA0B,IAAI,CAAC,CAAA;AAEhE,SAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,GAAG,IAAI,EACsC;IAC7C,oEAAoE;IACpE,sEAAsE;IACtE,MAAM,IAAI,GAAG,IAAA,eAAO,EAClB,GAAG,EAAE,CAAC,IAAI,oBAAW,CAAC,IAAI,CAAC;IAC3B,uDAAuD;IACvD,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAClD,CAAA;IACD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAA,gBAAQ,EAAyB,IAAI,CAAC,IAAI,CAAC,CAAA;IACnE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAA;IAE5C,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE;YAChD,OAAO,CAAC,CAAC,CAAC,CAAA;YACV,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;QACF,OAAO,WAAW,CAAA;IACpB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,MAAM,KAAK,GAAG,IAAA,eAAO,EACnB,GAAG,EAAE,CAAC,CAAC;QACL,IAAI;QACJ,IAAI;QACJ,OAAO;QACP,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7B,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;QAC7B,iBAAiB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACnD,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;KACxC,CAAC,EACF,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CACtB,CAAA;IAED,OAAO,uBAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAwB,CAAA;AAC9E,CAAC;AAED,SAAgB,OAAO;IACrB,MAAM,GAAG,GAAG,IAAA,kBAAU,EAAC,WAAW,CAAC,CAAA;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAA;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,SAAgB,OAAO;IACrB,OAAO,OAAO,EAAE,CAAC,IAAI,CAAA;AACvB,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentroy Auth-as-a-Service — SDK types.
|
|
3
|
+
*
|
|
4
|
+
* Public types are kept narrow on purpose: SDK shapes evolve with backend;
|
|
5
|
+
* caller code should depend on these names, not on hand-coded interfaces.
|
|
6
|
+
*/
|
|
7
|
+
export interface SentroyAuthUser {
|
|
8
|
+
id: string;
|
|
9
|
+
authProjectId: string;
|
|
10
|
+
email: string;
|
|
11
|
+
emailVerified: boolean;
|
|
12
|
+
displayName: string | null;
|
|
13
|
+
image: string | null;
|
|
14
|
+
metadata: Record<string, unknown>;
|
|
15
|
+
lastLoginAt: string | null;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
updatedAt: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AuthTokensResponse {
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
expiresIn: number;
|
|
23
|
+
tokenType: "Bearer";
|
|
24
|
+
}
|
|
25
|
+
export interface SignupResponse {
|
|
26
|
+
user: SentroyAuthUser;
|
|
27
|
+
/** Email verification gerekiyorsa undefined; aksi halde set. */
|
|
28
|
+
accessToken?: string;
|
|
29
|
+
refreshToken?: string;
|
|
30
|
+
expiresIn?: number;
|
|
31
|
+
tokenType?: "Bearer";
|
|
32
|
+
emailVerificationRequired?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface LoginResponse {
|
|
35
|
+
user: SentroyAuthUser;
|
|
36
|
+
accessToken: string;
|
|
37
|
+
refreshToken: string;
|
|
38
|
+
expiresIn: number;
|
|
39
|
+
tokenType: "Bearer";
|
|
40
|
+
}
|
|
41
|
+
export interface AuthApiError {
|
|
42
|
+
error: string;
|
|
43
|
+
error_description: string;
|
|
44
|
+
}
|
|
45
|
+
export declare class SentroyAuthError extends Error {
|
|
46
|
+
readonly code: string;
|
|
47
|
+
readonly status: number;
|
|
48
|
+
constructor(code: string, message: string, status: number);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,OAAO,CAAA;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,QAAQ,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,CAAA;IACrB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,QAAQ,CAAA;IACpB,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,eAAe,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,QAAQ,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;gBACX,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAM1D"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Sentroy Auth-as-a-Service — SDK types.
|
|
4
|
+
*
|
|
5
|
+
* Public types are kept narrow on purpose: SDK shapes evolve with backend;
|
|
6
|
+
* caller code should depend on these names, not on hand-coded interfaces.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SentroyAuthError = void 0;
|
|
10
|
+
class SentroyAuthError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
status;
|
|
13
|
+
constructor(code, message, status) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "SentroyAuthError";
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.status = status;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.SentroyAuthError = SentroyAuthError;
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA6CH,MAAa,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAQ;IACZ,MAAM,CAAQ;IACvB,YAAY,IAAY,EAAE,OAAe,EAAE,MAAc;QACvD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF;AATD,4CASC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentroy-co/client-sdk",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.8",
|
|
4
4
|
"description": "TypeScript SDK + CLI for the Sentroy platform — mail, storage, env vault + React components.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,6 +38,21 @@
|
|
|
38
38
|
"types": "./dist/vault/react.d.ts",
|
|
39
39
|
"import": "./dist/vault/react.js",
|
|
40
40
|
"require": "./dist/vault/react.js"
|
|
41
|
+
},
|
|
42
|
+
"./auth": {
|
|
43
|
+
"types": "./dist/auth/index.d.ts",
|
|
44
|
+
"import": "./dist/auth/index.js",
|
|
45
|
+
"require": "./dist/auth/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./auth/admin": {
|
|
48
|
+
"types": "./dist/auth/admin/index.d.ts",
|
|
49
|
+
"import": "./dist/auth/admin/index.js",
|
|
50
|
+
"require": "./dist/auth/admin/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./auth/react": {
|
|
53
|
+
"types": "./dist/auth/react/index.d.ts",
|
|
54
|
+
"import": "./dist/auth/react/index.js",
|
|
55
|
+
"require": "./dist/auth/react/index.js"
|
|
41
56
|
}
|
|
42
57
|
},
|
|
43
58
|
"files": [
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { AuthHttp } from "../http"
|
|
2
|
+
import type { SentroyAuthUser } from "../types"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Server-side Sentroy Auth admin SDK. **Node only — apiKey browser'a
|
|
6
|
+
* koymayın**; bu sınıf Project'in master `aps_` token'ını taşır ve
|
|
7
|
+
* Sentroy üzerindeki user pool'a yetki vermez.
|
|
8
|
+
*
|
|
9
|
+
* Tipik kullanım: backend, kendi `/api/auth/...` proxy'sinde RP-spesifik
|
|
10
|
+
* authorization yapar, sonra `admin.users.get(...)` ile Sentroy'dan
|
|
11
|
+
* end-user'ı çeker. JWT verify de bu SDK üzerinden — tüm akış stateless.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface SentroyAuthAdminOptions {
|
|
15
|
+
authBaseUrl?: string
|
|
16
|
+
projectSlug: string
|
|
17
|
+
apiKey: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class SentroyAuthAdmin {
|
|
21
|
+
private readonly http: AuthHttp
|
|
22
|
+
private cachedJwks: { keys: Record<string, unknown>[] } | null = null
|
|
23
|
+
|
|
24
|
+
constructor(opts: SentroyAuthAdminOptions) {
|
|
25
|
+
this.http = new AuthHttp(opts)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ─── User pool admin ──────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
users = {
|
|
31
|
+
list: (opts: {
|
|
32
|
+
limit?: number
|
|
33
|
+
skip?: number
|
|
34
|
+
emailVerified?: boolean
|
|
35
|
+
} = {}): Promise<{
|
|
36
|
+
items: SentroyAuthUser[]
|
|
37
|
+
pagination: { total: number; limit: number; skip: number }
|
|
38
|
+
}> => {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"admin.users.list requires session-authenticated admin API; use dashboard /api/companies/[slug]/auth-projects/[id]/users instead. (v2 admin SDK will proxy this with stk_ tokens.)",
|
|
41
|
+
)
|
|
42
|
+
// NOTE Phase 5+: SDK admin endpoint'leri public path'lere taşınmadı;
|
|
43
|
+
// şu an `/api/companies/...` cookie-auth ile. v2'de `/api/v1/admin/...`
|
|
44
|
+
// RP token'ı ile authenticate eden ayrı public admin layer eklenir.
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ─── ID token verification ─────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Local verify — JWKS cache'lenir (5dk TTL), JWT signature kontrolü
|
|
52
|
+
* RS256 ile RP backend'inde stateless yapılır. `iss`/`aud` claim
|
|
53
|
+
* eşleşmesi de kontrol edilir.
|
|
54
|
+
*/
|
|
55
|
+
async verifyIdToken(token: string): Promise<{
|
|
56
|
+
sub: string
|
|
57
|
+
email?: string
|
|
58
|
+
email_verified?: boolean
|
|
59
|
+
name?: string
|
|
60
|
+
picture?: string
|
|
61
|
+
iss: string
|
|
62
|
+
aud: string
|
|
63
|
+
iat: number
|
|
64
|
+
exp: number
|
|
65
|
+
}> {
|
|
66
|
+
const parts = token.split(".")
|
|
67
|
+
if (parts.length !== 3) {
|
|
68
|
+
throw new Error("Malformed JWT — expected three segments.")
|
|
69
|
+
}
|
|
70
|
+
const [headerB64, payloadB64, sigB64] = parts
|
|
71
|
+
const header = JSON.parse(decodeBase64Url(headerB64)) as {
|
|
72
|
+
alg?: string
|
|
73
|
+
kid?: string
|
|
74
|
+
}
|
|
75
|
+
if (header.alg !== "RS256") {
|
|
76
|
+
throw new Error("Only RS256 supported.")
|
|
77
|
+
}
|
|
78
|
+
const claims = JSON.parse(decodeBase64Url(payloadB64)) as {
|
|
79
|
+
exp?: number
|
|
80
|
+
iss?: string
|
|
81
|
+
aud?: string
|
|
82
|
+
}
|
|
83
|
+
if (typeof claims.exp !== "number" || claims.exp * 1000 < Date.now()) {
|
|
84
|
+
throw new Error("Token expired.")
|
|
85
|
+
}
|
|
86
|
+
// iss + aud check
|
|
87
|
+
const expectedIssSuffix = `/p/${this.http.projectSlug}`
|
|
88
|
+
if (typeof claims.iss !== "string" || !claims.iss.endsWith(expectedIssSuffix)) {
|
|
89
|
+
throw new Error("Issuer mismatch.")
|
|
90
|
+
}
|
|
91
|
+
// aud == project apiKeyPrefix (12 chars). API key first 12 = aud check.
|
|
92
|
+
if (
|
|
93
|
+
typeof claims.aud !== "string" ||
|
|
94
|
+
!this.http.apiKey?.startsWith(claims.aud)
|
|
95
|
+
) {
|
|
96
|
+
throw new Error("Audience mismatch.")
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const jwks = await this.fetchJwks()
|
|
100
|
+
const key = jwks.keys.find(
|
|
101
|
+
(k) => (k as { kid?: string }).kid === header.kid,
|
|
102
|
+
) ?? jwks.keys[0]
|
|
103
|
+
if (!key) throw new Error("No public key in JWKS.")
|
|
104
|
+
|
|
105
|
+
await verifyRsaSignature({
|
|
106
|
+
data: `${headerB64}.${payloadB64}`,
|
|
107
|
+
sigB64,
|
|
108
|
+
jwk: key as JsonWebKey,
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
return claims as never
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private async fetchJwks(): Promise<{ keys: Record<string, unknown>[] }> {
|
|
115
|
+
if (this.cachedJwks) return this.cachedJwks
|
|
116
|
+
const jwks = await this.http.request<{ keys: Record<string, unknown>[] }>(
|
|
117
|
+
"/jwks.json",
|
|
118
|
+
{ method: "GET" },
|
|
119
|
+
)
|
|
120
|
+
this.cachedJwks = jwks
|
|
121
|
+
// 5dk cache — basit setTimeout invalidation
|
|
122
|
+
setTimeout(() => {
|
|
123
|
+
this.cachedJwks = null
|
|
124
|
+
}, 5 * 60 * 1000)
|
|
125
|
+
return jwks
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
function decodeBase64Url(s: string): string {
|
|
132
|
+
const padded = s.replace(/-/g, "+").replace(/_/g, "/")
|
|
133
|
+
const pad = padded.length % 4 === 0 ? "" : "=".repeat(4 - (padded.length % 4))
|
|
134
|
+
if (typeof atob === "function") {
|
|
135
|
+
const binary = atob(padded + pad)
|
|
136
|
+
const bytes = new Uint8Array(binary.length)
|
|
137
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)
|
|
138
|
+
return new TextDecoder().decode(bytes)
|
|
139
|
+
}
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
141
|
+
const B = (globalThis as any).Buffer
|
|
142
|
+
if (B) return B.from(padded + pad, "base64").toString("utf8")
|
|
143
|
+
throw new Error("No base64 decoder available")
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function base64UrlToBytes(s: string): Uint8Array {
|
|
147
|
+
const padded = s.replace(/-/g, "+").replace(/_/g, "/")
|
|
148
|
+
const pad = padded.length % 4 === 0 ? "" : "=".repeat(4 - (padded.length % 4))
|
|
149
|
+
if (typeof atob === "function") {
|
|
150
|
+
const binary = atob(padded + pad)
|
|
151
|
+
const bytes = new Uint8Array(binary.length)
|
|
152
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)
|
|
153
|
+
return bytes
|
|
154
|
+
}
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
156
|
+
const B = (globalThis as any).Buffer
|
|
157
|
+
if (B) return new Uint8Array(B.from(padded + pad, "base64"))
|
|
158
|
+
throw new Error("No base64 decoder available")
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function verifyRsaSignature(input: {
|
|
162
|
+
data: string
|
|
163
|
+
sigB64: string
|
|
164
|
+
jwk: JsonWebKey
|
|
165
|
+
}): Promise<void> {
|
|
166
|
+
// Browser + modern Node (>=18) have crypto.subtle. Tek kod yolu.
|
|
167
|
+
const subtle =
|
|
168
|
+
typeof crypto !== "undefined" && crypto.subtle ? crypto.subtle : null
|
|
169
|
+
if (!subtle) {
|
|
170
|
+
throw new Error("Web Crypto unavailable — upgrade Node >= 18 or run in a browser.")
|
|
171
|
+
}
|
|
172
|
+
const key = await subtle.importKey(
|
|
173
|
+
"jwk",
|
|
174
|
+
input.jwk,
|
|
175
|
+
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
|
|
176
|
+
false,
|
|
177
|
+
["verify"],
|
|
178
|
+
)
|
|
179
|
+
// Web Crypto types want ArrayBuffer-backed BufferSource. TypeScript
|
|
180
|
+
// can't prove Uint8Array isn't SharedArrayBuffer-backed (DOM lib edge);
|
|
181
|
+
// bytes are created fresh from base64 decode so ArrayBuffer-safe — cast.
|
|
182
|
+
const sigBytes = base64UrlToBytes(input.sigB64) as Uint8Array
|
|
183
|
+
const dataBytes = new TextEncoder().encode(input.data) as Uint8Array
|
|
184
|
+
const ok = await subtle.verify(
|
|
185
|
+
{ name: "RSASSA-PKCS1-v1_5" },
|
|
186
|
+
key,
|
|
187
|
+
sigBytes as unknown as ArrayBuffer,
|
|
188
|
+
dataBytes as unknown as ArrayBuffer,
|
|
189
|
+
)
|
|
190
|
+
if (!ok) throw new Error("Signature mismatch.")
|
|
191
|
+
}
|