@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,37 @@
1
+ /**
2
+ * Fouttypes voor de authentication-scaffolder. Draag altijd genoeg context voor een expliciete
3
+ * melding (paden, poorten, velden, versies), maar NOOIT invoerwaarden of secrets. Deterministisch:
4
+ * geen timestamps/random. Alle meldingen zijn Nederlandstalig.
5
+ */
6
+ /**
7
+ * Geworpen door `materializeAuthModule` wanneer te materialiseren surface-bestanden al in het
8
+ * project bestaan en `overwrite` niet gezet is. Benoemt ALLE conflicterende paden; er wordt niets
9
+ * (ook niet gedeeltelijk) weggeschreven — een gedivergeerd projectbestand wordt nooit stil overschreven.
10
+ */
11
+ export declare class AuthMaterializationConflictError extends Error {
12
+ readonly paths: readonly string[];
13
+ constructor(paths: readonly string[]);
14
+ }
15
+ /**
16
+ * Geworpen wanneer het project een door het manifest vereiste requires-port niet levert. De
17
+ * materialisatie weigert dan te starten (US-A0803 AC3), zodat er geen half-gewirede surface achterblijft.
18
+ */
19
+ export declare class MissingRequiredPortError extends Error {
20
+ readonly missing: readonly string[];
21
+ constructor(missing: readonly string[]);
22
+ }
23
+ /** Eén config-validatie-overtreding: pad naar het veld + reden (Nederlands). */
24
+ export interface AuthConfigViolation {
25
+ readonly path: string;
26
+ readonly message: string;
27
+ }
28
+ /**
29
+ * Geworpen door `resolveAuthConfig` wanneer het config-fragment ongeldig is (negatieve TTL,
30
+ * niet-absolute redirect, access-TTL ≥ refresh-TTL, ...). Faalt bij het opstarten met veld + reden
31
+ * (US-A1001 AC3), niet halverwege een flow. Bevat geen secret-waarden.
32
+ */
33
+ export declare class AuthConfigValidationError extends Error {
34
+ readonly violations: readonly AuthConfigViolation[];
35
+ constructor(violations: readonly AuthConfigViolation[]);
36
+ }
37
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../scaffolder/core/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;gBAEtB,KAAK,EAAE,SAAS,MAAM,EAAE;CAQrC;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;gBAExB,OAAO,EAAE,SAAS,MAAM,EAAE;CAOvC;AAED,gFAAgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,UAAU,EAAE,SAAS,mBAAmB,EAAE,CAAC;gBAExC,UAAU,EAAE,SAAS,mBAAmB,EAAE;CAMvD"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Fouttypes voor de authentication-scaffolder. Draag altijd genoeg context voor een expliciete
3
+ * melding (paden, poorten, velden, versies), maar NOOIT invoerwaarden of secrets. Deterministisch:
4
+ * geen timestamps/random. Alle meldingen zijn Nederlandstalig.
5
+ */
6
+ /**
7
+ * Geworpen door `materializeAuthModule` wanneer te materialiseren surface-bestanden al in het
8
+ * project bestaan en `overwrite` niet gezet is. Benoemt ALLE conflicterende paden; er wordt niets
9
+ * (ook niet gedeeltelijk) weggeschreven — een gedivergeerd projectbestand wordt nooit stil overschreven.
10
+ */
11
+ export class AuthMaterializationConflictError extends Error {
12
+ paths;
13
+ constructor(paths) {
14
+ super(`Materialisatie gestopt: ${paths.length} surface-bestand(en) bestaan al en zouden overschreven ` +
15
+ `worden zonder overwrite-vlag: ${paths.join(', ')}`);
16
+ this.name = 'AuthMaterializationConflictError';
17
+ this.paths = paths;
18
+ }
19
+ }
20
+ /**
21
+ * Geworpen wanneer het project een door het manifest vereiste requires-port niet levert. De
22
+ * materialisatie weigert dan te starten (US-A0803 AC3), zodat er geen half-gewirede surface achterblijft.
23
+ */
24
+ export class MissingRequiredPortError extends Error {
25
+ missing;
26
+ constructor(missing) {
27
+ super(`Materialisatie geweigerd: de host levert niet alle vereiste ports. Ontbrekend: ${missing.join(', ')}`);
28
+ this.name = 'MissingRequiredPortError';
29
+ this.missing = missing;
30
+ }
31
+ }
32
+ /**
33
+ * Geworpen door `resolveAuthConfig` wanneer het config-fragment ongeldig is (negatieve TTL,
34
+ * niet-absolute redirect, access-TTL ≥ refresh-TTL, ...). Faalt bij het opstarten met veld + reden
35
+ * (US-A1001 AC3), niet halverwege een flow. Bevat geen secret-waarden.
36
+ */
37
+ export class AuthConfigValidationError extends Error {
38
+ violations;
39
+ constructor(violations) {
40
+ const summary = violations.map((v) => `${v.path}: ${v.message}`).join('; ');
41
+ super(`Ongeldige auth-config: ${summary}`);
42
+ this.name = 'AuthConfigValidationError';
43
+ this.violations = violations;
44
+ }
45
+ }
46
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../scaffolder/core/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,OAAO,gCAAiC,SAAQ,KAAK;IAChD,KAAK,CAAoB;IAElC,YAAY,KAAwB;QAClC,KAAK,CACH,2BAA2B,KAAK,CAAC,MAAM,yDAAyD;YAC9F,iCAAiC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kCAAkC,CAAC;QAC/C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,OAAO,CAAoB;IAEpC,YAAY,OAA0B;QACpC,KAAK,CACH,kFAAkF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAQD;;;;GAIG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IACzC,UAAU,CAAiC;IAEpD,YAAY,UAA0C;QACpD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * extend — niveau 2 van de divergentie-ladder: UITBREIDEN (additief, upgrade-veilig) — US-A1002.
3
+ *
4
+ * Biedt drie additieve uitbreidingspunten die de surface honoreert zonder eject:
5
+ * 1. `defineRegisterFieldExtension` + `extendRegisterSchema` — een extra register-veld (bv. displayName),
6
+ * contract-conform toegevoegd aan het DTO-schema en persisteerbaar via de UserStore-port.
7
+ * 2. `createPostLoginHookRegistry` — een per-instantie hook-registry die na een geslaagde login draait;
8
+ * een falende/trage hook laat de login-uitkomst en sessie-uitgifte onaangetast (AC2). De hook-context
9
+ * bevat NOOIT secret- of wachtwoordmateriaal.
10
+ * 3. named-slot-descriptors — een component-slot (bv. de login-kaart) via `defineSlot` + `createSlotRegistry`.
11
+ *
12
+ * Alles is pure data / factory-gemaakte registries: geen module-globale mutable state, geen fs.
13
+ * Omdat de uitbreidingen additief zijn, blijft de upgrade fully upgrade-safe.
14
+ */
15
+ import { z } from 'zod';
16
+ /** Beschrijft één additief register-veld. */
17
+ export interface RegisterFieldExtension {
18
+ /** Veldnaam (moet uniek zijn en niet botsen met een gecontracteerd veld). */
19
+ readonly name: string;
20
+ /** Zod-schema voor het veld (validatie in het form én op de client). */
21
+ readonly schema: z.ZodTypeAny;
22
+ /** Verplicht veld? Zo niet, dan wordt het `.optional()` toegevoegd. */
23
+ readonly required: boolean;
24
+ /** Optioneel label voor het form. */
25
+ readonly label?: string;
26
+ /** Moet de waarde via de UserStore-port gepersisteerd worden? (default true) */
27
+ readonly persist: boolean;
28
+ }
29
+ /** Invoer voor `defineRegisterFieldExtension` (persist/required optioneel). */
30
+ export interface RegisterFieldExtensionSpec {
31
+ readonly name: string;
32
+ readonly schema: z.ZodTypeAny;
33
+ readonly required?: boolean;
34
+ readonly label?: string;
35
+ readonly persist?: boolean;
36
+ }
37
+ /**
38
+ * Definieert een additieve register-veld-extensie (bevroren descriptor).
39
+ *
40
+ * @throws Error als de veldnaam leeg is of een gecontracteerd veld zou overschrijven
41
+ */
42
+ export declare function defineRegisterFieldExtension(spec: RegisterFieldExtensionSpec): RegisterFieldExtension;
43
+ /**
44
+ * Breidt een register-DTO-schema additief uit met de opgegeven extensies. De bestaande (gecontracteerde)
45
+ * velden blijven ongewijzigd; niet-verplichte extensies worden `.optional()`. Pure functie — retourneert
46
+ * een nieuw schema, muteert het basisschema niet.
47
+ */
48
+ export declare function extendRegisterSchema<T extends z.ZodRawShape>(base: z.ZodObject<T>, extensions: readonly RegisterFieldExtension[]): z.ZodObject<z.ZodRawShape>;
49
+ /**
50
+ * De context die een post-login-hook krijgt. Bewust ZONDER wachtwoord- of secret-materiaal: een hook
51
+ * mag audit/preload doen, maar krijgt nooit credentials (security-invariant, US-A1002 AC4).
52
+ */
53
+ export interface PostLoginContext {
54
+ readonly userId: string;
55
+ readonly email: string;
56
+ /** Tijdstip van de login, geïnjecteerd door de caller (geen Date.now → deterministisch/testbaar). */
57
+ readonly at: string;
58
+ /** Optionele actieve locale. */
59
+ readonly locale?: string;
60
+ }
61
+ /** Een post-login-hook. Mag async zijn; een fout hierin mag de login-uitkomst niet beïnvloeden. */
62
+ export type PostLoginHook = (ctx: PostLoginContext) => void | Promise<void>;
63
+ /** Uitkomst van het draaien van alle hooks. */
64
+ export interface PostLoginRunResult {
65
+ /** Namen van hooks die (geslaagd) gedraaid hebben, in registratievolgorde. */
66
+ readonly ran: readonly string[];
67
+ /** Hooks die faalden, met hun foutmelding — de login is desondanks geslaagd. */
68
+ readonly failed: readonly {
69
+ readonly name: string;
70
+ readonly error: string;
71
+ }[];
72
+ }
73
+ /** Een per-instantie post-login-hook-registry. */
74
+ export interface PostLoginHookRegistry {
75
+ /** Registreert een hook onder een unieke naam. */
76
+ register(name: string, hook: PostLoginHook): void;
77
+ /** De geregistreerde hooknamen in registratievolgorde. */
78
+ list(): readonly string[];
79
+ /**
80
+ * Draait alle hooks precies één keer in registratievolgorde. Vangt fouten per hook op zodat een
81
+ * falende/trage hook de kern-login-uitkomst niet breekt; retourneert wat er liep en wat faalde.
82
+ */
83
+ run(ctx: PostLoginContext): Promise<PostLoginRunResult>;
84
+ }
85
+ /**
86
+ * Maakt een verse, geïsoleerde post-login-hook-registry. Factory (geen module-globale mutable state):
87
+ * elke app-factory/aanroep krijgt zijn eigen registry, wat SSR/hydratie-veilig is.
88
+ */
89
+ export declare function createPostLoginHookRegistry(): PostLoginHookRegistry;
90
+ /** De slots die de auth-surface aanbiedt om een default-component te vervangen. */
91
+ export declare const AUTH_SLOT_NAMES: readonly ["login.card", "login.footer", "register.card", "register.footer"];
92
+ /** Union van geldige slot-namen. */
93
+ export type AuthSlotName = (typeof AUTH_SLOT_NAMES)[number];
94
+ /** Een slot-override: welk slot door welke (design-system-)component wordt ingevuld. */
95
+ export interface SlotDescriptor {
96
+ readonly slot: AuthSlotName;
97
+ /** Referentie naar de vervangende component (import-pad/naam die de surface rendert). */
98
+ readonly component: string;
99
+ }
100
+ /**
101
+ * Definieert een slot-override (bevroren descriptor).
102
+ *
103
+ * @throws Error bij een onbekende slot-naam of een lege component-referentie
104
+ */
105
+ export declare function defineSlot(slot: AuthSlotName, component: string): SlotDescriptor;
106
+ /** Een per-instantie slot-registry die de surface bevraagt om default-componenten te vervangen. */
107
+ export interface SlotRegistry {
108
+ set(descriptor: SlotDescriptor): void;
109
+ /** De override voor een slot, of `undefined` (dan rendert de surface de default). */
110
+ get(slot: AuthSlotName): SlotDescriptor | undefined;
111
+ list(): readonly SlotDescriptor[];
112
+ }
113
+ /** Maakt een verse, geïsoleerde slot-registry (factory; geen module-globale mutable state). */
114
+ export declare function createSlotRegistry(): SlotRegistry;
115
+ //# sourceMappingURL=extend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../../../scaffolder/core/extend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * extend — niveau 2 van de divergentie-ladder: UITBREIDEN (additief, upgrade-veilig) — US-A1002.
3
+ *
4
+ * Biedt drie additieve uitbreidingspunten die de surface honoreert zonder eject:
5
+ * 1. `defineRegisterFieldExtension` + `extendRegisterSchema` — een extra register-veld (bv. displayName),
6
+ * contract-conform toegevoegd aan het DTO-schema en persisteerbaar via de UserStore-port.
7
+ * 2. `createPostLoginHookRegistry` — een per-instantie hook-registry die na een geslaagde login draait;
8
+ * een falende/trage hook laat de login-uitkomst en sessie-uitgifte onaangetast (AC2). De hook-context
9
+ * bevat NOOIT secret- of wachtwoordmateriaal.
10
+ * 3. named-slot-descriptors — een component-slot (bv. de login-kaart) via `defineSlot` + `createSlotRegistry`.
11
+ *
12
+ * Alles is pure data / factory-gemaakte registries: geen module-globale mutable state, geen fs.
13
+ * Omdat de uitbreidingen additief zijn, blijft de upgrade fully upgrade-safe.
14
+ */
15
+ import { z } from 'zod';
16
+ /** De gecontracteerde register-velden; een extensie mag deze niet overschrijven. */
17
+ const CONTRACTED_REGISTER_FIELDS = new Set(['email', 'password']);
18
+ /**
19
+ * Definieert een additieve register-veld-extensie (bevroren descriptor).
20
+ *
21
+ * @throws Error als de veldnaam leeg is of een gecontracteerd veld zou overschrijven
22
+ */
23
+ export function defineRegisterFieldExtension(spec) {
24
+ if (spec.name.trim() === '') {
25
+ throw new Error('Register-veld-extensie ongeldig: "name" mag niet leeg zijn.');
26
+ }
27
+ if (CONTRACTED_REGISTER_FIELDS.has(spec.name)) {
28
+ throw new Error(`Register-veld-extensie ongeldig: "${spec.name}" is een gecontracteerd veld en mag niet worden overschreven.`);
29
+ }
30
+ return Object.freeze({
31
+ name: spec.name,
32
+ schema: spec.schema,
33
+ required: spec.required ?? true,
34
+ label: spec.label,
35
+ persist: spec.persist ?? true,
36
+ });
37
+ }
38
+ /**
39
+ * Breidt een register-DTO-schema additief uit met de opgegeven extensies. De bestaande (gecontracteerde)
40
+ * velden blijven ongewijzigd; niet-verplichte extensies worden `.optional()`. Pure functie — retourneert
41
+ * een nieuw schema, muteert het basisschema niet.
42
+ */
43
+ export function extendRegisterSchema(base, extensions) {
44
+ const additions = {};
45
+ for (const ext of extensions) {
46
+ additions[ext.name] = ext.required ? ext.schema : ext.schema.optional();
47
+ }
48
+ return base.extend(additions);
49
+ }
50
+ /**
51
+ * Maakt een verse, geïsoleerde post-login-hook-registry. Factory (geen module-globale mutable state):
52
+ * elke app-factory/aanroep krijgt zijn eigen registry, wat SSR/hydratie-veilig is.
53
+ */
54
+ export function createPostLoginHookRegistry() {
55
+ const hooks = [];
56
+ return {
57
+ register(name, hook) {
58
+ if (name.trim() === '')
59
+ throw new Error('Post-login-hook ongeldig: "name" mag niet leeg zijn.');
60
+ if (hooks.some((h) => h.name === name)) {
61
+ throw new Error(`Post-login-hook ongeldig: naam "${name}" is al geregistreerd.`);
62
+ }
63
+ hooks.push({ name, hook });
64
+ },
65
+ list() {
66
+ return hooks.map((h) => h.name);
67
+ },
68
+ async run(ctx) {
69
+ const ran = [];
70
+ const failed = [];
71
+ for (const { name, hook } of hooks) {
72
+ try {
73
+ await hook(ctx);
74
+ ran.push(name);
75
+ }
76
+ catch (err) {
77
+ failed.push({ name, error: err instanceof Error ? err.message : String(err) });
78
+ }
79
+ }
80
+ return { ran, failed };
81
+ },
82
+ };
83
+ }
84
+ // --- 3. Named-slot-descriptors -----------------------------------------------------------------
85
+ /** De slots die de auth-surface aanbiedt om een default-component te vervangen. */
86
+ export const AUTH_SLOT_NAMES = ['login.card', 'login.footer', 'register.card', 'register.footer'];
87
+ /**
88
+ * Definieert een slot-override (bevroren descriptor).
89
+ *
90
+ * @throws Error bij een onbekende slot-naam of een lege component-referentie
91
+ */
92
+ export function defineSlot(slot, component) {
93
+ if (!AUTH_SLOT_NAMES.includes(slot)) {
94
+ throw new Error(`Onbekend slot: "${slot}". Geldig: ${AUTH_SLOT_NAMES.join(', ')}.`);
95
+ }
96
+ if (component.trim() === '') {
97
+ throw new Error('Slot-override ongeldig: "component" mag niet leeg zijn.');
98
+ }
99
+ return Object.freeze({ slot, component });
100
+ }
101
+ /** Maakt een verse, geïsoleerde slot-registry (factory; geen module-globale mutable state). */
102
+ export function createSlotRegistry() {
103
+ const overrides = new Map();
104
+ return {
105
+ set(descriptor) {
106
+ overrides.set(descriptor.slot, descriptor);
107
+ },
108
+ get(slot) {
109
+ return overrides.get(slot);
110
+ },
111
+ list() {
112
+ return AUTH_SLOT_NAMES.map((s) => overrides.get(s)).filter((d) => d !== undefined);
113
+ },
114
+ };
115
+ }
116
+ //# sourceMappingURL=extend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extend.js","sourceRoot":"","sources":["../../../scaffolder/core/extend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * materialize — de GENERATE-stap van de version-aware materializer (US-A0803).
3
+ *
4
+ * Gegeven de surface-`FileDescriptor`s van de authentication-module schrijft deze functie ze via een
5
+ * geïnjecteerde fs-port in een doelproject. Vanaf dat moment is de surface projecteigendom en mag ze
6
+ * divergeren; het mechanisme (`backend/src`, `frontend/src`, `contract/`) blijft een gepinde dependency. De functie:
7
+ *
8
+ * - stempelt de `templateVersion` per bestand in een `MaterializationRecord` (de basis waartegen een
9
+ * latere upgrade-merge diff't — US-A0804),
10
+ * - verzamelt ÁLLE collisions en weigert all-or-nothing zonder `overwrite` (nooit stil overschrijven),
11
+ * - weigert te starten als een vereiste requires-port ontbreekt (AC3), zodat er geen half-gewirede
12
+ * surface achterblijft.
13
+ *
14
+ * Puur op de fs-port na: geen echt filesystem, geen module-globale mutable state, deterministisch
15
+ * (invoervolgorde blijft behouden, geen Date.now/random).
16
+ */
17
+ import type { CapabilityModuleManifest } from '../../manifest.js';
18
+ import type { AuthScaffolderFsPort, FileDescriptor } from './ports.js';
19
+ /** De stempel van één gematerialiseerd bestand: de bronversie én de exact geschreven basis-inhoud. */
20
+ export interface MaterializedFile {
21
+ /** De `templateVersion` waaruit dit bestand is gegenereerd. */
22
+ readonly templateVersion: string;
23
+ /** De precies gematerialiseerde template-inhoud — de `base` voor een latere three-way-merge. */
24
+ readonly base: string;
25
+ }
26
+ /**
27
+ * Het per-project stempelrecord (manifest/lockfile-vorm): welke surface-bestanden zijn gematerialiseerd,
28
+ * vanaf welke `templateVersion`, met hun basis-inhoud. `files` mapt bestand → stempel; `templateVersion`
29
+ * is de module-brede versie waarmee gematerialiseerd is.
30
+ */
31
+ export interface MaterializationRecord {
32
+ /** Module-slug, bv. 'authentication'. */
33
+ readonly module: string;
34
+ /** De module-brede templateVersion waarmee gematerialiseerd is. */
35
+ readonly templateVersion: string;
36
+ /** Bestand-pad → stempel (versie + basis-inhoud). */
37
+ readonly files: Readonly<Record<string, MaterializedFile>>;
38
+ }
39
+ /** Opties voor `materializeAuthModule`. */
40
+ export interface MaterializeOptions {
41
+ /** Het (gevalideerde) capability-manifest dat de materialisatie stuurt. */
42
+ readonly manifest: CapabilityModuleManifest;
43
+ /** De surface-bestanden die gematerialiseerd worden (uitsluitend surface — US-A0802). */
44
+ readonly surfaceFiles: readonly FileDescriptor[];
45
+ /** De geïnjecteerde fs-port; alle writes lopen hierlangs. */
46
+ readonly fsPort: AuthScaffolderFsPort;
47
+ /** Overschrijf de te stempelen versie; standaard `manifest.templateVersion`. */
48
+ readonly templateVersion?: string;
49
+ /** Sta overschrijven van bestaande bestanden toe (expliciete eject/regenerate). */
50
+ readonly overwrite?: boolean;
51
+ /**
52
+ * De requires-ports die de host levert. Wordt dit opgegeven, dan controleert de materializer dat
53
+ * `manifest.requires.ports` een deelverzameling is en weigert anders (AC3). Weggelaten = check overslaan.
54
+ */
55
+ readonly providedPorts?: readonly string[];
56
+ }
57
+ /** Resultaat van een geslaagde materialisatie: het stempelrecord + de geschreven paden (in volgorde). */
58
+ export interface MaterializeResult {
59
+ readonly record: MaterializationRecord;
60
+ readonly written: readonly string[];
61
+ }
62
+ /**
63
+ * Materialiseert de surface van de authentication-module in een project.
64
+ *
65
+ * @throws MissingRequiredPortError als een vereiste port ontbreekt (geen enkele write gebeurt)
66
+ * @throws AuthMaterializationConflictError als bestanden al bestaan en `overwrite` niet gezet is
67
+ */
68
+ export declare function materializeAuthModule(options: MaterializeOptions): MaterializeResult;
69
+ /** Convenience: het stempelrecord platgeslagen tot een pure `bestand → templateVersion`-map. */
70
+ export declare function stampedVersions(record: MaterializationRecord): Record<string, string>;
71
+ //# sourceMappingURL=materialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materialize.d.ts","sourceRoot":"","sources":["../../../scaffolder/core/materialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGvE,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;CAC5D;AAED,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;IAC5C,yFAAyF;IACzF,QAAQ,CAAC,YAAY,EAAE,SAAS,cAAc,EAAE,CAAC;IACjD,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,gFAAgF;IAChF,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,mFAAmF;IACnF,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED,yGAAyG;AACzG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAkCpF;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMrF"}
@@ -0,0 +1,47 @@
1
+ import { AuthMaterializationConflictError, MissingRequiredPortError } from './errors.js';
2
+ /**
3
+ * Materialiseert de surface van de authentication-module in een project.
4
+ *
5
+ * @throws MissingRequiredPortError als een vereiste port ontbreekt (geen enkele write gebeurt)
6
+ * @throws AuthMaterializationConflictError als bestanden al bestaan en `overwrite` niet gezet is
7
+ */
8
+ export function materializeAuthModule(options) {
9
+ const { manifest, surfaceFiles, fsPort, overwrite = false, providedPorts } = options;
10
+ const templateVersion = options.templateVersion ?? manifest.templateVersion;
11
+ // (1) Requires-ports: weiger vóór welke write dan ook als de host er één niet levert.
12
+ if (providedPorts !== undefined) {
13
+ const geleverd = new Set(providedPorts);
14
+ const missing = manifest.requires.ports.filter((port) => !geleverd.has(port));
15
+ if (missing.length > 0) {
16
+ throw new MissingRequiredPortError(missing);
17
+ }
18
+ }
19
+ // (2) Collision-check: verzamel ÁLLE conflicten en weiger all-or-nothing (nooit stil overschrijven).
20
+ if (!overwrite) {
21
+ const conflicts = surfaceFiles.filter((f) => fsPort.exists(f.path)).map((f) => f.path);
22
+ if (conflicts.length > 0) {
23
+ throw new AuthMaterializationConflictError(conflicts);
24
+ }
25
+ }
26
+ // (3) Schrijf de surface en stempel per bestand de templateVersion + de basis-inhoud.
27
+ const files = {};
28
+ const written = [];
29
+ for (const descriptor of surfaceFiles) {
30
+ fsPort.write(descriptor.path, descriptor.contents);
31
+ files[descriptor.path] = { templateVersion, base: descriptor.contents };
32
+ written.push(descriptor.path);
33
+ }
34
+ return {
35
+ record: { module: manifest.name, templateVersion, files },
36
+ written,
37
+ };
38
+ }
39
+ /** Convenience: het stempelrecord platgeslagen tot een pure `bestand → templateVersion`-map. */
40
+ export function stampedVersions(record) {
41
+ const out = {};
42
+ for (const [path, file] of Object.entries(record.files)) {
43
+ out[path] = file.templateVersion;
44
+ }
45
+ return out;
46
+ }
47
+ //# sourceMappingURL=materialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"materialize.js","sourceRoot":"","sources":["../../../scaffolder/core/materialize.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,gCAAgC,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAiDzF;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAA2B;IAC/D,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IACrF,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,QAAQ,CAAC,eAAe,CAAC;IAE5E,sFAAsF;IACtF,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,wBAAwB,CAAC,OAAO,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,qGAAqG;IACrG,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACvF,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,gCAAgC,CAAC,SAAS,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,sFAAsF;IACtF,MAAM,KAAK,GAAqC,EAAE,CAAC;IACnD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;QACnD,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,OAAO;QACL,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE;QACzD,OAAO;KACR,CAAC;AACJ,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,eAAe,CAAC,MAA6B;IAC3D,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * ports — de geïnjecteerde randen van de scaffolder. De core-functies raken NOOIT een echt
3
+ * filesystem: ze krijgen een {@link AuthScaffolderFsPort} injected en werken uitsluitend met
4
+ * {@link FileDescriptor}s. Zo blijft de materializer deterministisch, testbaar met een in-memory
5
+ * port en vrij van module-globale mutable state.
6
+ *
7
+ * Spiegelt bewust de frontend-scaffolder (`kits/frontend/.../wiring-generator.ts`): dezelfde
8
+ * `{ path, contents }`-descriptor en dezelfde kleine, synchrone fs-port — één tier hoger.
9
+ */
10
+ /** Eén te materialiseren bestand: relatief pad + volledige inhoud. Pure data, geen side-effects. */
11
+ export interface FileDescriptor {
12
+ readonly path: string;
13
+ readonly contents: string;
14
+ }
15
+ /**
16
+ * Minimale, injecteerbare fs-port. Bewust synchroon en klein zodat hij triviaal te mocken is.
17
+ * `read` is nodig omdat de upgrade-merge de (mogelijk gedivergeerde) projectbestanden moet inlezen.
18
+ */
19
+ export interface AuthScaffolderFsPort {
20
+ /** Bestaat er al een bestand op dit pad? */
21
+ exists(path: string): boolean;
22
+ /** Leest de huidige inhoud; gooit als het pad niet bestaat. */
23
+ read(path: string): string;
24
+ /** Schrijft (of overschrijft) de inhoud op dit pad. */
25
+ write(path: string, contents: string): void;
26
+ }
27
+ /** Een in-memory fs-port met een `snapshot()` erbij, voor tests én voor de re-scaffold-naar-temp-stap. */
28
+ export interface MemoryFsPort extends AuthScaffolderFsPort {
29
+ /** Geeft een gewone-object-kopie van de huidige inhoud (pad → inhoud). Deterministisch. */
30
+ snapshot(): Record<string, string>;
31
+ }
32
+ /**
33
+ * Maakt een verse, geïsoleerde in-memory fs-port. Elke aanroep levert een eigen store — geen
34
+ * module-globale mutable state, zodat parallelle tests elkaar niet besmetten.
35
+ *
36
+ * @param seed optionele begininhoud (pad → inhoud)
37
+ */
38
+ export declare function createMemoryFsPort(seed?: Readonly<Record<string, string>>): MemoryFsPort;
39
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../scaffolder/core/ports.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oGAAoG;AACpG,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,4CAA4C;IAC5C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,+DAA+D;IAC/D,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,uDAAuD;IACvD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED,0GAA0G;AAC1G,MAAM,WAAW,YAAa,SAAQ,oBAAoB;IACxD,2FAA2F;IAC3F,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,YAAY,CAgBxF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * ports — de geïnjecteerde randen van de scaffolder. De core-functies raken NOOIT een echt
3
+ * filesystem: ze krijgen een {@link AuthScaffolderFsPort} injected en werken uitsluitend met
4
+ * {@link FileDescriptor}s. Zo blijft de materializer deterministisch, testbaar met een in-memory
5
+ * port en vrij van module-globale mutable state.
6
+ *
7
+ * Spiegelt bewust de frontend-scaffolder (`kits/frontend/.../wiring-generator.ts`): dezelfde
8
+ * `{ path, contents }`-descriptor en dezelfde kleine, synchrone fs-port — één tier hoger.
9
+ */
10
+ /**
11
+ * Maakt een verse, geïsoleerde in-memory fs-port. Elke aanroep levert een eigen store — geen
12
+ * module-globale mutable state, zodat parallelle tests elkaar niet besmetten.
13
+ *
14
+ * @param seed optionele begininhoud (pad → inhoud)
15
+ */
16
+ export function createMemoryFsPort(seed) {
17
+ const store = new Map(seed ? Object.entries(seed) : []);
18
+ return {
19
+ exists: (path) => store.has(path),
20
+ read: (path) => {
21
+ const value = store.get(path);
22
+ if (value === undefined) {
23
+ throw new Error(`Bestand niet gevonden op de fs-port: ${path}`);
24
+ }
25
+ return value;
26
+ },
27
+ write: (path, contents) => {
28
+ store.set(path, contents);
29
+ },
30
+ snapshot: () => Object.fromEntries([...store.entries()].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))),
31
+ };
32
+ }
33
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../../scaffolder/core/ports.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2BH;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAuC;IACxE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAiB,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxE,OAAO;QACL,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QACjC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;YACb,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;YACxB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC5B,CAAC;QACD,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAC1G,CAAC;AACJ,CAAC"}