@seifer-webapp-factory/authentication 0.1.0

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.
Files changed (113) hide show
  1. package/README.md +8 -0
  2. package/backend/templates/config/config-fragment.ts +73 -0
  3. package/backend/templates/mail/templates.ts +84 -0
  4. package/backend/templates/nestjs/auth.controller.ts +274 -0
  5. package/backend/templates/nestjs/auth.module.ts +207 -0
  6. package/backend/templates/nestjs/tokens.ts +24 -0
  7. package/backend/templates/persistence/migrations/0001_auth.sql +36 -0
  8. package/backend/templates/persistence/migrations/index.ts +75 -0
  9. package/backend/templates/persistence/pg-single-use-store.ts +64 -0
  10. package/backend/templates/persistence/pg-token-store.ts +75 -0
  11. package/backend/templates/persistence/pg-user-store.ts +53 -0
  12. package/backend/templates/security/cookies.ts +89 -0
  13. package/backend/templates/security/csrf.ts +44 -0
  14. package/backend/templates/security/headers.ts +30 -0
  15. package/backend/templates/security/redaction.ts +38 -0
  16. package/dist/backend/src/errors.d.ts +12 -0
  17. package/dist/backend/src/errors.d.ts.map +1 -0
  18. package/dist/backend/src/errors.js +55 -0
  19. package/dist/backend/src/errors.js.map +1 -0
  20. package/dist/backend/src/index.d.ts +9 -0
  21. package/dist/backend/src/index.d.ts.map +1 -0
  22. package/dist/backend/src/index.js +8 -0
  23. package/dist/backend/src/index.js.map +1 -0
  24. package/dist/backend/src/ports.d.ts +60 -0
  25. package/dist/backend/src/ports.d.ts.map +1 -0
  26. package/dist/backend/src/ports.js +2 -0
  27. package/dist/backend/src/ports.js.map +1 -0
  28. package/dist/backend/src/services.d.ts +49 -0
  29. package/dist/backend/src/services.d.ts.map +1 -0
  30. package/dist/backend/src/services.js +178 -0
  31. package/dist/backend/src/services.js.map +1 -0
  32. package/dist/contract/endpoints.d.ts +259 -0
  33. package/dist/contract/endpoints.d.ts.map +1 -0
  34. package/dist/contract/endpoints.js +42 -0
  35. package/dist/contract/endpoints.js.map +1 -0
  36. package/dist/contract/errors.d.ts +23 -0
  37. package/dist/contract/errors.d.ts.map +1 -0
  38. package/dist/contract/errors.js +31 -0
  39. package/dist/contract/errors.js.map +1 -0
  40. package/dist/contract/events.d.ts +40 -0
  41. package/dist/contract/events.d.ts.map +1 -0
  42. package/dist/contract/events.js +14 -0
  43. package/dist/contract/events.js.map +1 -0
  44. package/dist/contract/index.d.ts +9 -0
  45. package/dist/contract/index.d.ts.map +1 -0
  46. package/dist/contract/index.js +9 -0
  47. package/dist/contract/index.js.map +1 -0
  48. package/dist/contract/schemas.d.ts +150 -0
  49. package/dist/contract/schemas.d.ts.map +1 -0
  50. package/dist/contract/schemas.js +43 -0
  51. package/dist/contract/schemas.js.map +1 -0
  52. package/dist/frontend/src/client.d.ts +38 -0
  53. package/dist/frontend/src/client.d.ts.map +1 -0
  54. package/dist/frontend/src/client.js +88 -0
  55. package/dist/frontend/src/client.js.map +1 -0
  56. package/dist/frontend/src/composables.d.ts +46 -0
  57. package/dist/frontend/src/composables.d.ts.map +1 -0
  58. package/dist/frontend/src/composables.js +111 -0
  59. package/dist/frontend/src/composables.js.map +1 -0
  60. package/dist/frontend/src/guards.d.ts +10 -0
  61. package/dist/frontend/src/guards.d.ts.map +1 -0
  62. package/dist/frontend/src/guards.js +9 -0
  63. package/dist/frontend/src/guards.js.map +1 -0
  64. package/dist/frontend/src/index.d.ts +12 -0
  65. package/dist/frontend/src/index.d.ts.map +1 -0
  66. package/dist/frontend/src/index.js +9 -0
  67. package/dist/frontend/src/index.js.map +1 -0
  68. package/dist/manifest.d.ts +80 -0
  69. package/dist/manifest.d.ts.map +1 -0
  70. package/dist/manifest.js +126 -0
  71. package/dist/manifest.js.map +1 -0
  72. package/dist/scaffolder/core/config.d.ts +213 -0
  73. package/dist/scaffolder/core/config.d.ts.map +1 -0
  74. package/dist/scaffolder/core/config.js +132 -0
  75. package/dist/scaffolder/core/config.js.map +1 -0
  76. package/dist/scaffolder/core/errors.d.ts +37 -0
  77. package/dist/scaffolder/core/errors.d.ts.map +1 -0
  78. package/dist/scaffolder/core/errors.js +46 -0
  79. package/dist/scaffolder/core/errors.js.map +1 -0
  80. package/dist/scaffolder/core/extend.d.ts +115 -0
  81. package/dist/scaffolder/core/extend.d.ts.map +1 -0
  82. package/dist/scaffolder/core/extend.js +116 -0
  83. package/dist/scaffolder/core/extend.js.map +1 -0
  84. package/dist/scaffolder/core/materialize.d.ts +71 -0
  85. package/dist/scaffolder/core/materialize.d.ts.map +1 -0
  86. package/dist/scaffolder/core/materialize.js +47 -0
  87. package/dist/scaffolder/core/materialize.js.map +1 -0
  88. package/dist/scaffolder/core/ports.d.ts +39 -0
  89. package/dist/scaffolder/core/ports.d.ts.map +1 -0
  90. package/dist/scaffolder/core/ports.js +33 -0
  91. package/dist/scaffolder/core/ports.js.map +1 -0
  92. package/dist/scaffolder/core/three-way-merge.d.ts +113 -0
  93. package/dist/scaffolder/core/three-way-merge.d.ts.map +1 -0
  94. package/dist/scaffolder/core/three-way-merge.js +184 -0
  95. package/dist/scaffolder/core/three-way-merge.js.map +1 -0
  96. package/dist/scaffolder/index.d.ts +21 -0
  97. package/dist/scaffolder/index.d.ts.map +1 -0
  98. package/dist/scaffolder/index.js +20 -0
  99. package/dist/scaffolder/index.js.map +1 -0
  100. package/frontend/templates/components/AuthField.vue +68 -0
  101. package/frontend/templates/i18n/en.json +70 -0
  102. package/frontend/templates/i18n/nl.json +70 -0
  103. package/frontend/templates/middleware/auth.ts +25 -0
  104. package/frontend/templates/middleware/guest.ts +25 -0
  105. package/frontend/templates/pages/forgot-password.vue +89 -0
  106. package/frontend/templates/pages/login.vue +90 -0
  107. package/frontend/templates/pages/logout.vue +46 -0
  108. package/frontend/templates/pages/register.vue +100 -0
  109. package/frontend/templates/pages/reset-password.vue +105 -0
  110. package/frontend/templates/pages/verify-email.vue +76 -0
  111. package/frontend/templates/plugins/auth.client.ts +111 -0
  112. package/frontend/templates/runtime.ts +60 -0
  113. package/package.json +71 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * US-A0102 — Error-taxonomie + i18n-sleutels. Eén gedeelde foutcodelijst die beide helften (backend
3
+ * mapping → HTTP, frontend weergave → i18n) uit het contract afleiden. Codes lekken nooit of een
4
+ * e-mail bestaat of waarom een token precies faalde (no-enumeration, security).
5
+ */
6
+ export const AUTH_ERROR_CODES = [
7
+ 'invalid_credentials',
8
+ 'email_taken',
9
+ 'weak_password',
10
+ 'token_invalid',
11
+ 'token_expired',
12
+ 'email_not_verified',
13
+ 'rate_limited',
14
+ 'csrf_failed',
15
+ 'unauthenticated',
16
+ 'validation_failed',
17
+ ];
18
+ /** Enige bron van de code→HTTP + code→i18n-mapping. Bewust generiek gehouden (no-enumeration). */
19
+ export const AUTH_ERROR_TAXONOMY = Object.freeze({
20
+ invalid_credentials: { httpStatus: 401, i18nKey: 'auth.error.invalid_credentials' },
21
+ email_taken: { httpStatus: 409, i18nKey: 'auth.error.email_taken' },
22
+ weak_password: { httpStatus: 422, i18nKey: 'auth.error.weak_password' },
23
+ token_invalid: { httpStatus: 400, i18nKey: 'auth.error.token_invalid' },
24
+ token_expired: { httpStatus: 410, i18nKey: 'auth.error.token_expired' },
25
+ email_not_verified: { httpStatus: 403, i18nKey: 'auth.error.email_not_verified' },
26
+ rate_limited: { httpStatus: 429, i18nKey: 'auth.error.rate_limited' },
27
+ csrf_failed: { httpStatus: 403, i18nKey: 'auth.error.csrf_failed' },
28
+ unauthenticated: { httpStatus: 401, i18nKey: 'auth.error.unauthenticated' },
29
+ validation_failed: { httpStatus: 422, i18nKey: 'auth.error.validation_failed' },
30
+ });
31
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../contract/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,qBAAqB;IACrB,aAAa;IACb,eAAe;IACf,eAAe;IACf,eAAe;IACf,oBAAoB;IACpB,cAAc;IACd,aAAa;IACb,iBAAiB;IACjB,mBAAmB;CACX,CAAC;AAWX,kGAAkG;AAClG,MAAM,CAAC,MAAM,mBAAmB,GAAyD,MAAM,CAAC,MAAM,CAAC;IACrG,mBAAmB,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,gCAAgC,EAAE;IACnF,WAAW,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,wBAAwB,EAAE;IACnE,aAAa,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,0BAA0B,EAAE;IACvE,aAAa,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,0BAA0B,EAAE;IACvE,aAAa,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,0BAA0B,EAAE;IACvE,kBAAkB,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,+BAA+B,EAAE;IACjF,YAAY,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,yBAAyB,EAAE;IACrE,WAAW,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,wBAAwB,EAAE;IACnE,eAAe,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,4BAA4B,EAAE;IAC3E,iBAAiB,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,8BAA8B,EAAE;CAChF,CAAC,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * US-A0103 — Domein-events. De module publiceert deze events (bv. voor audit-log US-A0705 of
3
+ * host-hooks). Payloads bevatten identificatie, nooit credentials/tokens.
4
+ */
5
+ export declare const AUTH_EVENTS: readonly ["user.registered", "user.verified", "user.logged_in", "user.logged_out", "session.refreshed", "password.reset_requested", "password.reset"];
6
+ export type AuthEventName = (typeof AUTH_EVENTS)[number];
7
+ export interface AuthEventBase {
8
+ readonly name: AuthEventName;
9
+ /** ISO-8601 timestamp — door de host/klok geïnjecteerd, niet hier gegenereerd. */
10
+ readonly occurredAt: string;
11
+ readonly userId: string;
12
+ }
13
+ export interface UserRegisteredEvent extends AuthEventBase {
14
+ readonly name: 'user.registered';
15
+ readonly email: string;
16
+ }
17
+ export interface UserVerifiedEvent extends AuthEventBase {
18
+ readonly name: 'user.verified';
19
+ }
20
+ export interface UserLoggedInEvent extends AuthEventBase {
21
+ readonly name: 'user.logged_in';
22
+ }
23
+ export interface UserLoggedOutEvent extends AuthEventBase {
24
+ readonly name: 'user.logged_out';
25
+ }
26
+ export interface SessionRefreshedEvent extends AuthEventBase {
27
+ readonly name: 'session.refreshed';
28
+ }
29
+ export interface PasswordResetRequestedEvent extends AuthEventBase {
30
+ readonly name: 'password.reset_requested';
31
+ }
32
+ export interface PasswordResetEvent extends AuthEventBase {
33
+ readonly name: 'password.reset';
34
+ }
35
+ export type AuthEvent = UserRegisteredEvent | UserVerifiedEvent | UserLoggedInEvent | UserLoggedOutEvent | SessionRefreshedEvent | PasswordResetRequestedEvent | PasswordResetEvent;
36
+ /** Poort die de host levert om events te consumeren (audit-log/analytics/…). */
37
+ export interface AuthEventSink {
38
+ emit(event: AuthEvent): void;
39
+ }
40
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../contract/events.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,WAAW,uJAQd,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;CAChC;AACD,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AACD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;CAClC;AACD,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AACD,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IAChE,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;CAC3C;AACD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,MAAM,MAAM,SAAS,GACjB,mBAAmB,GACnB,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,qBAAqB,GACrB,2BAA2B,GAC3B,kBAAkB,CAAC;AAEvB,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CAC9B"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * US-A0103 — Domein-events. De module publiceert deze events (bv. voor audit-log US-A0705 of
3
+ * host-hooks). Payloads bevatten identificatie, nooit credentials/tokens.
4
+ */
5
+ export const AUTH_EVENTS = [
6
+ 'user.registered',
7
+ 'user.verified',
8
+ 'user.logged_in',
9
+ 'user.logged_out',
10
+ 'session.refreshed',
11
+ 'password.reset_requested',
12
+ 'password.reset',
13
+ ];
14
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../contract/events.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB;IACjB,eAAe;IACf,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB;IACnB,0BAA0B;IAC1B,gBAAgB;CACR,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * authentication — het contract (de seam). Eén bron waaruit backend-validatie én frontend-client
3
+ * hun types afleiden. Bevat geen mechanisme, alleen schema's/typen/taxonomie/events.
4
+ */
5
+ export * from './schemas.js';
6
+ export * from './errors.js';
7
+ export * from './events.js';
8
+ export * from './endpoints.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../contract/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * authentication — het contract (de seam). Eén bron waaruit backend-validatie én frontend-client
3
+ * hun types afleiden. Bevat geen mechanisme, alleen schema's/typen/taxonomie/events.
4
+ */
5
+ export * from './schemas.js';
6
+ export * from './errors.js';
7
+ export * from './events.js';
8
+ export * from './endpoints.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../contract/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,150 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * US-A0101 — DTO-schema's (de seam). Eén set Zod-schema's waaruit de backend valideert én de
4
+ * frontend zijn getypte client afleidt (`z.infer`). Wachtwoord-policy-details komen uit config
5
+ * (US-A0603); hier alleen de vorm + minimale invarianten.
6
+ */
7
+ export declare const emailSchema: z.ZodString;
8
+ export declare const passwordSchema: z.ZodString;
9
+ export declare const registerRequestSchema: z.ZodObject<{
10
+ email: z.ZodString;
11
+ password: z.ZodString;
12
+ }, "strip", z.ZodTypeAny, {
13
+ email: string;
14
+ password: string;
15
+ }, {
16
+ email: string;
17
+ password: string;
18
+ }>;
19
+ export declare const verifyEmailRequestSchema: z.ZodObject<{
20
+ token: z.ZodString;
21
+ }, "strip", z.ZodTypeAny, {
22
+ token: string;
23
+ }, {
24
+ token: string;
25
+ }>;
26
+ export declare const loginRequestSchema: z.ZodObject<{
27
+ email: z.ZodString;
28
+ password: z.ZodString;
29
+ }, "strip", z.ZodTypeAny, {
30
+ email: string;
31
+ password: string;
32
+ }, {
33
+ email: string;
34
+ password: string;
35
+ }>;
36
+ export declare const forgotPasswordRequestSchema: z.ZodObject<{
37
+ email: z.ZodString;
38
+ }, "strip", z.ZodTypeAny, {
39
+ email: string;
40
+ }, {
41
+ email: string;
42
+ }>;
43
+ export declare const resetPasswordRequestSchema: z.ZodObject<{
44
+ token: z.ZodString;
45
+ password: z.ZodString;
46
+ }, "strip", z.ZodTypeAny, {
47
+ password: string;
48
+ token: string;
49
+ }, {
50
+ password: string;
51
+ token: string;
52
+ }>;
53
+ export declare const publicUserSchema: z.ZodObject<{
54
+ id: z.ZodString;
55
+ email: z.ZodString;
56
+ emailVerified: z.ZodBoolean;
57
+ }, "strip", z.ZodTypeAny, {
58
+ email: string;
59
+ id: string;
60
+ emailVerified: boolean;
61
+ }, {
62
+ email: string;
63
+ id: string;
64
+ emailVerified: boolean;
65
+ }>;
66
+ /** Access-token in de body; het roterende refresh-token gaat via httpOnly cookie (US-A0703). */
67
+ export declare const sessionResponseSchema: z.ZodObject<{
68
+ user: z.ZodObject<{
69
+ id: z.ZodString;
70
+ email: z.ZodString;
71
+ emailVerified: z.ZodBoolean;
72
+ }, "strip", z.ZodTypeAny, {
73
+ email: string;
74
+ id: string;
75
+ emailVerified: boolean;
76
+ }, {
77
+ email: string;
78
+ id: string;
79
+ emailVerified: boolean;
80
+ }>;
81
+ accessToken: z.ZodString;
82
+ expiresIn: z.ZodNumber;
83
+ }, "strip", z.ZodTypeAny, {
84
+ user: {
85
+ email: string;
86
+ id: string;
87
+ emailVerified: boolean;
88
+ };
89
+ accessToken: string;
90
+ expiresIn: number;
91
+ }, {
92
+ user: {
93
+ email: string;
94
+ id: string;
95
+ emailVerified: boolean;
96
+ };
97
+ accessToken: string;
98
+ expiresIn: number;
99
+ }>;
100
+ export declare const meResponseSchema: z.ZodObject<{
101
+ user: z.ZodObject<{
102
+ id: z.ZodString;
103
+ email: z.ZodString;
104
+ emailVerified: z.ZodBoolean;
105
+ }, "strip", z.ZodTypeAny, {
106
+ email: string;
107
+ id: string;
108
+ emailVerified: boolean;
109
+ }, {
110
+ email: string;
111
+ id: string;
112
+ emailVerified: boolean;
113
+ }>;
114
+ roles: z.ZodArray<z.ZodString, "many">;
115
+ permissions: z.ZodArray<z.ZodString, "many">;
116
+ }, "strip", z.ZodTypeAny, {
117
+ user: {
118
+ email: string;
119
+ id: string;
120
+ emailVerified: boolean;
121
+ };
122
+ roles: string[];
123
+ permissions: string[];
124
+ }, {
125
+ user: {
126
+ email: string;
127
+ id: string;
128
+ emailVerified: boolean;
129
+ };
130
+ roles: string[];
131
+ permissions: string[];
132
+ }>;
133
+ /** Generieke bevestiging voor register/forgot (no-enumeration): altijd hetzelfde. */
134
+ export declare const acknowledgementSchema: z.ZodObject<{
135
+ ok: z.ZodLiteral<true>;
136
+ }, "strip", z.ZodTypeAny, {
137
+ ok: true;
138
+ }, {
139
+ ok: true;
140
+ }>;
141
+ export type RegisterRequest = z.infer<typeof registerRequestSchema>;
142
+ export type VerifyEmailRequest = z.infer<typeof verifyEmailRequestSchema>;
143
+ export type LoginRequest = z.infer<typeof loginRequestSchema>;
144
+ export type ForgotPasswordRequest = z.infer<typeof forgotPasswordRequestSchema>;
145
+ export type ResetPasswordRequest = z.infer<typeof resetPasswordRequestSchema>;
146
+ export type PublicUser = z.infer<typeof publicUserSchema>;
147
+ export type SessionResponse = z.infer<typeof sessionResponseSchema>;
148
+ export type MeResponse = z.infer<typeof meResponseSchema>;
149
+ export type Acknowledgement = z.infer<typeof acknowledgementSchema>;
150
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../contract/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AAEH,eAAO,MAAM,WAAW,aAAqB,CAAC;AAC9C,eAAO,MAAM,cAAc,aAA6B,CAAC;AAGzD,eAAO,MAAM,qBAAqB;;;;;;;;;EAGhC,CAAC;AACH,eAAO,MAAM,wBAAwB;;;;;;EAAyC,CAAC;AAC/E,eAAO,MAAM,kBAAkB;;;;;;;;;EAG7B,CAAC;AACH,eAAO,MAAM,2BAA2B;;;;;;EAAmC,CAAC;AAC5E,eAAO,MAAM,0BAA0B;;;;;;;;;EAGrC,CAAC;AAGH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAI3B,CAAC;AACH,gGAAgG;AAChG,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIhC,CAAC;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI3B,CAAC;AACH,qFAAqF;AACrF,eAAO,MAAM,qBAAqB;;;;;;EAAoC,CAAC;AAGvE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAChF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAC9E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * US-A0101 — DTO-schema's (de seam). Eén set Zod-schema's waaruit de backend valideert én de
4
+ * frontend zijn getypte client afleidt (`z.infer`). Wachtwoord-policy-details komen uit config
5
+ * (US-A0603); hier alleen de vorm + minimale invarianten.
6
+ */
7
+ export const emailSchema = z.string().email();
8
+ export const passwordSchema = z.string().min(8).max(200);
9
+ // --- Requests ---
10
+ export const registerRequestSchema = z.object({
11
+ email: emailSchema,
12
+ password: passwordSchema,
13
+ });
14
+ export const verifyEmailRequestSchema = z.object({ token: z.string().min(1) });
15
+ export const loginRequestSchema = z.object({
16
+ email: emailSchema,
17
+ password: z.string().min(1),
18
+ });
19
+ export const forgotPasswordRequestSchema = z.object({ email: emailSchema });
20
+ export const resetPasswordRequestSchema = z.object({
21
+ token: z.string().min(1),
22
+ password: passwordSchema,
23
+ });
24
+ // --- Responses ---
25
+ export const publicUserSchema = z.object({
26
+ id: z.string(),
27
+ email: emailSchema,
28
+ emailVerified: z.boolean(),
29
+ });
30
+ /** Access-token in de body; het roterende refresh-token gaat via httpOnly cookie (US-A0703). */
31
+ export const sessionResponseSchema = z.object({
32
+ user: publicUserSchema,
33
+ accessToken: z.string(),
34
+ expiresIn: z.number().int().positive(),
35
+ });
36
+ export const meResponseSchema = z.object({
37
+ user: publicUserSchema,
38
+ roles: z.array(z.string()),
39
+ permissions: z.array(z.string()),
40
+ });
41
+ /** Generieke bevestiging voor register/forgot (no-enumeration): altijd hetzelfde. */
42
+ export const acknowledgementSchema = z.object({ ok: z.literal(true) });
43
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../contract/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;AAC9C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEzD,mBAAmB;AACnB,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,WAAW;IAClB,QAAQ,EAAE,cAAc;CACzB,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,WAAW;IAClB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC5B,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,QAAQ,EAAE,cAAc;CACzB,CAAC,CAAC;AAEH,oBAAoB;AACpB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;CAC3B,CAAC,CAAC;AACH,gGAAgG;AAChG,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1B,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AACH,qFAAqF;AACrF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { HttpClient } from '@seifer-webapp-factory/kits/frontend/http-client';
2
+ import type { AuthErrorCode, Acknowledgement, ForgotPasswordRequest, LoginRequest, MeResponse, RegisterRequest, ResetPasswordRequest, SessionResponse, VerifyEmailRequest } from '../../contract/index.js';
3
+ /**
4
+ * Getypte fout die de client bij een niet-2xx-respons gooit. Draagt de contract-`code` + de
5
+ * bijbehorende `i18nKey` (uit de taxonomie) zodat de UI een sleutel toont, nooit rauwe details.
6
+ * Bevat nooit credential-/token-materiaal.
7
+ */
8
+ export declare class AuthClientError extends Error {
9
+ readonly code: AuthErrorCode;
10
+ readonly i18nKey: string;
11
+ readonly httpStatus: number;
12
+ /** Optionele veld-gebonden validatiefouten (paden), zonder ingevoerde waarden. */
13
+ readonly fields?: Readonly<Record<string, string[]>>;
14
+ constructor(code: AuthErrorCode, i18nKey: string, httpStatus: number, fields?: Readonly<Record<string, string[]>>);
15
+ }
16
+ /** De publieke, getypte client-API. Elke methode neemt het contract-request en levert de -respons. */
17
+ export interface AuthClient {
18
+ register(input: RegisterRequest): Promise<Acknowledgement>;
19
+ verifyEmail(input: VerifyEmailRequest): Promise<Acknowledgement>;
20
+ login(input: LoginRequest): Promise<SessionResponse>;
21
+ refresh(): Promise<SessionResponse>;
22
+ logout(): Promise<Acknowledgement>;
23
+ forgotPassword(input: ForgotPasswordRequest): Promise<Acknowledgement>;
24
+ resetPassword(input: ResetPasswordRequest): Promise<Acknowledgement>;
25
+ me(): Promise<MeResponse>;
26
+ }
27
+ export interface CreateAuthClientOptions {
28
+ /** De geïnjecteerde kit-`HttpClient` (met base-URL + cookie-transport). */
29
+ readonly http: HttpClient;
30
+ }
31
+ /**
32
+ * Maakt een getypte auth-client rond de geïnjecteerde kit-`HttpClient`. Elke methode is een dunne
33
+ * wrapper om `call`, die het endpoint-descriptor uit het contract gebruikt voor methode + pad, de
34
+ * kit-`HttpError` naar een getypte `AuthClientError` mapt (via de response-body), en de happy-respons
35
+ * tegen het contract-schema valideert.
36
+ */
37
+ export declare function createAuthClient(options: CreateAuthClientOptions): AuthClient;
38
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../frontend/src/client.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kDAAkD,CAAC;AAMnF,OAAO,KAAK,EAEV,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,YAAY,EACZ,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;gBAGnD,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAS9C;AAED,sGAAsG;AACtG,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3D,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjE,KAAK,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrD,OAAO,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IACpC,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IACnC,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACvE,aAAa,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrE,EAAE,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AA0BD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,UAAU,CA+C7E"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * De getypte auth-client (het mechanisme). Leidt zijn methoden, paden en foutcodes af uit het
3
+ * contract (`AUTH_ENDPOINTS` + `AUTH_ERROR_TAXONOMY`) — één bron, geen drift. De client kent geen
4
+ * netwerk: hij krijgt de kit-`HttpClient` (`@seifer-webapp-factory/kits/frontend/http-client`) geïnjecteerd,
5
+ * geconfigureerd met base-URL + een transport dat cookies (roterend refresh-token + CSRF) meestuurt.
6
+ * Bij een niet-2xx-respons gooit de kit-client een `HttpError` mét de geparste response-body, zodat
7
+ * we de contract-`code` kunnen lezen en naar een getypte `AuthClientError` mappen. Geen module-globale
8
+ * mutable state — elke `createAuthClient` is een verse closure over de geïnjecteerde client.
9
+ */
10
+ import { HttpError } from '@seifer-webapp-factory/kits/frontend/http-client';
11
+ import { AUTH_ENDPOINTS, AUTH_ERROR_CODES, AUTH_ERROR_TAXONOMY, } from '../../contract/index.js';
12
+ /**
13
+ * Getypte fout die de client bij een niet-2xx-respons gooit. Draagt de contract-`code` + de
14
+ * bijbehorende `i18nKey` (uit de taxonomie) zodat de UI een sleutel toont, nooit rauwe details.
15
+ * Bevat nooit credential-/token-materiaal.
16
+ */
17
+ export class AuthClientError extends Error {
18
+ code;
19
+ i18nKey;
20
+ httpStatus;
21
+ /** Optionele veld-gebonden validatiefouten (paden), zonder ingevoerde waarden. */
22
+ fields;
23
+ constructor(code, i18nKey, httpStatus, fields) {
24
+ super(`[auth] ${code} (HTTP ${httpStatus})`);
25
+ this.name = 'AuthClientError';
26
+ this.code = code;
27
+ this.i18nKey = i18nKey;
28
+ this.httpStatus = httpStatus;
29
+ this.fields = fields;
30
+ }
31
+ }
32
+ const ERROR_CODES = AUTH_ERROR_CODES;
33
+ /**
34
+ * Leidt de foutcode af uit de respons: bij voorkeur uit de body (`code`), anders een reverse-lookup
35
+ * op de HTTP-status (no-enumeration: bewust generiek), met een veilige validation-fallback.
36
+ */
37
+ function resolveErrorCode(status, body) {
38
+ const bodyCode = body?.code;
39
+ if (typeof bodyCode === 'string' && ERROR_CODES.includes(bodyCode)) {
40
+ return bodyCode;
41
+ }
42
+ const byStatus = AUTH_ERROR_CODES.find((code) => AUTH_ERROR_TAXONOMY[code].httpStatus === status);
43
+ return byStatus ?? 'validation_failed';
44
+ }
45
+ /**
46
+ * Maakt een getypte auth-client rond de geïnjecteerde kit-`HttpClient`. Elke methode is een dunne
47
+ * wrapper om `call`, die het endpoint-descriptor uit het contract gebruikt voor methode + pad, de
48
+ * kit-`HttpError` naar een getypte `AuthClientError` mapt (via de response-body), en de happy-respons
49
+ * tegen het contract-schema valideert.
50
+ */
51
+ export function createAuthClient(options) {
52
+ const { http } = options;
53
+ async function call(endpoint, body) {
54
+ let data;
55
+ let status;
56
+ try {
57
+ const res = await http.request({ method: endpoint.method, path: endpoint.path, body });
58
+ data = res.data;
59
+ status = res.status;
60
+ }
61
+ catch (err) {
62
+ if (err instanceof HttpError && err.status !== undefined) {
63
+ const code = resolveErrorCode(err.status, err.body);
64
+ const errorBody = err.body;
65
+ throw new AuthClientError(code, AUTH_ERROR_TAXONOMY[code].i18nKey, err.status, errorBody?.fields);
66
+ }
67
+ // Netwerk/timeout/abort: laat de getypte kit-fout ongewijzigd door.
68
+ throw err;
69
+ }
70
+ // Valideer de happy-respons tegen het contract-schema: gegarandeerde vorm, of een getypte fout.
71
+ const parsed = endpoint.response.safeParse(data);
72
+ if (!parsed.success) {
73
+ throw new AuthClientError('validation_failed', AUTH_ERROR_TAXONOMY.validation_failed.i18nKey, status);
74
+ }
75
+ return parsed.data;
76
+ }
77
+ return {
78
+ register: (input) => call(AUTH_ENDPOINTS.register, input),
79
+ verifyEmail: (input) => call(AUTH_ENDPOINTS.verifyEmail, input),
80
+ login: (input) => call(AUTH_ENDPOINTS.login, input),
81
+ refresh: () => call(AUTH_ENDPOINTS.refresh),
82
+ logout: () => call(AUTH_ENDPOINTS.logout),
83
+ forgotPassword: (input) => call(AUTH_ENDPOINTS.forgotPassword, input),
84
+ resetPassword: (input) => call(AUTH_ENDPOINTS.resetPassword, input),
85
+ me: () => call(AUTH_ENDPOINTS.me),
86
+ };
87
+ }
88
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../frontend/src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Vue-composables (het mechanisme, provide/inject). Een dunne, reactieve laag bovenop de getypte
3
+ * auth-client en de frontend auth-kit sessie-store. De client wordt per app-instance geprovide
4
+ * (`provideAuthClient`), zodat SSR-render en client-hydratie per request geïsoleerd blijven — geen
5
+ * module-globale mutable state. Elke actie-composable stelt reactieve `pending`/`error`(i18nKey)/
6
+ * `result` bloot plus een `submit`-functie.
7
+ */
8
+ import { type App, type InjectionKey, type Ref } from 'vue';
9
+ import { type AuthClient } from './client.js';
10
+ import type { Acknowledgement, ForgotPasswordRequest, LoginRequest, RegisterRequest, ResetPasswordRequest, SessionResponse, VerifyEmailRequest } from '../../contract/index.js';
11
+ /** De per-request client die op de app wordt geprovide. Symbool = module-constante (geen state). */
12
+ export declare const AUTH_CLIENT_KEY: InjectionKey<AuthClient>;
13
+ /** Registreer de auth-client op een app-instance (bij bootstrap). */
14
+ export declare function provideAuthClient(app: App, client: AuthClient): void;
15
+ /** Haal de getypte auth-client op binnen setup(). Werpt als er niets geprovide is. */
16
+ export declare function useAuthClient(): AuthClient;
17
+ /** De reactieve vorm die elke actie-composable teruggeeft. `error` is een i18n-sleutel, geen detail. */
18
+ export interface UseAuthAction<Input, Result> {
19
+ /** True tijdens de call. */
20
+ readonly pending: Ref<boolean>;
21
+ /** i18n-sleutel bij falen (uit de foutentaxonomie), anders `null`. */
22
+ readonly error: Ref<string | null>;
23
+ /** De laatste geslaagde respons, of `null`. */
24
+ readonly result: Ref<Result | null>;
25
+ /** Voer de actie uit; levert de respons bij succes, of `undefined` bij een gemapte fout. */
26
+ submit(input: Input): Promise<Result | undefined>;
27
+ }
28
+ /**
29
+ * Login-composable: roept `client.login` aan en hydrateert bij succes de auth-kit sessie-store
30
+ * (status → `authenticated`). Werpt als er geen auth-instantie geprovide is (via `provideAuth`).
31
+ */
32
+ export declare function useLogin(): UseAuthAction<LoginRequest, SessionResponse>;
33
+ /** Registratie-composable. */
34
+ export declare function useRegister(): UseAuthAction<RegisterRequest, Acknowledgement>;
35
+ /** E-mailverificatie-composable. */
36
+ export declare function useVerifyEmail(): UseAuthAction<VerifyEmailRequest, Acknowledgement>;
37
+ /** Wachtwoord-vergeten-composable (no-enumeration: altijd dezelfde bevestiging). */
38
+ export declare function useForgotPassword(): UseAuthAction<ForgotPasswordRequest, Acknowledgement>;
39
+ /** Wachtwoord-reset-composable. */
40
+ export declare function useResetPassword(): UseAuthAction<ResetPasswordRequest, Acknowledgement>;
41
+ /**
42
+ * Logout-composable: beëindigt de server-sessie en wist de lokale auth-kit-sessie. De lokale sessie
43
+ * wordt hoe dan ook gewist, ook als de server-call faalt (netwerk/afgemeld).
44
+ */
45
+ export declare function useLogout(): UseAuthAction<void, Acknowledgement>;
46
+ //# sourceMappingURL=composables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composables.d.ts","sourceRoot":"","sources":["../../../frontend/src/composables.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAe,KAAK,GAAG,EAAE,KAAK,YAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAGzE,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACrB,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAEjC,oGAAoG;AACpG,eAAO,MAAM,eAAe,EAAE,YAAY,CAAC,UAAU,CAAyB,CAAC;AAE/E,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAEpE;AAED,sFAAsF;AACtF,wBAAgB,aAAa,IAAI,UAAU,CAQ1C;AAED,wGAAwG;AACxG,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,MAAM;IAC1C,4BAA4B;IAC5B,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnC,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACpC,4FAA4F;IAC5F,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACnD;AAiCD;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,aAAa,CAAC,YAAY,EAAE,eAAe,CAAC,CAoBvE;AAED,8BAA8B;AAC9B,wBAAgB,WAAW,IAAI,aAAa,CAAC,eAAe,EAAE,eAAe,CAAC,CAG7E;AAED,oCAAoC;AACpC,wBAAgB,cAAc,IAAI,aAAa,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAGnF;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,IAAI,aAAa,CAAC,qBAAqB,EAAE,eAAe,CAAC,CAKzF;AAED,mCAAmC;AACnC,wBAAgB,gBAAgB,IAAI,aAAa,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAGvF;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,aAAa,CAAC,IAAI,EAAE,eAAe,CAAC,CAUhE"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Vue-composables (het mechanisme, provide/inject). Een dunne, reactieve laag bovenop de getypte
3
+ * auth-client en de frontend auth-kit sessie-store. De client wordt per app-instance geprovide
4
+ * (`provideAuthClient`), zodat SSR-render en client-hydratie per request geïsoleerd blijven — geen
5
+ * module-globale mutable state. Elke actie-composable stelt reactieve `pending`/`error`(i18nKey)/
6
+ * `result` bloot plus een `submit`-functie.
7
+ */
8
+ import { inject, ref } from 'vue';
9
+ import { AUTH_KEY } from '@seifer-webapp-factory/kits/frontend/auth/vue';
10
+ import { AuthClientError } from './client.js';
11
+ /** De per-request client die op de app wordt geprovide. Symbool = module-constante (geen state). */
12
+ export const AUTH_CLIENT_KEY = Symbol('auth.client');
13
+ /** Registreer de auth-client op een app-instance (bij bootstrap). */
14
+ export function provideAuthClient(app, client) {
15
+ app.provide(AUTH_CLIENT_KEY, client);
16
+ }
17
+ /** Haal de getypte auth-client op binnen setup(). Werpt als er niets geprovide is. */
18
+ export function useAuthClient() {
19
+ const client = inject(AUTH_CLIENT_KEY);
20
+ if (client === undefined) {
21
+ throw new Error('[auth] useAuthClient(): geen auth-client geprovide. Roep provideAuthClient(app, client) aan bij bootstrap.');
22
+ }
23
+ return client;
24
+ }
25
+ /** Vertaalt een gevangen fout naar een i18n-sleutel zonder details te lekken. */
26
+ function toI18nKey(cause) {
27
+ return cause instanceof AuthClientError ? cause.i18nKey : 'auth.error.unknown';
28
+ }
29
+ /** Interne fabriek: bouwt een reactieve actie rond een async runner met uniforme foutafhandeling. */
30
+ function useAuthAction(run) {
31
+ const pending = ref(false);
32
+ const error = ref(null);
33
+ const result = ref(null);
34
+ async function submit(input) {
35
+ pending.value = true;
36
+ error.value = null;
37
+ try {
38
+ const value = await run(input);
39
+ result.value = value;
40
+ return value;
41
+ }
42
+ catch (cause) {
43
+ error.value = toI18nKey(cause);
44
+ return undefined;
45
+ }
46
+ finally {
47
+ pending.value = false;
48
+ }
49
+ }
50
+ return { pending, error, result, submit };
51
+ }
52
+ /**
53
+ * Login-composable: roept `client.login` aan en hydrateert bij succes de auth-kit sessie-store
54
+ * (status → `authenticated`). Werpt als er geen auth-instantie geprovide is (via `provideAuth`).
55
+ */
56
+ export function useLogin() {
57
+ const client = useAuthClient();
58
+ const auth = inject(AUTH_KEY);
59
+ if (auth === undefined) {
60
+ throw new Error('[auth] useLogin(): geen auth-instantie geprovide. Roep provideAuth(app, instance) aan bij bootstrap.');
61
+ }
62
+ return useAuthAction(async (input) => {
63
+ const session = await client.login(input);
64
+ auth.store.establish({
65
+ tokens: {
66
+ accessToken: session.accessToken,
67
+ expiresAt: Date.now() + session.expiresIn * 1000,
68
+ },
69
+ subject: session.user.id,
70
+ claims: session.user,
71
+ });
72
+ return session;
73
+ });
74
+ }
75
+ /** Registratie-composable. */
76
+ export function useRegister() {
77
+ const client = useAuthClient();
78
+ return useAuthAction((input) => client.register(input));
79
+ }
80
+ /** E-mailverificatie-composable. */
81
+ export function useVerifyEmail() {
82
+ const client = useAuthClient();
83
+ return useAuthAction((input) => client.verifyEmail(input));
84
+ }
85
+ /** Wachtwoord-vergeten-composable (no-enumeration: altijd dezelfde bevestiging). */
86
+ export function useForgotPassword() {
87
+ const client = useAuthClient();
88
+ return useAuthAction((input) => client.forgotPassword(input));
89
+ }
90
+ /** Wachtwoord-reset-composable. */
91
+ export function useResetPassword() {
92
+ const client = useAuthClient();
93
+ return useAuthAction((input) => client.resetPassword(input));
94
+ }
95
+ /**
96
+ * Logout-composable: beëindigt de server-sessie en wist de lokale auth-kit-sessie. De lokale sessie
97
+ * wordt hoe dan ook gewist, ook als de server-call faalt (netwerk/afgemeld).
98
+ */
99
+ export function useLogout() {
100
+ const client = useAuthClient();
101
+ const auth = inject(AUTH_KEY);
102
+ return useAuthAction(async () => {
103
+ try {
104
+ return await client.logout();
105
+ }
106
+ finally {
107
+ auth?.store.clear();
108
+ }
109
+ });
110
+ }
111
+ //# sourceMappingURL=composables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composables.js","sourceRoot":"","sources":["../../../frontend/src/composables.ts"],"names":[],"mappings":"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"}