@siran/auth-core 0.1.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 +29 -0
- package/README.md +11 -0
- package/eslint.config.mjs +25 -0
- package/package.json +22 -0
- package/src/application/ports/auth-service.port.ts +20 -0
- package/src/application/use-cases/authenticate-user.ts +8 -0
- package/src/domain/session.ts +16 -0
- package/src/domain/user-account.ts +25 -0
- package/src/index.ts +11 -0
- package/tests/application/use-cases/authenticate-user.test.ts +25 -0
- package/tsconfig.json +13 -0
- package/tsconfig.lib.json +32 -0
- package/tsconfig.spec.json +39 -0
- package/vite.config.mts +62 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
## 0.1.1 (2026-01-23)
|
|
2
|
+
|
|
3
|
+
### 🩹 Fixes
|
|
4
|
+
|
|
5
|
+
- Remove private flag from package.json for @siran/auth-core ([4f4e36c](https://github.com/narisraz/auth/commit/4f4e36c))
|
|
6
|
+
|
|
7
|
+
### ❤️ Thank You
|
|
8
|
+
|
|
9
|
+
- Naris Razafimahatratra
|
|
10
|
+
|
|
11
|
+
## 0.1.0 (2026-01-23)
|
|
12
|
+
|
|
13
|
+
### 🚀 Features
|
|
14
|
+
|
|
15
|
+
- Extend OAuth support in AuthMethod type to include Apple and Facebook providers ([d1f5d3e](https://github.com/narisraz/auth/commit/d1f5d3e))
|
|
16
|
+
|
|
17
|
+
### ❤️ Thank You
|
|
18
|
+
|
|
19
|
+
- Naris Razafimahatratra
|
|
20
|
+
|
|
21
|
+
## 0.0.2 (2026-01-23)
|
|
22
|
+
|
|
23
|
+
### 🩹 Fixes
|
|
24
|
+
|
|
25
|
+
- Enhance Vite configuration with TypeScript path aliases and updated plugin setup ([321b446](https://github.com/narisraz/auth/commit/321b446))
|
|
26
|
+
|
|
27
|
+
### ❤️ Thank You
|
|
28
|
+
|
|
29
|
+
- Naris Razafimahatratra
|
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import baseConfig from '../../eslint.config.mjs';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
...baseConfig,
|
|
5
|
+
{
|
|
6
|
+
files: ['**/*.json'],
|
|
7
|
+
rules: {
|
|
8
|
+
'@nx/dependency-checks': [
|
|
9
|
+
'error',
|
|
10
|
+
{
|
|
11
|
+
ignoredFiles: [
|
|
12
|
+
'{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
|
|
13
|
+
'{projectRoot}/vite.config.{js,ts,mjs,mts}',
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
languageOptions: {
|
|
19
|
+
parser: await import('jsonc-eslint-parser'),
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
ignores: ['**/out-tsc'],
|
|
24
|
+
},
|
|
25
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@siran/auth-core",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./package.json": "./package.json",
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"vite-tsconfig-paths": "^6.0.4"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { UserAccount } from "@domain/user-account.js";
|
|
2
|
+
|
|
3
|
+
export type AuthMethod =
|
|
4
|
+
| { type: "password"; identifier: string; password: string }
|
|
5
|
+
| { type: "otp"; identifier: string; code: string }
|
|
6
|
+
| { type: "magic_link"; token: string }
|
|
7
|
+
| { type: "oauth"; provider: "google" | "github" | "apple" | "facebook"; code: string };
|
|
8
|
+
|
|
9
|
+
export type AuthErrorCode = "INVALID_CREDENTIALS" | "ACCOUNT_DISABLED" | "ACCOUNT_LOCKED";
|
|
10
|
+
|
|
11
|
+
export type AuthResult =
|
|
12
|
+
| { ok: true; user: UserAccount }
|
|
13
|
+
| { ok: false; error: AuthErrorCode };
|
|
14
|
+
|
|
15
|
+
export interface AuthServicePort {
|
|
16
|
+
authenticate(method: AuthMethod): Promise<AuthResult>;
|
|
17
|
+
logout(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AuthServicePort } from "@application/ports/auth-service.port.js";
|
|
2
|
+
import type { AuthMethod } from "@application/ports/auth-service.port.js";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const authenticateUser =
|
|
6
|
+
(authService: AuthServicePort) =>
|
|
7
|
+
(method: AuthMethod) =>
|
|
8
|
+
authService.authenticate(method);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domaine: session utilisateur Sekoliko.
|
|
3
|
+
* Ne contient pas de détails d’implémentation (cookies, tokens, etc.).
|
|
4
|
+
*/
|
|
5
|
+
export interface Session {
|
|
6
|
+
id: string;
|
|
7
|
+
userId: string;
|
|
8
|
+
createdAt: Date;
|
|
9
|
+
lastActivityAt: Date;
|
|
10
|
+
expiresAt: Date;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const isSessionActive = (session: Session, now: Date = new Date()): boolean =>
|
|
14
|
+
now < session.expiresAt;
|
|
15
|
+
|
|
16
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type UserStatus = "active" | "disabled" | "lockedTemporarily";
|
|
2
|
+
|
|
3
|
+
export type UserRole = "parent" | "staff" | "admin" | "student" | "teacher";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Domaine: compte utilisateur Sekoliko.
|
|
7
|
+
* Indépendant de toute technologie (pas de dépendance à Supabase ou React).
|
|
8
|
+
*/
|
|
9
|
+
export interface UserAccount {
|
|
10
|
+
id: string;
|
|
11
|
+
establishmentIds: string[];
|
|
12
|
+
displayName: string;
|
|
13
|
+
firstName?: string;
|
|
14
|
+
lastName?: string;
|
|
15
|
+
contactEmail: string;
|
|
16
|
+
status: UserStatus;
|
|
17
|
+
roles: UserRole[];
|
|
18
|
+
failedLoginAttempts: number;
|
|
19
|
+
lastFailedLoginAt: Date | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const canLogin = (user: UserAccount): boolean =>
|
|
23
|
+
user.status === "active";
|
|
24
|
+
|
|
25
|
+
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { authenticateUser } from "@application/use-cases/authenticate-user.js";
|
|
2
|
+
import { AuthServicePort } from "@application/ports/auth-service.port.js";
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
describe('AuthenticateUser', () => {
|
|
6
|
+
it('should authenticate a user', async () => {
|
|
7
|
+
const authService: AuthServicePort = {
|
|
8
|
+
authenticate: vi.fn().mockResolvedValue({ ok: true, user: { id: '1', email: 'test@test.com' } }),
|
|
9
|
+
logout: vi.fn().mockResolvedValue(undefined),
|
|
10
|
+
};
|
|
11
|
+
const loginUser = authenticateUser(authService);
|
|
12
|
+
const user = await loginUser({ type: 'password', identifier: 'test@test.com', password: 'test' });
|
|
13
|
+
expect(user).toEqual({ ok: true, user: { id: '1', email: 'test@test.com' } });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return an error if the authentication fails', async () => {
|
|
17
|
+
const authService: AuthServicePort = {
|
|
18
|
+
authenticate: vi.fn().mockResolvedValue({ ok: false, error: 'INVALID_CREDENTIALS' }),
|
|
19
|
+
logout: vi.fn().mockResolvedValue(undefined),
|
|
20
|
+
};
|
|
21
|
+
const loginUser = authenticateUser(authService);
|
|
22
|
+
const user = await loginUser({ type: 'password', identifier: 'test@test.com', password: 'test' });
|
|
23
|
+
expect(user).toEqual({ ok: false, error: 'INVALID_CREDENTIALS' });
|
|
24
|
+
});
|
|
25
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"paths": {
|
|
8
|
+
"@domain/*": ["src/domain/*"],
|
|
9
|
+
"@application/*": ["src/application/*"],
|
|
10
|
+
},
|
|
11
|
+
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
12
|
+
"emitDeclarationOnly": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"types": ["node", "vite/client"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts"],
|
|
17
|
+
"references": [],
|
|
18
|
+
"exclude": [
|
|
19
|
+
"vite.config.ts",
|
|
20
|
+
"vite.config.mts",
|
|
21
|
+
"vitest.config.ts",
|
|
22
|
+
"vitest.config.mts",
|
|
23
|
+
"src/**/*.test.ts",
|
|
24
|
+
"src/**/*.spec.ts",
|
|
25
|
+
"src/**/*.test.tsx",
|
|
26
|
+
"src/**/*.spec.tsx",
|
|
27
|
+
"src/**/*.test.js",
|
|
28
|
+
"src/**/*.spec.js",
|
|
29
|
+
"src/**/*.test.jsx",
|
|
30
|
+
"src/**/*.spec.jsx"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"paths": {
|
|
6
|
+
"@domain/*": ["src/domain/*"],
|
|
7
|
+
"@application/*": ["src/application/*"]
|
|
8
|
+
},
|
|
9
|
+
"outDir": "./out-tsc/vitest",
|
|
10
|
+
"types": [
|
|
11
|
+
"vitest/globals",
|
|
12
|
+
"vitest/importMeta",
|
|
13
|
+
"vite/client",
|
|
14
|
+
"node",
|
|
15
|
+
"vitest"
|
|
16
|
+
],
|
|
17
|
+
"forceConsistentCasingInFileNames": true
|
|
18
|
+
},
|
|
19
|
+
"include": [
|
|
20
|
+
"vite.config.ts",
|
|
21
|
+
"vite.config.mts",
|
|
22
|
+
"vitest.config.ts",
|
|
23
|
+
"vitest.config.mts",
|
|
24
|
+
"tests/**/*.test.ts",
|
|
25
|
+
"tests/**/*.spec.ts",
|
|
26
|
+
"tests/**/*.test.tsx",
|
|
27
|
+
"tests/**/*.spec.tsx",
|
|
28
|
+
"tests/**/*.test.js",
|
|
29
|
+
"tests/**/*.spec.js",
|
|
30
|
+
"tests/**/*.test.jsx",
|
|
31
|
+
"tests/**/*.spec.jsx",
|
|
32
|
+
"tests/**/*.d.ts",
|
|
33
|
+
],
|
|
34
|
+
"references": [
|
|
35
|
+
{
|
|
36
|
+
"path": "./tsconfig.lib.json"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
package/vite.config.mts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/// <reference types='vitest' />
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import dts from 'vite-plugin-dts';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
6
|
+
|
|
7
|
+
export default defineConfig(() => ({
|
|
8
|
+
root: import.meta.dirname,
|
|
9
|
+
cacheDir: '../../node_modules/.vite/packages/core',
|
|
10
|
+
plugins: [
|
|
11
|
+
tsconfigPaths(),
|
|
12
|
+
dts({
|
|
13
|
+
entryRoot: 'src',
|
|
14
|
+
tsconfigPath: path.join(import.meta.dirname, 'tsconfig.lib.json'),
|
|
15
|
+
}),
|
|
16
|
+
],
|
|
17
|
+
resolve: {
|
|
18
|
+
alias: {
|
|
19
|
+
'@domain': path.resolve(__dirname, 'src/domain'),
|
|
20
|
+
'@application': path.resolve(__dirname, 'src/application'),
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
// Uncomment this if you are using workers.
|
|
24
|
+
// worker: {
|
|
25
|
+
// plugins: [],
|
|
26
|
+
// },
|
|
27
|
+
// Configuration for building your library.
|
|
28
|
+
// See: https://vite.dev/guide/build.html#library-mode
|
|
29
|
+
build: {
|
|
30
|
+
outDir: './dist',
|
|
31
|
+
emptyOutDir: true,
|
|
32
|
+
reportCompressedSize: true,
|
|
33
|
+
commonjsOptions: {
|
|
34
|
+
transformMixedEsModules: true,
|
|
35
|
+
},
|
|
36
|
+
lib: {
|
|
37
|
+
// Could also be a dictionary or array of multiple entry points.
|
|
38
|
+
entry: 'src/index.ts',
|
|
39
|
+
name: '@siran/auth-core',
|
|
40
|
+
fileName: 'index',
|
|
41
|
+
// Change this to the formats you want to support.
|
|
42
|
+
// Don't forget to update your package.json as well.
|
|
43
|
+
formats: ['es' as const],
|
|
44
|
+
},
|
|
45
|
+
rollupOptions: {
|
|
46
|
+
// External packages that should not be bundled into your library.
|
|
47
|
+
external: [],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
test: {
|
|
51
|
+
name: '@siran/auth-core',
|
|
52
|
+
watch: false,
|
|
53
|
+
globals: true,
|
|
54
|
+
environment: 'node',
|
|
55
|
+
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
56
|
+
reporters: ['default'],
|
|
57
|
+
coverage: {
|
|
58
|
+
reportsDirectory: './test-output/vitest/coverage',
|
|
59
|
+
provider: 'v8' as const,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
}));
|