@axproo/auth-kit 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # Auth-Kit 🔐
2
+
3
+ ![npm](https://img.shields.io/npm/v/auth-kit)
4
+ ![vue](https://img.shields.io/badge/Vue-3.5+-42b883)
5
+ ![pinia](https://img.shields.io/badge/Pinia-3.0.4-yellow)
6
+ ![typescript](https://img.shields.io/badge/TypeScript-ready-blue)
7
+ ![license](https://img.shields.io/badge/license-MIT-green)
8
+
9
+ **Auth-Kit** est un kit d’authentification moderne pour **Vue 3**, conçu pour fonctionner avec **Pinia**, **TypeScript** et des **formulaires dynamiques**.
10
+ Il fournit un flux d’authentification clair, extensible et prêt pour la production.
11
+
12
+ > 💡 Pensé pour les apps SaaS, dashboards admin et projets modulaires.
13
+
14
+ ---
15
+
16
+ ## ✨ Fonctionnalités
17
+
18
+ - 🔐 Login sécurisé
19
+ - ⏳ Gestion du chargement (`isLoading`)
20
+ - 🔒 Verrouillage temporaire après erreurs (`isLocked`)
21
+ - 🔁 Gestion du flux d’authentification (steps)
22
+ - 🌍 Compatible `vue-i18n`
23
+ - 🧩 Intégration native avec `@axproo/form-builder`
24
+ - 🧠 Store Pinia prêt à l’emploi
25
+ - 🧪 Full TypeScript
26
+
27
+ ---
28
+
29
+ ## 📦 Installation
30
+
31
+ ```bash
32
+ npm install auth-kit pinia vue
33
+ ```
34
+
35
+ ⚠️ auth-kit utilise des peerDependencies, assure-toi qu’elles sont bien installées.
36
+
37
+ ## 🔗 Peer Dependencies
38
+
39
+ | Package | Version |
40
+ | ---------------- | ------- |
41
+ | vue | ^3.5.0 |
42
+ | pinia | 3.0.4 |
43
+ | vite | ^7.2.4 |
44
+ | @axproo/app-core | ^0.1.0 |
45
+
46
+ ## 🚀 Utilisation rapide
47
+
48
+ ### 1️⃣ Initialiser Pinia
49
+
50
+ ```typescript
51
+ import { createPinia } from 'pinia'
52
+
53
+ export const pinia = createPinia()
54
+ ```
55
+
56
+ ### 2️⃣ Utiliser Auth-Kit
57
+
58
+ ```TypeScript
59
+ import { useAuth, useAuthFlowStore } from '@axproo/auth-kit'
60
+ import { pinia } from '@/pinia'
61
+
62
+ const { login } = useAuth()
63
+ const flow = useAuthFlowStore(pinia)
64
+ ```
65
+
66
+ ### 3️⃣ Soumettre le formulaire
67
+
68
+ ```typescript
69
+ const onSubmit = async (data: Record<string, any>) => {
70
+ const ok = await login(pinia, data)
71
+
72
+ if (ok) {
73
+ flow.setStep('dashboard')
74
+ }
75
+ }
76
+ ```
77
+
78
+ ## 🧩 Exemple complet (Login)
79
+
80
+ ```vue
81
+ <template>
82
+ <DynamicForm
83
+ form-id="auth_login"
84
+ :ui="loginSchema"
85
+ @submit="onSubmit"
86
+ form-class="space-y-6"
87
+ >
88
+ <template #spinner>
89
+ <span class="flex items-center justify-center gap-2">
90
+ <Loader :size="20" class="animate-spin" />
91
+ Chargement...
92
+ </span>
93
+ </template>
94
+
95
+ <template #passwordToggleButton="{ toggle, showPassword }">
96
+ <button type="button" @click="toggle">
97
+ <EyeOff v-if="showPassword" />
98
+ <Eye v-else />
99
+ </button>
100
+ </template>
101
+
102
+ <template #submit>
103
+ <button :disabled="flow.isLoading || flow.isLocked">
104
+ <span v-if="flow.isLoading">Connexion...</span>
105
+ <span v-else-if="flow.isLocked">
106
+ Verrouillé {{ flow.lockTimer }}s
107
+ </span>
108
+ <span v-else>Se connecter</span>
109
+ </button>
110
+ </template>
111
+
112
+ <template #errorGlobal="{ error }">
113
+ <ErrorMessage
114
+ v-if="error"
115
+ :message="error"
116
+ :is-locked="flow.isLocked"
117
+ />
118
+ </template>
119
+ </DynamicForm>
120
+ </template>
121
+ ```
122
+
123
+ ## 🧠 Stores disponibles
124
+
125
+ useAuthFlowStore
126
+
127
+ | Propriété | Description |
128
+ | ----------- | ------------------------------------------- |
129
+ | `isLoading` | État de chargement |
130
+ | `isLocked` | Compte temporairement verrouillé |
131
+ | `lockTimer` | Temps restant du verrouillage |
132
+ | `step` | Étape actuelle (`login`, `dashboard`, etc.) |
133
+
134
+ Méthodes
135
+
136
+ ```typescript
137
+ flow.setStep('login' | 'dashboard' | string)
138
+ ```
139
+
140
+ ## 🧩 Slots supportés (DynamicForm)
141
+
142
+ | Slot | Description |
143
+ | ---------------------- | ---------------------------------- |
144
+ | `spinner` | Indicateur de chargement |
145
+ | `passwordToggleButton` | Afficher / masquer le mot de passe |
146
+ | `showLabel` | Label “Se souvenir de moi” |
147
+ | `showPasswordForgot` | Bouton “Mot de passe oublié” |
148
+ | `submit` | Bouton de soumission |
149
+ | `errorGlobal` | Message d’erreur global |
150
+
151
+ ## 🛠 Build
152
+
153
+ ```bash
154
+ npm run build
155
+ ```
156
+
157
+ Génère :
158
+
159
+ * auth-kit.es.js → ESM
160
+ * auth-kit.umd.js → UMD
161
+ * index.d.ts → Types TS
162
+
163
+ ## 🧪 Environnements supportés
164
+
165
+ - Vue 3 SPA
166
+ - Dashboard Admin
167
+ - SaaS
168
+ - Projets modulaires / monorepos
169
+
170
+ ## 📄 Licence
171
+
172
+ MIT © AXPROO
173
+
174
+ ## 🤝 Contribuer
175
+
176
+ Les PR sont bienvenues.
177
+ Merci de respecter la structure TypeScript et Pinia existante.
178
+
179
+ ## 💬 Support
180
+
181
+ Pour toute question ou intégration avancée :
182
+
183
+ 👉 AXPROO Team
@@ -0,0 +1,6 @@
1
+ import { AuthResponse } from '../types/auth.types';
2
+ export declare const authApi: {
3
+ login(payload: any): Promise<AuthResponse>;
4
+ me(): Promise<AuthResponse>;
5
+ logout(): Promise<AuthResponse>;
6
+ };
@@ -0,0 +1,446 @@
1
+ import { useAppErrors as pt, normalizeBackendErrors as dt } from "@axproo/app-core";
2
+ import { hasInjectionContext as B, inject as W, getCurrentInstance as Et, ref as ot, reactive as _t, markRaw as j, effectScope as gt, isRef as A, isReactive as z, toRef as I, toRaw as mt, nextTick as Y, getCurrentScope as vt, onScopeDispose as yt, watch as Nt, computed as nt, toRefs as Z } from "vue";
3
+ const rt = {
4
+ apiBaseUrl: "",
5
+ userKey: "auth_login",
6
+ enableMock: !1
7
+ }, Ct = {
8
+ install(t, r) {
9
+ Object.assign(rt, r);
10
+ }
11
+ };
12
+ async function R(t, r) {
13
+ try {
14
+ const n = await fetch(`${rt.apiBaseUrl}${t}`, {
15
+ credentials: "include",
16
+ headers: {
17
+ "Content-Type": "application/json"
18
+ },
19
+ ...r
20
+ }), s = await n.json().catch(() => ({}));
21
+ return {
22
+ ok: n.ok,
23
+ status: n.status,
24
+ data: s,
25
+ next: s?.next,
26
+ user: s?.data?.user ?? {}
27
+ };
28
+ } catch (n) {
29
+ return {
30
+ ok: !1,
31
+ status: 0,
32
+ data: n
33
+ };
34
+ }
35
+ }
36
+ const J = {
37
+ async login(t) {
38
+ return R("/auth/login", {
39
+ method: "POST",
40
+ body: JSON.stringify(t)
41
+ });
42
+ },
43
+ async me() {
44
+ return R("/auth/me", {
45
+ method: "GET"
46
+ });
47
+ },
48
+ async logout() {
49
+ return R("/auth/logout", {
50
+ method: "POST"
51
+ });
52
+ }
53
+ };
54
+ const P = typeof window < "u";
55
+ let b;
56
+ const L = (t) => b = t;
57
+ process.env.NODE_ENV;
58
+ const H = process.env.NODE_ENV !== "production" ? /* @__PURE__ */ Symbol("pinia") : (
59
+ /* istanbul ignore next */
60
+ /* @__PURE__ */ Symbol()
61
+ );
62
+ function O(t) {
63
+ return t && typeof t == "object" && Object.prototype.toString.call(t) === "[object Object]" && typeof t.toJSON != "function";
64
+ }
65
+ var w;
66
+ (function(t) {
67
+ t.direct = "direct", t.patchObject = "patch object", t.patchFunction = "patch function";
68
+ })(w || (w = {}));
69
+ function ct(t, r) {
70
+ for (const n in r) {
71
+ const s = r[n];
72
+ if (!(n in t))
73
+ continue;
74
+ const i = t[n];
75
+ O(i) && O(s) && !A(s) && !z(s) ? t[n] = ct(i, s) : t[n] = s;
76
+ }
77
+ return t;
78
+ }
79
+ const at = () => {
80
+ };
81
+ function K(t, r, n, s = at) {
82
+ t.add(r);
83
+ const i = () => {
84
+ t.delete(r) && s();
85
+ };
86
+ return !n && vt() && yt(i), i;
87
+ }
88
+ function S(t, ...r) {
89
+ t.forEach((n) => {
90
+ n(...r);
91
+ });
92
+ }
93
+ const bt = (t) => t(), tt = /* @__PURE__ */ Symbol(), F = /* @__PURE__ */ Symbol();
94
+ function M(t, r) {
95
+ t instanceof Map && r instanceof Map ? r.forEach((n, s) => t.set(s, n)) : t instanceof Set && r instanceof Set && r.forEach(t.add, t);
96
+ for (const n in r) {
97
+ if (!r.hasOwnProperty(n))
98
+ continue;
99
+ const s = r[n], i = t[n];
100
+ O(i) && O(s) && t.hasOwnProperty(n) && !A(s) && !z(s) ? t[n] = M(i, s) : t[n] = s;
101
+ }
102
+ return t;
103
+ }
104
+ const Ot = process.env.NODE_ENV !== "production" ? /* @__PURE__ */ Symbol("pinia:skipHydration") : (
105
+ /* istanbul ignore next */
106
+ /* @__PURE__ */ Symbol()
107
+ );
108
+ function kt(t) {
109
+ return !O(t) || !Object.prototype.hasOwnProperty.call(t, Ot);
110
+ }
111
+ const { assign: _ } = Object;
112
+ function et(t) {
113
+ return !!(A(t) && t.effect);
114
+ }
115
+ function st(t, r, n, s) {
116
+ const { state: i, actions: f, getters: a } = r, g = n.state.value[t];
117
+ let N;
118
+ function h() {
119
+ !g && (process.env.NODE_ENV === "production" || !s) && (n.state.value[t] = i ? i() : {});
120
+ const l = process.env.NODE_ENV !== "production" && s ? (
121
+ // use ref() to unwrap refs inside state TODO: check if this is still necessary
122
+ Z(ot(i ? i() : {}).value)
123
+ ) : Z(n.state.value[t]);
124
+ return _(l, f, Object.keys(a || {}).reduce((p, m) => (process.env.NODE_ENV !== "production" && m in l && console.warn(`[🍍]: A getter cannot have the same name as another state property. Rename one of them. Found with "${m}" in store "${t}".`), p[m] = j(nt(() => {
125
+ L(n);
126
+ const v = n._s.get(t);
127
+ return a[m].call(v, v);
128
+ })), p), {}));
129
+ }
130
+ return N = q(t, h, r, n, s, !0), N;
131
+ }
132
+ function q(t, r, n = {}, s, i, f) {
133
+ let a;
134
+ const g = _({ actions: {} }, n);
135
+ if (process.env.NODE_ENV !== "production" && !s._e.active)
136
+ throw new Error("Pinia destroyed");
137
+ const N = { deep: !0 };
138
+ process.env.NODE_ENV !== "production" && (N.onTrigger = (o) => {
139
+ h ? v = o : h == !1 && !c._hotUpdating && (Array.isArray(v) ? v.push(o) : console.error("🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug."));
140
+ });
141
+ let h, l, p = /* @__PURE__ */ new Set(), m = /* @__PURE__ */ new Set(), v;
142
+ const k = s.state.value[t];
143
+ !f && !k && (process.env.NODE_ENV === "production" || !i) && (s.state.value[t] = {});
144
+ const U = ot({});
145
+ let G;
146
+ function Q(o) {
147
+ let e;
148
+ h = l = !1, process.env.NODE_ENV !== "production" && (v = []), typeof o == "function" ? (o(s.state.value[t]), e = {
149
+ type: w.patchFunction,
150
+ storeId: t,
151
+ events: v
152
+ }) : (M(s.state.value[t], o), e = {
153
+ type: w.patchObject,
154
+ payload: o,
155
+ storeId: t,
156
+ events: v
157
+ });
158
+ const u = G = /* @__PURE__ */ Symbol();
159
+ Y().then(() => {
160
+ G === u && (h = !0);
161
+ }), l = !0, S(p, e, s.state.value[t]);
162
+ }
163
+ const ut = f ? function() {
164
+ const { state: e } = n, u = e ? e() : {};
165
+ this.$patch((d) => {
166
+ _(d, u);
167
+ });
168
+ } : (
169
+ /* istanbul ignore next */
170
+ process.env.NODE_ENV !== "production" ? () => {
171
+ throw new Error(`🍍: Store "${t}" is built using the setup syntax and does not implement $reset().`);
172
+ } : at
173
+ );
174
+ function lt() {
175
+ a.stop(), p.clear(), m.clear(), s._s.delete(t);
176
+ }
177
+ const $ = (o, e = "") => {
178
+ if (tt in o)
179
+ return o[F] = e, o;
180
+ const u = function() {
181
+ L(s);
182
+ const d = Array.from(arguments), D = /* @__PURE__ */ new Set(), T = /* @__PURE__ */ new Set();
183
+ function ft(E) {
184
+ D.add(E);
185
+ }
186
+ function ht(E) {
187
+ T.add(E);
188
+ }
189
+ S(m, {
190
+ args: d,
191
+ name: u[F],
192
+ store: c,
193
+ after: ft,
194
+ onError: ht
195
+ });
196
+ let V;
197
+ try {
198
+ V = o.apply(this && this.$id === t ? this : c, d);
199
+ } catch (E) {
200
+ throw S(T, E), E;
201
+ }
202
+ return V instanceof Promise ? V.then((E) => (S(D, E), E)).catch((E) => (S(T, E), Promise.reject(E))) : (S(D, V), V);
203
+ };
204
+ return u[tt] = !0, u[F] = e, u;
205
+ }, C = /* @__PURE__ */ j({
206
+ actions: {},
207
+ getters: {},
208
+ state: [],
209
+ hotState: U
210
+ }), X = {
211
+ _p: s,
212
+ // _s: scope,
213
+ $id: t,
214
+ $onAction: K.bind(null, m),
215
+ $patch: Q,
216
+ $reset: ut,
217
+ $subscribe(o, e = {}) {
218
+ const u = K(p, o, e.detached, () => d()), d = a.run(() => Nt(() => s.state.value[t], (D) => {
219
+ (e.flush === "sync" ? l : h) && o({
220
+ storeId: t,
221
+ type: w.direct,
222
+ events: v
223
+ }, D);
224
+ }, _({}, N, e)));
225
+ return u;
226
+ },
227
+ $dispose: lt
228
+ }, c = _t(process.env.NODE_ENV !== "production" || process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test" && P ? _(
229
+ {
230
+ _hmrPayload: C,
231
+ _customProperties: j(/* @__PURE__ */ new Set())
232
+ // devtools custom properties
233
+ },
234
+ X
235
+ // must be added later
236
+ // setupStore
237
+ ) : X);
238
+ s._s.set(t, c);
239
+ const y = (s._a && s._a.runWithContext || bt)(() => s._e.run(() => (a = gt()).run(() => r({ action: $ }))));
240
+ for (const o in y) {
241
+ const e = y[o];
242
+ if (A(e) && !et(e) || z(e))
243
+ process.env.NODE_ENV !== "production" && i ? U.value[o] = I(y, o) : f || (k && kt(e) && (A(e) ? e.value = k[o] : M(e, k[o])), s.state.value[t][o] = e), process.env.NODE_ENV !== "production" && C.state.push(o);
244
+ else if (typeof e == "function") {
245
+ const u = process.env.NODE_ENV !== "production" && i ? e : $(e, o);
246
+ y[o] = u, process.env.NODE_ENV !== "production" && (C.actions[o] = e), g.actions[o] = e;
247
+ } else process.env.NODE_ENV !== "production" && et(e) && (C.getters[o] = f ? (
248
+ // @ts-expect-error
249
+ n.getters[o]
250
+ ) : e, P && (y._getters || // @ts-expect-error: same
251
+ (y._getters = j([]))).push(o));
252
+ }
253
+ if (_(c, y), _(mt(c), y), Object.defineProperty(c, "$state", {
254
+ get: () => process.env.NODE_ENV !== "production" && i ? U.value : s.state.value[t],
255
+ set: (o) => {
256
+ if (process.env.NODE_ENV !== "production" && i)
257
+ throw new Error("cannot set hotState");
258
+ Q((e) => {
259
+ _(e, o);
260
+ });
261
+ }
262
+ }), process.env.NODE_ENV !== "production" && (c._hotUpdate = j((o) => {
263
+ c._hotUpdating = !0, o._hmrPayload.state.forEach((e) => {
264
+ if (e in c.$state) {
265
+ const u = o.$state[e], d = c.$state[e];
266
+ typeof u == "object" && O(u) && O(d) ? ct(u, d) : o.$state[e] = d;
267
+ }
268
+ c[e] = I(o.$state, e);
269
+ }), Object.keys(c.$state).forEach((e) => {
270
+ e in o.$state || delete c[e];
271
+ }), h = !1, l = !1, s.state.value[t] = I(o._hmrPayload, "hotState"), l = !0, Y().then(() => {
272
+ h = !0;
273
+ });
274
+ for (const e in o._hmrPayload.actions) {
275
+ const u = o[e];
276
+ c[e] = //
277
+ $(u, e);
278
+ }
279
+ for (const e in o._hmrPayload.getters) {
280
+ const u = o._hmrPayload.getters[e], d = f ? (
281
+ // special handling of options api
282
+ nt(() => (L(s), u.call(c, c)))
283
+ ) : u;
284
+ c[e] = //
285
+ d;
286
+ }
287
+ Object.keys(c._hmrPayload.getters).forEach((e) => {
288
+ e in o._hmrPayload.getters || delete c[e];
289
+ }), Object.keys(c._hmrPayload.actions).forEach((e) => {
290
+ e in o._hmrPayload.actions || delete c[e];
291
+ }), c._hmrPayload = o._hmrPayload, c._getters = o._getters, c._hotUpdating = !1;
292
+ })), process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test" && P) {
293
+ const o = {
294
+ writable: !0,
295
+ configurable: !0,
296
+ // avoid warning on devtools trying to display this property
297
+ enumerable: !1
298
+ };
299
+ ["_p", "_hmrPayload", "_getters", "_customProperties"].forEach((e) => {
300
+ Object.defineProperty(c, e, _({ value: c[e] }, o));
301
+ });
302
+ }
303
+ return s._p.forEach((o) => {
304
+ if (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test" && P) {
305
+ const e = a.run(() => o({
306
+ store: c,
307
+ app: s._a,
308
+ pinia: s,
309
+ options: g
310
+ }));
311
+ Object.keys(e || {}).forEach((u) => c._customProperties.add(u)), _(c, e);
312
+ } else
313
+ _(c, a.run(() => o({
314
+ store: c,
315
+ app: s._a,
316
+ pinia: s,
317
+ options: g
318
+ })));
319
+ }), process.env.NODE_ENV !== "production" && c.$state && typeof c.$state == "object" && typeof c.$state.constructor == "function" && !c.$state.constructor.toString().includes("[native code]") && console.warn(`[🍍]: The "state" must be a plain object. It cannot be
320
+ state: () => new MyClass()
321
+ Found in store "${c.$id}".`), k && f && n.hydrate && n.hydrate(c.$state, k), h = !0, l = !0, c;
322
+ }
323
+ // @__NO_SIDE_EFFECTS__
324
+ function it(t, r, n) {
325
+ let s;
326
+ const i = typeof r == "function";
327
+ s = i ? n : r;
328
+ function f(a, g) {
329
+ const N = B();
330
+ if (a = // in test mode, ignore the argument provided as we can always retrieve a
331
+ // pinia instance with getActivePinia()
332
+ (process.env.NODE_ENV === "test" && b && b._testing ? null : a) || (N ? W(H, null) : null), a && L(a), process.env.NODE_ENV !== "production" && !b)
333
+ throw new Error(`[🍍]: "getActivePinia()" was called but there was no active Pinia. Are you trying to use a store before calling "app.use(pinia)"?
334
+ See https://pinia.vuejs.org/core-concepts/outside-component-usage.html for help.
335
+ This will fail in production.`);
336
+ a = b, a._s.has(t) || (i ? q(t, r, s, a) : st(t, s, a), process.env.NODE_ENV !== "production" && (f._pinia = a));
337
+ const h = a._s.get(t);
338
+ if (process.env.NODE_ENV !== "production" && g) {
339
+ const l = "__hot:" + t, p = i ? q(l, r, s, a, !0) : st(l, _({}, s), a, !0);
340
+ g._hotUpdate(p), delete a.state.value[l], a._s.delete(l);
341
+ }
342
+ if (process.env.NODE_ENV !== "production" && P) {
343
+ const l = Et();
344
+ if (l && l.proxy && // avoid adding stores that are just built for hot module replacement
345
+ !g) {
346
+ const p = l.proxy, m = "_pStores" in p ? p._pStores : p._pStores = {};
347
+ m[t] = h;
348
+ }
349
+ }
350
+ return h;
351
+ }
352
+ return f.$id = t, f;
353
+ }
354
+ const St = /* @__PURE__ */ it("auth-flow", {
355
+ state: () => ({
356
+ isLoading: !1,
357
+ isLocked: !1,
358
+ lockTimer: 0,
359
+ loginAttempts: 0,
360
+ step: "login"
361
+ }),
362
+ actions: {
363
+ registerOnUnlock(t) {
364
+ this.onUnlock = t;
365
+ },
366
+ startLoading() {
367
+ this.isLoading = !0;
368
+ },
369
+ stopLoading() {
370
+ this.isLoading = !1;
371
+ },
372
+ failAttempt() {
373
+ this.loginAttempts++;
374
+ },
375
+ lockFromBackend(t) {
376
+ this.isLocked = !0, this.lockTimer = t;
377
+ const r = setInterval(() => {
378
+ this.lockTimer--, this.lockTimer <= 0 && (clearInterval(r), this.unLock());
379
+ }, 1e3);
380
+ },
381
+ unLock() {
382
+ this.isLocked = !1, this.loginAttempts = 0, this.lockTimer = 0, this.onUnlock?.();
383
+ },
384
+ setStep(t) {
385
+ this.step = t;
386
+ }
387
+ }
388
+ }), x = /* @__PURE__ */ it("auth", {
389
+ state: () => ({
390
+ user: null,
391
+ isAuthenticated: !1,
392
+ checked: !1
393
+ }),
394
+ actions: {
395
+ // Connexion
396
+ setUser(t) {
397
+ this.user = t, this.isAuthenticated = !0, this.checked = !0;
398
+ },
399
+ logout() {
400
+ this.user = null, this.isAuthenticated = !1, this.checked = !0;
401
+ }
402
+ }
403
+ });
404
+ async function Pt(t, r, n = "auth_login") {
405
+ const s = pt(), i = St(t), f = x(t);
406
+ if (i.registerOnUnlock(() => s.clear(n)), i.isLocked) return !1;
407
+ s.clear(n), i.startLoading();
408
+ const a = await J.login(r);
409
+ if (i.stopLoading(), !a?.ok) {
410
+ const g = dt(a.data);
411
+ return a.data?.code === "AUTH_ACCOUNT_LOCKED" && a.data?.remaining ? i.lockFromBackend(a.data?.remaining) : i.failAttempt(), s.setFromBackend(n, g), !1;
412
+ }
413
+ return a?.next ? (console.log("response success", a?.next), a?.user && f.setUser(a.user), i.setStep(a?.next), s.clear(n), !0) : !1;
414
+ }
415
+ async function Dt(t) {
416
+ const r = x(t);
417
+ try {
418
+ const n = await J.me();
419
+ return !n.ok || !n?.user ? (r.logout(), !1) : (r.setUser(n.user), !0);
420
+ } catch {
421
+ return r.logout(), !1;
422
+ }
423
+ }
424
+ async function Vt(t) {
425
+ const r = x(t);
426
+ try {
427
+ return (await J.logout()).ok && r.logout(), !0;
428
+ } catch {
429
+ return !1;
430
+ }
431
+ }
432
+ function Lt() {
433
+ return {
434
+ ...x(),
435
+ login: Pt,
436
+ me: Dt,
437
+ logout: Vt
438
+ };
439
+ }
440
+ export {
441
+ Ct as AuthKit,
442
+ rt as authConfig,
443
+ Lt as useAuth,
444
+ St as useAuthFlowStore,
445
+ x as useAuthState
446
+ };
@@ -0,0 +1,5 @@
1
+ (function(d,P){typeof exports=="object"&&typeof module<"u"?P(exports,require("@axproo/app-core"),require("vue")):typeof define=="function"&&define.amd?define(["exports","@axproo/app-core","vue"],P):(d=typeof globalThis<"u"?globalThis:d||self,P(d.AuthKit={},d.AppCore,d.Vue))})(this,(function(d,P,a){"use strict";const T={apiBaseUrl:"",userKey:"auth_login",enableMock:!1},ot={install(t,r){Object.assign(T,r)}};async function U(t,r){try{const n=await fetch(`${T.apiBaseUrl}${t}`,{credentials:"include",headers:{"Content-Type":"application/json"},...r}),s=await n.json().catch(()=>({}));return{ok:n.ok,status:n.status,data:s,next:s?.next,user:s?.data?.user??{}}}catch(n){return{ok:!1,status:0,data:n}}}const $={async login(t){return U("/auth/login",{method:"POST",body:JSON.stringify(t)})},async me(){return U("/auth/me",{method:"GET"})},async logout(){return U("/auth/logout",{method:"POST"})}};const V=typeof window<"u";let k;const x=t=>k=t;process.env.NODE_ENV;const I=process.env.NODE_ENV!=="production"?Symbol("pinia"):Symbol();function v(t){return t&&typeof t=="object"&&Object.prototype.toString.call(t)==="[object Object]"&&typeof t.toJSON!="function"}var w;(function(t){t.direct="direct",t.patchObject="patch object",t.patchFunction="patch function"})(w||(w={}));function z(t,r){for(const n in r){const s=r[n];if(!(n in t))continue;const u=t[n];v(u)&&v(s)&&!a.isRef(s)&&!a.isReactive(s)?t[n]=z(u,s):t[n]=s}return t}const J=()=>{};function G(t,r,n,s=J){t.add(r);const u=()=>{t.delete(r)&&s()};return!n&&a.getCurrentScope()&&a.onScopeDispose(u),u}function j(t,...r){t.forEach(n=>{n(...r)})}const nt=t=>t(),K=Symbol(),F=Symbol();function B(t,r){t instanceof Map&&r instanceof Map?r.forEach((n,s)=>t.set(s,n)):t instanceof Set&&r instanceof Set&&r.forEach(t.add,t);for(const n in r){if(!r.hasOwnProperty(n))continue;const s=r[n],u=t[n];v(u)&&v(s)&&t.hasOwnProperty(n)&&!a.isRef(s)&&!a.isReactive(s)?t[n]=B(u,s):t[n]=s}return t}const rt=process.env.NODE_ENV!=="production"?Symbol("pinia:skipHydration"):Symbol();function ct(t){return!v(t)||!Object.prototype.hasOwnProperty.call(t,rt)}const{assign:E}=Object;function Q(t){return!!(a.isRef(t)&&t.effect)}function X(t,r,n,s){const{state:u,actions:h,getters:i}=r,y=n.state.value[t];let S;function p(){!y&&(process.env.NODE_ENV==="production"||!s)&&(n.state.value[t]=u?u():{});const f=process.env.NODE_ENV!=="production"&&s?a.toRefs(a.ref(u?u():{}).value):a.toRefs(n.state.value[t]);return E(f,h,Object.keys(i||{}).reduce((_,N)=>(process.env.NODE_ENV!=="production"&&N in f&&console.warn(`[🍍]: A getter cannot have the same name as another state property. Rename one of them. Found with "${N}" in store "${t}".`),_[N]=a.markRaw(a.computed(()=>{x(n);const b=n._s.get(t);return i[N].call(b,b)})),_),{}))}return S=M(t,p,r,n,s,!0),S}function M(t,r,n={},s,u,h){let i;const y=E({actions:{}},n);if(process.env.NODE_ENV!=="production"&&!s._e.active)throw new Error("Pinia destroyed");const S={deep:!0};process.env.NODE_ENV!=="production"&&(S.onTrigger=o=>{p?b=o:p==!1&&!c._hotUpdating&&(Array.isArray(b)?b.push(o):console.error("🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug."))});let p,f,_=new Set,N=new Set,b;const D=s.state.value[t];!h&&!D&&(process.env.NODE_ENV==="production"||!u)&&(s.state.value[t]={});const W=a.ref({});let tt;function et(o){let e;p=f=!1,process.env.NODE_ENV!=="production"&&(b=[]),typeof o=="function"?(o(s.state.value[t]),e={type:w.patchFunction,storeId:t,events:b}):(B(s.state.value[t],o),e={type:w.patchObject,payload:o,storeId:t,events:b});const l=tt=Symbol();a.nextTick().then(()=>{tt===l&&(p=!0)}),f=!0,j(_,e,s.state.value[t])}const ft=h?function(){const{state:e}=n,l=e?e():{};this.$patch(g=>{E(g,l)})}:process.env.NODE_ENV!=="production"?()=>{throw new Error(`🍍: Store "${t}" is built using the setup syntax and does not implement $reset().`)}:J;function ht(){i.stop(),_.clear(),N.clear(),s._s.delete(t)}const q=(o,e="")=>{if(K in o)return o[F]=e,o;const l=function(){x(s);const g=Array.from(arguments),R=new Set,H=new Set;function pt(m){R.add(m)}function dt(m){H.add(m)}j(N,{args:g,name:l[F],store:c,after:pt,onError:dt});let C;try{C=o.apply(this&&this.$id===t?this:c,g)}catch(m){throw j(H,m),m}return C instanceof Promise?C.then(m=>(j(R,m),m)).catch(m=>(j(H,m),Promise.reject(m))):(j(R,C),C)};return l[K]=!0,l[F]=e,l},L=a.markRaw({actions:{},getters:{},state:[],hotState:W}),st={_p:s,$id:t,$onAction:G.bind(null,N),$patch:et,$reset:ft,$subscribe(o,e={}){const l=G(_,o,e.detached,()=>g()),g=i.run(()=>a.watch(()=>s.state.value[t],R=>{(e.flush==="sync"?f:p)&&o({storeId:t,type:w.direct,events:b},R)},E({},S,e)));return l},$dispose:ht},c=a.reactive(process.env.NODE_ENV!=="production"||process.env.NODE_ENV!=="production"&&process.env.NODE_ENV!=="test"&&V?E({_hmrPayload:L,_customProperties:a.markRaw(new Set)},st):st);s._s.set(t,c);const O=(s._a&&s._a.runWithContext||nt)(()=>s._e.run(()=>(i=a.effectScope()).run(()=>r({action:q}))));for(const o in O){const e=O[o];if(a.isRef(e)&&!Q(e)||a.isReactive(e))process.env.NODE_ENV!=="production"&&u?W.value[o]=a.toRef(O,o):h||(D&&ct(e)&&(a.isRef(e)?e.value=D[o]:B(e,D[o])),s.state.value[t][o]=e),process.env.NODE_ENV!=="production"&&L.state.push(o);else if(typeof e=="function"){const l=process.env.NODE_ENV!=="production"&&u?e:q(e,o);O[o]=l,process.env.NODE_ENV!=="production"&&(L.actions[o]=e),y.actions[o]=e}else process.env.NODE_ENV!=="production"&&Q(e)&&(L.getters[o]=h?n.getters[o]:e,V&&(O._getters||(O._getters=a.markRaw([]))).push(o))}if(E(c,O),E(a.toRaw(c),O),Object.defineProperty(c,"$state",{get:()=>process.env.NODE_ENV!=="production"&&u?W.value:s.state.value[t],set:o=>{if(process.env.NODE_ENV!=="production"&&u)throw new Error("cannot set hotState");et(e=>{E(e,o)})}}),process.env.NODE_ENV!=="production"&&(c._hotUpdate=a.markRaw(o=>{c._hotUpdating=!0,o._hmrPayload.state.forEach(e=>{if(e in c.$state){const l=o.$state[e],g=c.$state[e];typeof l=="object"&&v(l)&&v(g)?z(l,g):o.$state[e]=g}c[e]=a.toRef(o.$state,e)}),Object.keys(c.$state).forEach(e=>{e in o.$state||delete c[e]}),p=!1,f=!1,s.state.value[t]=a.toRef(o._hmrPayload,"hotState"),f=!0,a.nextTick().then(()=>{p=!0});for(const e in o._hmrPayload.actions){const l=o[e];c[e]=q(l,e)}for(const e in o._hmrPayload.getters){const l=o._hmrPayload.getters[e],g=h?a.computed(()=>(x(s),l.call(c,c))):l;c[e]=g}Object.keys(c._hmrPayload.getters).forEach(e=>{e in o._hmrPayload.getters||delete c[e]}),Object.keys(c._hmrPayload.actions).forEach(e=>{e in o._hmrPayload.actions||delete c[e]}),c._hmrPayload=o._hmrPayload,c._getters=o._getters,c._hotUpdating=!1})),process.env.NODE_ENV!=="production"&&process.env.NODE_ENV!=="test"&&V){const o={writable:!0,configurable:!0,enumerable:!1};["_p","_hmrPayload","_getters","_customProperties"].forEach(e=>{Object.defineProperty(c,e,E({value:c[e]},o))})}return s._p.forEach(o=>{if(process.env.NODE_ENV!=="production"&&process.env.NODE_ENV!=="test"&&V){const e=i.run(()=>o({store:c,app:s._a,pinia:s,options:y}));Object.keys(e||{}).forEach(l=>c._customProperties.add(l)),E(c,e)}else E(c,i.run(()=>o({store:c,app:s._a,pinia:s,options:y})))}),process.env.NODE_ENV!=="production"&&c.$state&&typeof c.$state=="object"&&typeof c.$state.constructor=="function"&&!c.$state.constructor.toString().includes("[native code]")&&console.warn(`[🍍]: The "state" must be a plain object. It cannot be
2
+ state: () => new MyClass()
3
+ Found in store "${c.$id}".`),D&&h&&n.hydrate&&n.hydrate(c.$state,D),p=!0,f=!0,c}function Y(t,r,n){let s;const u=typeof r=="function";s=u?n:r;function h(i,y){const S=a.hasInjectionContext();if(i=(process.env.NODE_ENV==="test"&&k&&k._testing?null:i)||(S?a.inject(I,null):null),i&&x(i),process.env.NODE_ENV!=="production"&&!k)throw new Error(`[🍍]: "getActivePinia()" was called but there was no active Pinia. Are you trying to use a store before calling "app.use(pinia)"?
4
+ See https://pinia.vuejs.org/core-concepts/outside-component-usage.html for help.
5
+ This will fail in production.`);i=k,i._s.has(t)||(u?M(t,r,s,i):X(t,s,i),process.env.NODE_ENV!=="production"&&(h._pinia=i));const p=i._s.get(t);if(process.env.NODE_ENV!=="production"&&y){const f="__hot:"+t,_=u?M(f,r,s,i,!0):X(f,E({},s),i,!0);y._hotUpdate(_),delete i.state.value[f],i._s.delete(f)}if(process.env.NODE_ENV!=="production"&&V){const f=a.getCurrentInstance();if(f&&f.proxy&&!y){const _=f.proxy,N="_pStores"in _?_._pStores:_._pStores={};N[t]=p}}return p}return h.$id=t,h}const Z=Y("auth-flow",{state:()=>({isLoading:!1,isLocked:!1,lockTimer:0,loginAttempts:0,step:"login"}),actions:{registerOnUnlock(t){this.onUnlock=t},startLoading(){this.isLoading=!0},stopLoading(){this.isLoading=!1},failAttempt(){this.loginAttempts++},lockFromBackend(t){this.isLocked=!0,this.lockTimer=t;const r=setInterval(()=>{this.lockTimer--,this.lockTimer<=0&&(clearInterval(r),this.unLock())},1e3)},unLock(){this.isLocked=!1,this.loginAttempts=0,this.lockTimer=0,this.onUnlock?.()},setStep(t){this.step=t}}}),A=Y("auth",{state:()=>({user:null,isAuthenticated:!1,checked:!1}),actions:{setUser(t){this.user=t,this.isAuthenticated=!0,this.checked=!0},logout(){this.user=null,this.isAuthenticated=!1,this.checked=!0}}});async function at(t,r,n="auth_login"){const s=P.useAppErrors(),u=Z(t),h=A(t);if(u.registerOnUnlock(()=>s.clear(n)),u.isLocked)return!1;s.clear(n),u.startLoading();const i=await $.login(r);if(u.stopLoading(),!i?.ok){const y=P.normalizeBackendErrors(i.data);return i.data?.code==="AUTH_ACCOUNT_LOCKED"&&i.data?.remaining?u.lockFromBackend(i.data?.remaining):u.failAttempt(),s.setFromBackend(n,y),!1}return i?.next?(console.log("response success",i?.next),i?.user&&h.setUser(i.user),u.setStep(i?.next),s.clear(n),!0):!1}async function it(t){const r=A(t);try{const n=await $.me();return!n.ok||!n?.user?(r.logout(),!1):(r.setUser(n.user),!0)}catch{return r.logout(),!1}}async function ut(t){const r=A(t);try{return(await $.logout()).ok&&r.logout(),!0}catch{return!1}}function lt(){return{...A(),login:at,me:it,logout:ut}}d.AuthKit=ot,d.authConfig=T,d.useAuth=lt,d.useAuthFlowStore=Z,d.useAuthState=A,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
@@ -0,0 +1,68 @@
1
+ import { login, logout, me } from '../services/auth.service';
2
+ export declare function useAuth(): {
3
+ login: typeof login;
4
+ me: typeof me;
5
+ logout: typeof logout;
6
+ $state: {
7
+ user: {
8
+ id: number | string;
9
+ email?: string | undefined;
10
+ name?: string | undefined;
11
+ isActivated: boolean;
12
+ } | null;
13
+ isAuthenticated: boolean;
14
+ checked: boolean;
15
+ } & import('pinia').PiniaCustomStateProperties<{
16
+ user: import('..').User | null;
17
+ isAuthenticated: boolean;
18
+ checked: boolean;
19
+ }>;
20
+ $patch(partialState: import('pinia')._DeepPartial<{
21
+ user: {
22
+ id: number | string;
23
+ email?: string | undefined;
24
+ name?: string | undefined;
25
+ isActivated: boolean;
26
+ } | null;
27
+ isAuthenticated: boolean;
28
+ checked: boolean;
29
+ }>): void;
30
+ $patch<F extends (state: {
31
+ user: {
32
+ id: number | string;
33
+ email?: string | undefined;
34
+ name?: string | undefined;
35
+ isActivated: boolean;
36
+ } | null;
37
+ isAuthenticated: boolean;
38
+ checked: boolean;
39
+ }) => any>(stateMutator: ReturnType<F> extends Promise<any> ? never : F): void;
40
+ $reset(): void;
41
+ $subscribe(callback: import('pinia').SubscriptionCallback<{
42
+ user: import('..').User | null;
43
+ isAuthenticated: boolean;
44
+ checked: boolean;
45
+ }>, options?: {
46
+ detached?: boolean;
47
+ } & import('vue').WatchOptions): () => void;
48
+ $onAction(callback: import('pinia').StoreOnActionListener<"auth", {
49
+ user: import('..').User | null;
50
+ isAuthenticated: boolean;
51
+ checked: boolean;
52
+ }, {}, {
53
+ setUser(user: import('..').User | null): void;
54
+ logout(): void;
55
+ }>, detached?: boolean): () => void;
56
+ $dispose(): void;
57
+ $id: "auth";
58
+ _customProperties: Set<string>;
59
+ user: {
60
+ id: number | string;
61
+ email?: string | undefined;
62
+ name?: string | undefined;
63
+ isActivated: boolean;
64
+ } | null;
65
+ isAuthenticated: boolean;
66
+ checked: boolean;
67
+ setUser(user: import('..').User | null): void;
68
+ };
@@ -0,0 +1,14 @@
1
+ import { AuthFlowState, AuthStep } from '../types/auth.types';
2
+ type UnlockCallback = () => void;
3
+ export declare const useAuthFlowStore: import('pinia').StoreDefinition<"auth-flow", AuthFlowState & {
4
+ onUnlock?: UnlockCallback;
5
+ }, {}, {
6
+ registerOnUnlock(cb: UnlockCallback): void;
7
+ startLoading(): void;
8
+ stopLoading(): void;
9
+ failAttempt(): void;
10
+ lockFromBackend(duration: number): void;
11
+ unLock(): void;
12
+ setStep(step: AuthStep): void;
13
+ }>;
14
+ export {};
@@ -0,0 +1,5 @@
1
+ export declare const authConfig: {
2
+ apiBaseUrl: string;
3
+ userKey: string;
4
+ enableMock: boolean;
5
+ };
File without changes
@@ -0,0 +1,6 @@
1
+ export { AuthKit } from './plugins/AuthKit';
2
+ export { authConfig } from './config/auth.config';
3
+ export { useAuth } from './composables/useAuth';
4
+ export { useAuthState } from './stores/useAuthState';
5
+ export { useAuthFlowStore } from './composables/useAuthFlow';
6
+ export * from './types/auth.types';
@@ -0,0 +1,5 @@
1
+ import { App } from 'vue';
2
+ import { authConfig } from '../config/auth.config';
3
+ export declare const AuthKit: {
4
+ install(app: App, options?: Partial<typeof authConfig>): void;
5
+ };
@@ -0,0 +1,4 @@
1
+ import { Pinia } from 'pinia';
2
+ export declare function login(pinia: Pinia, payload: any, formId?: string): Promise<boolean>;
3
+ export declare function me(pinia: Pinia): Promise<boolean>;
4
+ export declare function logout(pinia: Pinia): Promise<boolean>;
@@ -0,0 +1,9 @@
1
+ import { User } from '../types/auth.types';
2
+ export declare const useAuthState: import('pinia').StoreDefinition<"auth", {
3
+ user: User | null;
4
+ isAuthenticated: boolean;
5
+ checked: boolean;
6
+ }, {}, {
7
+ setUser(user: User | null): void;
8
+ logout(): void;
9
+ }>;
@@ -0,0 +1,23 @@
1
+ export type AuthErrorCode = 'AUTH_INVALID_CREDENTIALS' | 'AUTH_ACCOUNT_LOCKED' | 'AUTH_REQUIRES_2FA' | 'AUTH_SUCCESS' | 'HTTP_401' | 'HTTP_403' | 'HTTP_404' | 'HTTP_422' | 'HTTP_500' | 'AUTH_REQUEST_FAILED';
2
+ export interface AuthResponse {
3
+ ok: boolean;
4
+ code?: AuthErrorCode;
5
+ status?: number;
6
+ data?: any;
7
+ next?: AuthStep;
8
+ user?: User;
9
+ }
10
+ export type AuthStep = 'login' | 'activation' | 'twofactor' | 'dashboard' | 'success' | 'verify' | 'forgot' | 'reset';
11
+ export interface AuthFlowState {
12
+ isLoading: boolean;
13
+ isLocked: boolean;
14
+ lockTimer: number;
15
+ loginAttempts: number;
16
+ step: AuthStep;
17
+ }
18
+ export interface User {
19
+ id: number | string;
20
+ email?: string;
21
+ name?: string;
22
+ isActivated: boolean;
23
+ }
@@ -0,0 +1,14 @@
1
+ export declare class AuthHttpError extends Error {
2
+ status?: number;
3
+ code?: string;
4
+ rawMessage?: string;
5
+ locked?: boolean;
6
+ retryAfter?: number;
7
+ constructor(params: {
8
+ status: number;
9
+ code?: string;
10
+ message?: string;
11
+ locked?: boolean;
12
+ retryAfter?: number;
13
+ });
14
+ }
package/dist/vite.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@axproo/auth-kit",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "main": "./dist/auth-kit.umd.js",
6
+ "module": "./dist/auth-kit.es.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/auth-kit.es.js",
11
+ "types": "./dist/index.d.ts",
12
+ "require": "./dist/auth-kit.umd.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "vite build"
20
+ },
21
+ "peerDependencies": {
22
+ "@axproo/app-core": "^0.1.0",
23
+ "vue": "^3.5.0",
24
+ "vite": "^7.2.4",
25
+ "pinia": "3.0.4"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^24.10.1",
29
+ "@vitejs/plugin-vue": "^6.0.1",
30
+ "@vue/tsconfig": "^0.8.1",
31
+ "typescript": "~5.9.3",
32
+ "vite-plugin-dts": "^4.5.4",
33
+ "vue-tsc": "^3.1.4",
34
+ "pinia": "3.0.4"
35
+ }
36
+ }