@rhino-dev/rhino-nestjs 0.2.5

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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +427 -0
  3. package/dist/blueprint/blueprint-parser.d.ts +130 -0
  4. package/dist/blueprint/blueprint-parser.js +276 -0
  5. package/dist/blueprint/blueprint-parser.js.map +1 -0
  6. package/dist/blueprint/blueprint-runner.d.ts +51 -0
  7. package/dist/blueprint/blueprint-runner.js +238 -0
  8. package/dist/blueprint/blueprint-runner.js.map +1 -0
  9. package/dist/blueprint/blueprint-validator.d.ts +19 -0
  10. package/dist/blueprint/blueprint-validator.js +163 -0
  11. package/dist/blueprint/blueprint-validator.js.map +1 -0
  12. package/dist/blueprint/generators/policy-generator.d.ts +40 -0
  13. package/dist/blueprint/generators/policy-generator.js +157 -0
  14. package/dist/blueprint/generators/policy-generator.js.map +1 -0
  15. package/dist/blueprint/generators/prisma-schema-generator.d.ts +43 -0
  16. package/dist/blueprint/generators/prisma-schema-generator.js +197 -0
  17. package/dist/blueprint/generators/prisma-schema-generator.js.map +1 -0
  18. package/dist/blueprint/generators/resource-definition-generator.d.ts +52 -0
  19. package/dist/blueprint/generators/resource-definition-generator.js +229 -0
  20. package/dist/blueprint/generators/resource-definition-generator.js.map +1 -0
  21. package/dist/blueprint/generators/seeder-generator.d.ts +21 -0
  22. package/dist/blueprint/generators/seeder-generator.js +135 -0
  23. package/dist/blueprint/generators/seeder-generator.js.map +1 -0
  24. package/dist/blueprint/generators/test-generator.d.ts +28 -0
  25. package/dist/blueprint/generators/test-generator.js +275 -0
  26. package/dist/blueprint/generators/test-generator.js.map +1 -0
  27. package/dist/blueprint/manifest-manager.d.ts +58 -0
  28. package/dist/blueprint/manifest-manager.js +137 -0
  29. package/dist/blueprint/manifest-manager.js.map +1 -0
  30. package/dist/cli/commands/blueprint.command.d.ts +16 -0
  31. package/dist/cli/commands/blueprint.command.js +35 -0
  32. package/dist/cli/commands/blueprint.command.js.map +1 -0
  33. package/dist/cli/commands/export-postman.command.d.ts +5 -0
  34. package/dist/cli/commands/export-postman.command.js +39 -0
  35. package/dist/cli/commands/export-postman.command.js.map +1 -0
  36. package/dist/cli/commands/export-types.command.d.ts +4 -0
  37. package/dist/cli/commands/export-types.command.js +36 -0
  38. package/dist/cli/commands/export-types.command.js.map +1 -0
  39. package/dist/cli/commands/generate.command.d.ts +6 -0
  40. package/dist/cli/commands/generate.command.js +212 -0
  41. package/dist/cli/commands/generate.command.js.map +1 -0
  42. package/dist/cli/commands/install.command.d.ts +8 -0
  43. package/dist/cli/commands/install.command.js +205 -0
  44. package/dist/cli/commands/install.command.js.map +1 -0
  45. package/dist/cli/index.d.ts +17 -0
  46. package/dist/cli/index.js +123 -0
  47. package/dist/cli/index.js.map +1 -0
  48. package/dist/cli/utils/io.d.ts +12 -0
  49. package/dist/cli/utils/io.js +74 -0
  50. package/dist/cli/utils/io.js.map +1 -0
  51. package/dist/cli/utils/prompt.d.ts +12 -0
  52. package/dist/cli/utils/prompt.js +78 -0
  53. package/dist/cli/utils/prompt.js.map +1 -0
  54. package/dist/constants/tokens.d.ts +3 -0
  55. package/dist/constants/tokens.js +7 -0
  56. package/dist/constants/tokens.js.map +1 -0
  57. package/dist/controllers/auth.controller.d.ts +59 -0
  58. package/dist/controllers/auth.controller.js +121 -0
  59. package/dist/controllers/auth.controller.js.map +1 -0
  60. package/dist/controllers/global.controller.d.ts +44 -0
  61. package/dist/controllers/global.controller.js +357 -0
  62. package/dist/controllers/global.controller.js.map +1 -0
  63. package/dist/controllers/invitation.controller.d.ts +30 -0
  64. package/dist/controllers/invitation.controller.js +111 -0
  65. package/dist/controllers/invitation.controller.js.map +1 -0
  66. package/dist/controllers/nested.controller.d.ts +12 -0
  67. package/dist/controllers/nested.controller.js +69 -0
  68. package/dist/controllers/nested.controller.js.map +1 -0
  69. package/dist/decorators/index.d.ts +33 -0
  70. package/dist/decorators/index.js +79 -0
  71. package/dist/decorators/index.js.map +1 -0
  72. package/dist/errors/rhino-exception.d.ts +24 -0
  73. package/dist/errors/rhino-exception.js +47 -0
  74. package/dist/errors/rhino-exception.js.map +1 -0
  75. package/dist/exporters/postman-exporter.d.ts +21 -0
  76. package/dist/exporters/postman-exporter.js +396 -0
  77. package/dist/exporters/postman-exporter.js.map +1 -0
  78. package/dist/exporters/typescript-exporter.d.ts +23 -0
  79. package/dist/exporters/typescript-exporter.js +129 -0
  80. package/dist/exporters/typescript-exporter.js.map +1 -0
  81. package/dist/guards/jwt-auth.guard.d.ts +16 -0
  82. package/dist/guards/jwt-auth.guard.js +61 -0
  83. package/dist/guards/jwt-auth.guard.js.map +1 -0
  84. package/dist/guards/resource-policy.guard.d.ts +12 -0
  85. package/dist/guards/resource-policy.guard.js +111 -0
  86. package/dist/guards/resource-policy.guard.js.map +1 -0
  87. package/dist/index.d.ts +60 -0
  88. package/dist/index.js +171 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/interceptors/hidden-columns.interceptor.d.ts +18 -0
  91. package/dist/interceptors/hidden-columns.interceptor.js +66 -0
  92. package/dist/interceptors/hidden-columns.interceptor.js.map +1 -0
  93. package/dist/interceptors/response.interceptor.d.ts +19 -0
  94. package/dist/interceptors/response.interceptor.js +47 -0
  95. package/dist/interceptors/response.interceptor.js.map +1 -0
  96. package/dist/interfaces/rhino-config.interface.d.ts +103 -0
  97. package/dist/interfaces/rhino-config.interface.js +3 -0
  98. package/dist/interfaces/rhino-config.interface.js.map +1 -0
  99. package/dist/interfaces/rhino-request.interface.d.ts +12 -0
  100. package/dist/interfaces/rhino-request.interface.js +3 -0
  101. package/dist/interfaces/rhino-request.interface.js.map +1 -0
  102. package/dist/middleware/resolve-organization.middleware.d.ts +15 -0
  103. package/dist/middleware/resolve-organization.middleware.js +38 -0
  104. package/dist/middleware/resolve-organization.middleware.js.map +1 -0
  105. package/dist/middleware/route-group.middleware.d.ts +17 -0
  106. package/dist/middleware/route-group.middleware.js +60 -0
  107. package/dist/middleware/route-group.middleware.js.map +1 -0
  108. package/dist/middleware/tenant-route-rewrite.d.ts +76 -0
  109. package/dist/middleware/tenant-route-rewrite.js +124 -0
  110. package/dist/middleware/tenant-route-rewrite.js.map +1 -0
  111. package/dist/policies/resource-policy.d.ts +25 -0
  112. package/dist/policies/resource-policy.js +77 -0
  113. package/dist/policies/resource-policy.js.map +1 -0
  114. package/dist/prisma/prisma-soft-delete.extension.d.ts +16 -0
  115. package/dist/prisma/prisma-soft-delete.extension.js +57 -0
  116. package/dist/prisma/prisma-soft-delete.extension.js.map +1 -0
  117. package/dist/prisma/prisma-uuid.extension.d.ts +9 -0
  118. package/dist/prisma/prisma-uuid.extension.js +28 -0
  119. package/dist/prisma/prisma-uuid.extension.js.map +1 -0
  120. package/dist/prisma/prisma.service.d.ts +38 -0
  121. package/dist/prisma/prisma.service.js +100 -0
  122. package/dist/prisma/prisma.service.js.map +1 -0
  123. package/dist/rhino.config.d.ts +43 -0
  124. package/dist/rhino.config.js +130 -0
  125. package/dist/rhino.config.js.map +1 -0
  126. package/dist/rhino.module.d.ts +61 -0
  127. package/dist/rhino.module.js +268 -0
  128. package/dist/rhino.module.js.map +1 -0
  129. package/dist/services/audit.service.d.ts +35 -0
  130. package/dist/services/audit.service.js +92 -0
  131. package/dist/services/audit.service.js.map +1 -0
  132. package/dist/services/auth.service.d.ts +33 -0
  133. package/dist/services/auth.service.js +157 -0
  134. package/dist/services/auth.service.js.map +1 -0
  135. package/dist/services/invitation.service.d.ts +37 -0
  136. package/dist/services/invitation.service.js +143 -0
  137. package/dist/services/invitation.service.js.map +1 -0
  138. package/dist/services/nested.service.d.ts +34 -0
  139. package/dist/services/nested.service.js +163 -0
  140. package/dist/services/nested.service.js.map +1 -0
  141. package/dist/services/organization.service.d.ts +13 -0
  142. package/dist/services/organization.service.js +60 -0
  143. package/dist/services/organization.service.js.map +1 -0
  144. package/dist/services/query-builder.service.d.ts +31 -0
  145. package/dist/services/query-builder.service.js +151 -0
  146. package/dist/services/query-builder.service.js.map +1 -0
  147. package/dist/services/resource.service.d.ts +38 -0
  148. package/dist/services/resource.service.js +230 -0
  149. package/dist/services/resource.service.js.map +1 -0
  150. package/dist/services/route-registration.service.d.ts +40 -0
  151. package/dist/services/route-registration.service.js +68 -0
  152. package/dist/services/route-registration.service.js.map +1 -0
  153. package/dist/services/scope.service.d.ts +16 -0
  154. package/dist/services/scope.service.js +32 -0
  155. package/dist/services/scope.service.js.map +1 -0
  156. package/dist/services/serializer.service.d.ts +36 -0
  157. package/dist/services/serializer.service.js +90 -0
  158. package/dist/services/serializer.service.js.map +1 -0
  159. package/dist/services/validation.service.d.ts +50 -0
  160. package/dist/services/validation.service.js +203 -0
  161. package/dist/services/validation.service.js.map +1 -0
  162. package/dist/tsconfig.build.tsbuildinfo +1 -0
  163. package/dist/utils/fk-chain-walker.d.ts +30 -0
  164. package/dist/utils/fk-chain-walker.js +23 -0
  165. package/dist/utils/fk-chain-walker.js.map +1 -0
  166. package/dist/utils/format.d.ts +7 -0
  167. package/dist/utils/format.js +28 -0
  168. package/dist/utils/format.js.map +1 -0
  169. package/dist/utils/model-builder.d.ts +64 -0
  170. package/dist/utils/model-builder.js +67 -0
  171. package/dist/utils/model-builder.js.map +1 -0
  172. package/dist/utils/permission-matcher.d.ts +46 -0
  173. package/dist/utils/permission-matcher.js +120 -0
  174. package/dist/utils/permission-matcher.js.map +1 -0
  175. package/dist/utils/scope-discovery.d.ts +34 -0
  176. package/dist/utils/scope-discovery.js +102 -0
  177. package/dist/utils/scope-discovery.js.map +1 -0
  178. package/package.json +64 -0
  179. package/stubs/skills/rhino-audit.md +184 -0
  180. package/stubs/skills/rhino-bugfix.md +117 -0
  181. package/stubs/skills/rhino-deploy.md +5 -0
  182. package/stubs/skills/rhino-docs.md +147 -0
  183. package/stubs/skills/rhino-feature.md +146 -0
  184. package/stubs/skills/rhino-migrate.md +181 -0
  185. package/stubs/skills/rhino-model.md +180 -0
  186. package/stubs/skills/rhino-plan.md +5 -0
  187. package/stubs/skills/rhino-policy.md +183 -0
  188. package/stubs/skills/rhino-refactor.md +147 -0
  189. package/stubs/skills/rhino-review.md +113 -0
  190. package/stubs/skills/rhino-scope.md +140 -0
  191. package/stubs/skills/rhino-test.md +233 -0
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BlueprintValidator = void 0;
4
+ // ---------------------------------------------------------------------------
5
+ // Valid values
6
+ // ---------------------------------------------------------------------------
7
+ const VALID_COLUMN_TYPES = [
8
+ 'string', 'text', 'integer', 'bigInteger', 'boolean',
9
+ 'date', 'datetime', 'timestamp', 'decimal', 'float',
10
+ 'json', 'uuid', 'foreignId', 'enum',
11
+ ];
12
+ const VALID_ACTIONS = [
13
+ 'index', 'show', 'store', 'update', 'destroy',
14
+ 'trashed', 'restore', 'forceDelete',
15
+ ];
16
+ const VALID_RELATIONSHIP_TYPES = ['belongsTo', 'hasMany', 'hasOne', 'belongsToMany'];
17
+ // ---------------------------------------------------------------------------
18
+ // Validator
19
+ // ---------------------------------------------------------------------------
20
+ class BlueprintValidator {
21
+ /**
22
+ * Validate a parsed Blueprint. Returns errors and warnings.
23
+ *
24
+ * @param blueprint Parsed blueprint from BlueprintParser.parseModel()
25
+ * @param validRoles Optional array of known role slugs — enables stricter role checks
26
+ */
27
+ validate(blueprint, validRoles = []) {
28
+ const errors = [];
29
+ const warnings = [];
30
+ // -- model name ----------------------------------------------------------
31
+ if (!blueprint.model) {
32
+ errors.push('Model name is required.');
33
+ }
34
+ else if (!/^[A-Z][a-zA-Z0-9]*$/.test(blueprint.model)) {
35
+ errors.push(`Model name '${blueprint.model}' must be PascalCase (e.g., 'Post', 'BlogPost').`);
36
+ }
37
+ // -- slug ----------------------------------------------------------------
38
+ if (blueprint.slug && !/^[a-z][a-z0-9_-]*$/.test(blueprint.slug)) {
39
+ errors.push(`Slug '${blueprint.slug}' must be lowercase alphanumeric with hyphens/underscores.`);
40
+ }
41
+ // -- columns -------------------------------------------------------------
42
+ const colErrors = this.validateColumns(blueprint.columns ?? []);
43
+ errors.push(...colErrors);
44
+ // -- permissions ---------------------------------------------------------
45
+ const columnNames = (blueprint.columns ?? []).map((c) => c.name);
46
+ const permResult = this.validatePermissions(blueprint.permissions ?? {}, validRoles, columnNames);
47
+ errors.push(...permResult.errors);
48
+ warnings.push(...permResult.warnings);
49
+ // -- options -------------------------------------------------------------
50
+ const optErrors = this.validateOptions(blueprint.options);
51
+ errors.push(...optErrors);
52
+ // -- relationships -------------------------------------------------------
53
+ const relErrors = this.validateRelationships(blueprint.relationships ?? []);
54
+ errors.push(...relErrors);
55
+ return { valid: errors.length === 0, errors, warnings };
56
+ }
57
+ // -------------------------------------------------------------------------
58
+ // Section validators
59
+ // -------------------------------------------------------------------------
60
+ validateColumns(columns) {
61
+ const errors = [];
62
+ const seen = new Set();
63
+ for (const col of columns) {
64
+ if (!col.name) {
65
+ errors.push('Column name cannot be empty.');
66
+ continue;
67
+ }
68
+ if (seen.has(col.name)) {
69
+ errors.push(`Duplicate column name: '${col.name}'.`);
70
+ }
71
+ seen.add(col.name);
72
+ if (!VALID_COLUMN_TYPES.includes(col.type)) {
73
+ errors.push(`Column '${col.name}' has invalid type '${col.type}'. Valid types: ${VALID_COLUMN_TYPES.join(', ')}.`);
74
+ }
75
+ if (col.type === 'foreignId' && !col.foreignModel) {
76
+ errors.push(`Column '${col.name}' has type foreignId but is missing 'foreign_model'.`);
77
+ }
78
+ if (col.type === 'enum' && (!col.values || col.values.length === 0)) {
79
+ errors.push(`Column '${col.name}' has type enum but is missing 'values'.`);
80
+ }
81
+ }
82
+ return errors;
83
+ }
84
+ validatePermissions(permissions, validRoles, columnNames) {
85
+ const errors = [];
86
+ const warnings = [];
87
+ for (const [role, def] of Object.entries(permissions)) {
88
+ // Validate role exists (if roles list provided)
89
+ if (validRoles.length > 0 && !validRoles.includes(role)) {
90
+ errors.push(`Permission defined for unknown role '${role}'. Define it in your roles list first.`);
91
+ }
92
+ // Validate actions
93
+ for (const action of def.actions ?? []) {
94
+ if (!VALID_ACTIONS.includes(action)) {
95
+ errors.push(`Role '${role}' has invalid action '${action}'. Valid actions: ${VALID_ACTIONS.join(', ')}.`);
96
+ }
97
+ }
98
+ // Warn about unknown fields in show_fields
99
+ const showFields = def.show_fields ?? [];
100
+ if (showFields[0] !== '*' && columnNames.length > 0) {
101
+ for (const field of showFields) {
102
+ if (field !== 'id' && !columnNames.includes(field)) {
103
+ warnings.push(`Role '${role}' references unknown field '${field}' in show_fields.`);
104
+ }
105
+ }
106
+ }
107
+ // Conflicts: field in both show_fields and hidden_fields
108
+ const hiddenFields = def.hidden_fields ?? [];
109
+ if (showFields[0] !== '*' && hiddenFields.length > 0) {
110
+ const conflicts = showFields.filter((f) => hiddenFields.includes(f));
111
+ if (conflicts.length > 0) {
112
+ warnings.push(`Role '${role}' has fields in both show_fields and hidden_fields: ${conflicts.join(', ')}.`);
113
+ }
114
+ }
115
+ // Warn if create_fields defined without store action
116
+ const createFields = def.create_fields;
117
+ const hasCreateFields = createFields &&
118
+ !(Array.isArray(createFields) && createFields[0] === '*') &&
119
+ (Array.isArray(createFields) ? createFields.length > 0 : Object.keys(createFields).length > 0);
120
+ if (hasCreateFields && !def.actions.includes('store')) {
121
+ warnings.push(`Role '${role}' has create_fields but no 'store' action.`);
122
+ }
123
+ // Warn if update_fields defined without update action
124
+ const updateFields = def.update_fields;
125
+ const hasUpdateFields = updateFields &&
126
+ !(Array.isArray(updateFields) && updateFields[0] === '*') &&
127
+ (Array.isArray(updateFields) ? updateFields.length > 0 : Object.keys(updateFields).length > 0);
128
+ if (hasUpdateFields && !def.actions.includes('update')) {
129
+ warnings.push(`Role '${role}' has update_fields but no 'update' action.`);
130
+ }
131
+ }
132
+ return { errors, warnings };
133
+ }
134
+ validateOptions(options) {
135
+ const errors = [];
136
+ if (!options)
137
+ return errors;
138
+ for (const action of options.except_actions ?? []) {
139
+ if (!VALID_ACTIONS.includes(action)) {
140
+ errors.push(`Invalid except_action: '${action}'.`);
141
+ }
142
+ }
143
+ return errors;
144
+ }
145
+ validateRelationships(relationships) {
146
+ const errors = [];
147
+ for (const rel of relationships) {
148
+ if (!rel.type) {
149
+ errors.push('Relationship is missing type.');
150
+ continue;
151
+ }
152
+ if (!VALID_RELATIONSHIP_TYPES.includes(rel.type)) {
153
+ errors.push(`Invalid relationship type '${rel.type}'. Valid: ${VALID_RELATIONSHIP_TYPES.join(', ')}.`);
154
+ }
155
+ if (!rel.model) {
156
+ errors.push(`Relationship '${rel.name}' of type '${rel.type}' is missing model.`);
157
+ }
158
+ }
159
+ return errors;
160
+ }
161
+ }
162
+ exports.BlueprintValidator = BlueprintValidator;
163
+ //# sourceMappingURL=blueprint-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprint-validator.js","sourceRoot":"","sources":["../../src/blueprint/blueprint-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { Blueprint, BlueprintPermission } from '../blueprint-parser';
2
+ /**
3
+ * Generates a TypeScript Policy class extending `ResourcePolicy`.
4
+ *
5
+ * The generated class overrides:
6
+ * - `permittedAttributesForShow` — from `show_fields`
7
+ * - `hiddenAttributesForShow` — from `hidden_fields`
8
+ * - `permittedAttributesForCreate` — from `create_fields`
9
+ * - `permittedAttributesForUpdate` — from `update_fields`
10
+ *
11
+ * Each method uses `this.hasRole(user, '<role>', org)` guards identical to the
12
+ * Laravel reference implementation.
13
+ */
14
+ export declare class PolicyGenerator {
15
+ generate(blueprint: Blueprint): string;
16
+ /**
17
+ * Build a `permittedAttributesFor*` method.
18
+ * Groups roles with identical field sets to avoid repetitive if-branches.
19
+ */
20
+ buildPermittedMethod(methodName: string, permissions: Record<string, BlueprintPermission>, fieldKey: 'show_fields' | 'create_fields' | 'update_fields'): string;
21
+ buildHiddenMethod(permissions: Record<string, BlueprintPermission>): string;
22
+ /**
23
+ * Group roles that share the same field set for a given field key.
24
+ */
25
+ groupRolesByFields(permissions: Record<string, BlueprintPermission>, fieldKey: 'show_fields' | 'create_fields' | 'update_fields'): Array<{
26
+ fields: unknown;
27
+ roles: string[];
28
+ }>;
29
+ /**
30
+ * Normalise `fields` to a string array or null.
31
+ * - ['*'] / '*' → ['*']
32
+ * - string[] → as-is
33
+ * - Record<string, string> → Object.keys(…)
34
+ * - [] / {} / null → null (skip)
35
+ */
36
+ private toFieldsArray;
37
+ buildCondition(roles: string[]): string;
38
+ fieldsToTsArray(fields: string[]): string;
39
+ private wrapMethod;
40
+ }
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PolicyGenerator = void 0;
4
+ // ---------------------------------------------------------------------------
5
+ // PolicyGenerator
6
+ // ---------------------------------------------------------------------------
7
+ /**
8
+ * Generates a TypeScript Policy class extending `ResourcePolicy`.
9
+ *
10
+ * The generated class overrides:
11
+ * - `permittedAttributesForShow` — from `show_fields`
12
+ * - `hiddenAttributesForShow` — from `hidden_fields`
13
+ * - `permittedAttributesForCreate` — from `create_fields`
14
+ * - `permittedAttributesForUpdate` — from `update_fields`
15
+ *
16
+ * Each method uses `this.hasRole(user, '<role>', org)` guards identical to the
17
+ * Laravel reference implementation.
18
+ */
19
+ class PolicyGenerator {
20
+ generate(blueprint) {
21
+ const { model, slug, permissions } = blueprint;
22
+ const policyName = `${model}Policy`;
23
+ const showMethod = this.buildPermittedMethod('permittedAttributesForShow', permissions, 'show_fields');
24
+ const hiddenMethod = this.buildHiddenMethod(permissions);
25
+ const createMethod = this.buildPermittedMethod('permittedAttributesForCreate', permissions, 'create_fields');
26
+ const updateMethod = this.buildPermittedMethod('permittedAttributesForUpdate', permissions, 'update_fields');
27
+ return [
28
+ `// Generated by Rhino Blueprint — do not edit directly.`,
29
+ `// Source: .rhino/blueprints/${blueprint.source_file}`,
30
+ `import { ResourcePolicy } from '@rhino-dev/rhino-nestjs';`,
31
+ ``,
32
+ `/**`,
33
+ ` * Authorization policy for the ${model} resource.`,
34
+ ` * Regenerate with: npx rhino blueprint`,
35
+ ` */`,
36
+ `export class ${policyName} extends ResourcePolicy {`,
37
+ ` override resourceSlug = '${slug}';`,
38
+ ``,
39
+ showMethod,
40
+ ``,
41
+ hiddenMethod,
42
+ ``,
43
+ createMethod,
44
+ ``,
45
+ updateMethod,
46
+ `}`,
47
+ ``,
48
+ ].join('\n');
49
+ }
50
+ // -------------------------------------------------------------------------
51
+ // Method builders
52
+ // -------------------------------------------------------------------------
53
+ /**
54
+ * Build a `permittedAttributesFor*` method.
55
+ * Groups roles with identical field sets to avoid repetitive if-branches.
56
+ */
57
+ buildPermittedMethod(methodName, permissions, fieldKey) {
58
+ if (Object.keys(permissions).length === 0) {
59
+ return this.wrapMethod(methodName, ` return ['*'];`);
60
+ }
61
+ const groups = this.groupRolesByFields(permissions, fieldKey);
62
+ const bodyLines = [];
63
+ for (const { fields, roles } of groups) {
64
+ const fieldArr = this.toFieldsArray(fields);
65
+ if (!fieldArr || fieldArr.length === 0)
66
+ continue; // skip roles with no fields
67
+ const condition = this.buildCondition(roles);
68
+ bodyLines.push(` if (${condition}) {`);
69
+ bodyLines.push(` return ${this.fieldsToTsArray(fieldArr)};`);
70
+ bodyLines.push(` }`);
71
+ }
72
+ bodyLines.push(` return [];`);
73
+ return this.wrapMethod(methodName, bodyLines.join('\n'));
74
+ }
75
+ buildHiddenMethod(permissions) {
76
+ const rolesWithHidden = {};
77
+ for (const [role, def] of Object.entries(permissions)) {
78
+ if (def.hidden_fields?.length > 0) {
79
+ rolesWithHidden[role] = def.hidden_fields;
80
+ }
81
+ }
82
+ if (Object.keys(rolesWithHidden).length === 0) {
83
+ return this.wrapMethod('hiddenAttributesForShow', ` return [];`);
84
+ }
85
+ // Group by field set
86
+ const groups = new Map();
87
+ for (const [role, fields] of Object.entries(rolesWithHidden)) {
88
+ const key = JSON.stringify(fields);
89
+ if (!groups.has(key))
90
+ groups.set(key, { fields, roles: [] });
91
+ groups.get(key).roles.push(role);
92
+ }
93
+ const bodyLines = [];
94
+ for (const { fields, roles } of groups.values()) {
95
+ const condition = this.buildCondition(roles);
96
+ bodyLines.push(` if (${condition}) {`);
97
+ bodyLines.push(` return ${this.fieldsToTsArray(fields)};`);
98
+ bodyLines.push(` }`);
99
+ }
100
+ bodyLines.push(` return [];`);
101
+ return this.wrapMethod('hiddenAttributesForShow', bodyLines.join('\n'));
102
+ }
103
+ // -------------------------------------------------------------------------
104
+ // Helpers
105
+ // -------------------------------------------------------------------------
106
+ /**
107
+ * Group roles that share the same field set for a given field key.
108
+ */
109
+ groupRolesByFields(permissions, fieldKey) {
110
+ const groups = new Map();
111
+ for (const [role, def] of Object.entries(permissions)) {
112
+ const fields = def[fieldKey];
113
+ const key = JSON.stringify(fields);
114
+ if (!groups.has(key))
115
+ groups.set(key, { fields, roles: [] });
116
+ groups.get(key).roles.push(role);
117
+ }
118
+ return Array.from(groups.values());
119
+ }
120
+ /**
121
+ * Normalise `fields` to a string array or null.
122
+ * - ['*'] / '*' → ['*']
123
+ * - string[] → as-is
124
+ * - Record<string, string> → Object.keys(…)
125
+ * - [] / {} / null → null (skip)
126
+ */
127
+ toFieldsArray(fields) {
128
+ if (fields === '*' || (Array.isArray(fields) && fields[0] === '*'))
129
+ return ['*'];
130
+ if (Array.isArray(fields))
131
+ return fields.length > 0 ? fields : null;
132
+ if (fields && typeof fields === 'object') {
133
+ const keys = Object.keys(fields);
134
+ return keys.length > 0 ? keys : null;
135
+ }
136
+ return null;
137
+ }
138
+ buildCondition(roles) {
139
+ const parts = roles.map((r) => `this.hasRole(user, '${r}', org)`);
140
+ return parts.join(' ||\n ');
141
+ }
142
+ fieldsToTsArray(fields) {
143
+ if (fields[0] === '*')
144
+ return `['*']`;
145
+ const items = fields.map((f) => `'${f}'`).join(', ');
146
+ return `[${items}]`;
147
+ }
148
+ wrapMethod(name, body) {
149
+ return [
150
+ ` override ${name}(user: any, org?: any): string[] {`,
151
+ body,
152
+ ` }`,
153
+ ].join('\n');
154
+ }
155
+ }
156
+ exports.PolicyGenerator = PolicyGenerator;
157
+ //# sourceMappingURL=policy-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-generator.js","sourceRoot":"","sources":["../../../src/blueprint/generators/policy-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { Blueprint } from '../blueprint-parser';
2
+ export type PrismaProvider = 'sqlite' | 'postgresql' | 'mysql' | 'sqlserver' | 'mongodb';
3
+ export interface PrismaSchemaGenerateOptions {
4
+ /**
5
+ * Target datasource provider. SQLite has no native Decimal; `decimal`
6
+ * columns map to `Float` for SQLite and `Decimal` elsewhere. Defaults to
7
+ * `postgresql`.
8
+ */
9
+ provider?: PrismaProvider;
10
+ /**
11
+ * Existing `prisma/schema.prisma` content. When provided, any model whose
12
+ * name already appears is SKIPPED — the generator returns an empty string
13
+ * for that model block. Consumer's hand-authored schemas are preserved.
14
+ * (BP-002 — no more duplicate `model Foo { ... }` blocks.)
15
+ */
16
+ existingSchema?: string;
17
+ }
18
+ /**
19
+ * Generates a Prisma `model` block (plus any required enum declarations)
20
+ * from a Blueprint.
21
+ *
22
+ * BP-002 corrections:
23
+ * - Skip generation when the model already exists in `existingSchema`
24
+ * - Emit proper `@relation(fields, references)` for `foreignId` columns
25
+ * that name a `foreign_model`
26
+ * - Switch `decimal` → `Float` on SQLite; keep `Decimal` on other providers
27
+ * - Honor `has_uuid` for the primary key (already in place via BP-005)
28
+ */
29
+ export declare class PrismaSchemaGenerator {
30
+ generate(blueprint: Blueprint, options?: PrismaSchemaGenerateOptions): string;
31
+ private generateEnum;
32
+ private generateModelBlock;
33
+ private generateRelationship;
34
+ private generateField;
35
+ }
36
+ /**
37
+ * Return true when the given schema text declares `model <name> { ... }`.
38
+ * Matches the canonical Prisma syntax; doesn't try to parse comments or
39
+ * unusual whitespace — just a pragmatic check for "is this name taken".
40
+ */
41
+ export declare function modelExistsInSchema(schema: string, modelName: string): boolean;
42
+ /** Same, for top-level `enum <Name> { ... }` declarations. */
43
+ export declare function enumExistsInSchema(schema: string, enumName: string): boolean;
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PrismaSchemaGenerator = void 0;
4
+ exports.modelExistsInSchema = modelExistsInSchema;
5
+ exports.enumExistsInSchema = enumExistsInSchema;
6
+ // ---------------------------------------------------------------------------
7
+ // Prisma type mapping
8
+ // ---------------------------------------------------------------------------
9
+ const BASE_TYPE_MAP = {
10
+ string: 'String',
11
+ text: 'String',
12
+ integer: 'Int',
13
+ bigInteger: 'BigInt',
14
+ boolean: 'Boolean',
15
+ date: 'DateTime',
16
+ datetime: 'DateTime',
17
+ timestamp: 'DateTime',
18
+ float: 'Float',
19
+ json: 'Json',
20
+ uuid: 'String',
21
+ foreignId: 'Int',
22
+ // decimal — provider-dependent (see typeFor)
23
+ // enum — handled specially
24
+ };
25
+ // ---------------------------------------------------------------------------
26
+ // PrismaSchemaGenerator
27
+ // ---------------------------------------------------------------------------
28
+ /**
29
+ * Generates a Prisma `model` block (plus any required enum declarations)
30
+ * from a Blueprint.
31
+ *
32
+ * BP-002 corrections:
33
+ * - Skip generation when the model already exists in `existingSchema`
34
+ * - Emit proper `@relation(fields, references)` for `foreignId` columns
35
+ * that name a `foreign_model`
36
+ * - Switch `decimal` → `Float` on SQLite; keep `Decimal` on other providers
37
+ * - Honor `has_uuid` for the primary key (already in place via BP-005)
38
+ */
39
+ class PrismaSchemaGenerator {
40
+ generate(blueprint, options = {}) {
41
+ const provider = options.provider ?? 'postgresql';
42
+ // BP-002: if the model already exists in the consumer's schema, produce
43
+ // NOTHING. This is the safe default — don't duplicate, don't overwrite.
44
+ if (options.existingSchema && modelExistsInSchema(options.existingSchema, blueprint.model)) {
45
+ return '';
46
+ }
47
+ const parts = [];
48
+ const existing = options.existingSchema ?? '';
49
+ for (const col of blueprint.columns) {
50
+ if (col.type === 'enum' && col.values?.length) {
51
+ const enumName = `${blueprint.model}${pascalCase(col.name)}`;
52
+ // Don't redeclare enums that already exist
53
+ if (!enumExistsInSchema(existing, enumName)) {
54
+ parts.push(this.generateEnum(enumName, col));
55
+ }
56
+ }
57
+ }
58
+ parts.push(this.generateModelBlock(blueprint, provider));
59
+ return parts.join('\n\n');
60
+ }
61
+ // -------------------------------------------------------------------------
62
+ // Private helpers
63
+ // -------------------------------------------------------------------------
64
+ generateEnum(enumName, col) {
65
+ const values = (col.values ?? []).map((v) => ` ${v.toUpperCase()}`).join('\n');
66
+ return `enum ${enumName} {\n${values}\n}`;
67
+ }
68
+ generateModelBlock(blueprint, provider) {
69
+ const lines = [];
70
+ // -- id ---------------------------------------------------------------
71
+ if (blueprint.options.has_uuid) {
72
+ lines.push(' id String @id @default(uuid())');
73
+ }
74
+ else {
75
+ lines.push(' id Int @id @default(autoincrement())');
76
+ }
77
+ // -- organizationId FK ------------------------------------------------
78
+ if (blueprint.options.belongs_to_organization) {
79
+ lines.push(' organizationId Int');
80
+ lines.push(' organization Organization @relation(fields: [organizationId], references: [id])');
81
+ }
82
+ // -- user-defined columns --------------------------------------------
83
+ // For `foreignId` columns with a `foreign_model`, emit the FK column
84
+ // immediately followed by the @relation field. Dedupe the relation fields
85
+ // emitted by `relationships:` so we don't generate both.
86
+ const fkColumnsWithRelation = new Set();
87
+ for (const col of blueprint.columns) {
88
+ lines.push(this.generateField(blueprint.model, col, provider));
89
+ if (col.type === 'foreignId' && col.foreignModel) {
90
+ fkColumnsWithRelation.add(col.name);
91
+ const relName = stripIdSuffix(col.name); // projectId → project
92
+ const modelRef = col.nullable ? `${col.foreignModel}?` : col.foreignModel;
93
+ lines.push(` ${relName.padEnd(12)} ${modelRef} @relation(fields: [${col.name}], references: [id])`);
94
+ }
95
+ }
96
+ // -- relationships ----------------------------------------------------
97
+ for (const rel of blueprint.relationships) {
98
+ this.generateRelationship(rel, fkColumnsWithRelation, lines);
99
+ }
100
+ // -- timestamps -------------------------------------------------------
101
+ lines.push(' createdAt DateTime @default(now())');
102
+ lines.push(' updatedAt DateTime @updatedAt');
103
+ if (blueprint.options.soft_deletes) {
104
+ lines.push(' deletedAt DateTime?');
105
+ }
106
+ // -- @@map ------------------------------------------------------------
107
+ lines.push('');
108
+ lines.push(` @@map("${blueprint.table}")`);
109
+ return `model ${blueprint.model} {\n${lines.join('\n')}\n}`;
110
+ }
111
+ generateRelationship(rel, alreadyEmitted, lines) {
112
+ if (rel.type === 'belongsTo') {
113
+ // Skip when we already emitted this FK + @relation from a `foreignId`
114
+ // column (avoids duplicate relation fields).
115
+ const fkField = `${rel.name}Id`;
116
+ if (alreadyEmitted.has(fkField))
117
+ return;
118
+ lines.push(` ${fkField.padEnd(12)} Int`);
119
+ lines.push(` ${rel.name.padEnd(12)} ${rel.model} @relation(fields: [${fkField}], references: [id])`);
120
+ }
121
+ else if (rel.type === 'hasMany') {
122
+ lines.push(` ${rel.name.padEnd(12)} ${rel.model}[]`);
123
+ }
124
+ else if (rel.type === 'hasOne') {
125
+ lines.push(` ${rel.name.padEnd(12)} ${rel.model}?`);
126
+ }
127
+ // belongsToMany: join-table generation is deliberately out of scope;
128
+ // consumers declare the pivot model themselves.
129
+ }
130
+ generateField(modelName, col, provider) {
131
+ let prismaType;
132
+ let modifiers = '';
133
+ if (col.type === 'enum') {
134
+ prismaType = `${modelName}${pascalCase(col.name)}`;
135
+ }
136
+ else if (col.type === 'decimal') {
137
+ prismaType = provider === 'sqlite' ? 'Float' : 'Decimal';
138
+ }
139
+ else {
140
+ prismaType = BASE_TYPE_MAP[col.type] ?? 'String';
141
+ }
142
+ if (col.nullable)
143
+ prismaType += '?';
144
+ // @default
145
+ if (col.default !== null && col.default !== undefined) {
146
+ if (col.type === 'boolean') {
147
+ modifiers += ` @default(${col.default})`;
148
+ }
149
+ else if (col.type === 'enum') {
150
+ modifiers += ` @default(${String(col.default).toUpperCase()})`;
151
+ }
152
+ else if (typeof col.default === 'string') {
153
+ modifiers += ` @default("${col.default}")`;
154
+ }
155
+ else {
156
+ modifiers += ` @default(${col.default})`;
157
+ }
158
+ }
159
+ // @unique
160
+ if (col.unique)
161
+ modifiers += ' @unique';
162
+ const paddedName = col.name.padEnd(12);
163
+ const paddedType = prismaType.padEnd(10);
164
+ return ` ${paddedName} ${paddedType}${modifiers}`;
165
+ }
166
+ }
167
+ exports.PrismaSchemaGenerator = PrismaSchemaGenerator;
168
+ // ---------------------------------------------------------------------------
169
+ // Schema introspection helpers (tiny — no full AST needed)
170
+ // ---------------------------------------------------------------------------
171
+ /**
172
+ * Return true when the given schema text declares `model <name> { ... }`.
173
+ * Matches the canonical Prisma syntax; doesn't try to parse comments or
174
+ * unusual whitespace — just a pragmatic check for "is this name taken".
175
+ */
176
+ function modelExistsInSchema(schema, modelName) {
177
+ const re = new RegExp(`^\\s*model\\s+${escapeRegex(modelName)}\\s*\\{`, 'm');
178
+ return re.test(schema);
179
+ }
180
+ /** Same, for top-level `enum <Name> { ... }` declarations. */
181
+ function enumExistsInSchema(schema, enumName) {
182
+ const re = new RegExp(`^\\s*enum\\s+${escapeRegex(enumName)}\\s*\\{`, 'm');
183
+ return re.test(schema);
184
+ }
185
+ function pascalCase(str) {
186
+ return str
187
+ .split(/[_\s-]+/)
188
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
189
+ .join('');
190
+ }
191
+ function stripIdSuffix(name) {
192
+ return name.endsWith('Id') ? name.slice(0, -2) : name;
193
+ }
194
+ function escapeRegex(s) {
195
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
196
+ }
197
+ //# sourceMappingURL=prisma-schema-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-schema-generator.js","sourceRoot":"","sources":["../../../src/blueprint/generators/prisma-schema-generator.ts"],"names":[],"mappings":";;;AAuNA,kDAGC;AAGD,gDAGC;AA9ND,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,MAAM,aAAa,GAA2B;IAC5C,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,KAAK;IACd,UAAU,EAAE,QAAQ;IACpB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,UAAU;IAChB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,UAAU;IACrB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,QAAQ;IACd,SAAS,EAAE,KAAK;IAChB,6CAA6C;IAC7C,2BAA2B;CAC5B,CAAC;AAoBF,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,MAAa,qBAAqB;IAChC,QAAQ,CAAC,SAAoB,EAAE,UAAuC,EAAE;QACtE,MAAM,QAAQ,GAAmB,OAAO,CAAC,QAAQ,IAAI,YAAY,CAAC;QAElE,wEAAwE;QACxE,wEAAwE;QACxE,IAAI,OAAO,CAAC,cAAc,IAAI,mBAAmB,CAAC,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3F,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;QAE9C,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBAC9C,MAAM,QAAQ,GAAG,GAAG,SAAS,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7D,2CAA2C;gBAC3C,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;oBAC5C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;QACzD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAED,4EAA4E;IAC5E,kBAAkB;IAClB,4EAA4E;IAEpE,YAAY,CAAC,QAAgB,EAAE,GAAoB;QACzD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChF,OAAO,QAAQ,QAAQ,OAAO,MAAM,KAAK,CAAC;IAC5C,CAAC;IAEO,kBAAkB,CAAC,SAAoB,EAAE,QAAwB;QACvE,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,wEAAwE;QACxE,IAAI,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC1D,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;QACnE,CAAC;QAED,wEAAwE;QACxE,IAAI,SAAS,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,qFAAqF,CAAC,CAAC;QACpG,CAAC;QAED,uEAAuE;QACvE,qEAAqE;QACrE,0EAA0E;QAC1E,yDAAyD;QACzD,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;QAChD,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC/D,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;gBACjD,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACpC,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,sBAAsB;gBAC/D,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;gBAC1E,KAAK,CAAC,IAAI,CACR,KAAK,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,uBAAuB,GAAG,CAAC,IAAI,sBAAsB,CACzF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,wEAAwE;QACxE,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,aAAa,EAAE,CAAC;YAC1C,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC;QAED,wEAAwE;QACxE,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAE9C,IAAI,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACtC,CAAC;QAED,wEAAwE;QACxE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,YAAY,SAAS,CAAC,KAAK,IAAI,CAAC,CAAC;QAE5C,OAAO,SAAS,SAAS,CAAC,KAAK,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAC9D,CAAC;IAEO,oBAAoB,CAC1B,GAA0B,EAC1B,cAA2B,EAC3B,KAAe;QAEf,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC7B,sEAAsE;YACtE,6CAA6C;YAC7C,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC;YAChC,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,OAAO;YAExC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;YAC1C,KAAK,CAAC,IAAI,CACR,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,uBAAuB,OAAO,sBAAsB,CAC1F,CAAC;QACJ,CAAC;aAAM,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC;QACxD,CAAC;aAAM,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;QACvD,CAAC;QACD,qEAAqE;QACrE,gDAAgD;IAClD,CAAC;IAEO,aAAa,CAAC,SAAiB,EAAE,GAAoB,EAAE,QAAwB;QACrF,IAAI,UAAkB,CAAC;QACvB,IAAI,SAAS,GAAG,EAAE,CAAC;QAEnB,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACxB,UAAU,GAAG,GAAG,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,CAAC;aAAM,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAClC,UAAU,GAAG,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;QACnD,CAAC;QAED,IAAI,GAAG,CAAC,QAAQ;YAAE,UAAU,IAAI,GAAG,CAAC;QAEpC,WAAW;QACX,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACtD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC3B,SAAS,IAAI,aAAa,GAAG,CAAC,OAAO,GAAG,CAAC;YAC3C,CAAC;iBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC/B,SAAS,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC;YACjE,CAAC;iBAAM,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC3C,SAAS,IAAI,cAAc,GAAG,CAAC,OAAO,IAAI,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,SAAS,IAAI,aAAa,GAAG,CAAC,OAAO,GAAG,CAAC;YAC3C,CAAC;QACH,CAAC;QAED,UAAU;QACV,IAAI,GAAG,CAAC,MAAM;YAAE,SAAS,IAAI,UAAU,CAAC;QAExC,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEzC,OAAO,KAAK,UAAU,IAAI,UAAU,GAAG,SAAS,EAAE,CAAC;IACrD,CAAC;CACF;AApJD,sDAoJC;AAED,8EAA8E;AAC9E,2DAA2D;AAC3D,8EAA8E;AAE9E;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,MAAc,EAAE,SAAiB;IACnE,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,iBAAiB,WAAW,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC7E,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC;AAED,8DAA8D;AAC9D,SAAgB,kBAAkB,CAAC,MAAc,EAAE,QAAgB;IACjE,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,gBAAgB,WAAW,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC3E,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG;SACP,KAAK,CAAC,SAAS,CAAC;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAClD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,SAAS,WAAW,CAAC,CAAS;IAC5B,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC"}