@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,143 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.InvitationService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const crypto_1 = require("crypto");
15
+ const prisma_service_1 = require("../prisma/prisma.service");
16
+ const rhino_config_1 = require("../rhino.config");
17
+ /**
18
+ * Invitation lifecycle: create/resend/cancel/accept with token-based acceptance.
19
+ * Mirrors Laravel's InvitationController + OrganizationInvitation model.
20
+ */
21
+ let InvitationService = class InvitationService {
22
+ prisma;
23
+ config;
24
+ constructor(prisma, config) {
25
+ this.prisma = prisma;
26
+ this.config = config;
27
+ }
28
+ delegate() {
29
+ return this.prisma.model('organizationInvitation');
30
+ }
31
+ generateToken() {
32
+ return (0, crypto_1.randomBytes)(32).toString('hex'); // 64 hex chars
33
+ }
34
+ expiresAt() {
35
+ const days = this.config.invitationsConfig().expiresDays;
36
+ const d = new Date();
37
+ d.setDate(d.getDate() + days);
38
+ return d;
39
+ }
40
+ async list(organizationId, status) {
41
+ const where = { organizationId };
42
+ if (status && status !== 'all')
43
+ where.status = status;
44
+ return this.delegate().findMany({ where, orderBy: { createdAt: 'desc' } });
45
+ }
46
+ async create(input) {
47
+ const cfg = this.config.invitationsConfig();
48
+ if (cfg.allowedRoles) {
49
+ const role = await this.prisma.model('role').findUnique({ where: { id: input.roleId } });
50
+ if (!role || !cfg.allowedRoles.includes(role.slug)) {
51
+ throw new common_1.BadRequestException('Role not allowed for invitations');
52
+ }
53
+ }
54
+ const token = this.generateToken();
55
+ const invitation = await this.delegate().create({
56
+ data: {
57
+ organizationId: input.organization.id,
58
+ email: input.email,
59
+ roleId: input.roleId,
60
+ token,
61
+ status: 'pending',
62
+ invitedById: input.invitedBy.id,
63
+ expiresAt: this.expiresAt(),
64
+ },
65
+ });
66
+ if (cfg.notificationHandler) {
67
+ await cfg.notificationHandler(invitation);
68
+ }
69
+ return invitation;
70
+ }
71
+ async resend(id) {
72
+ const invitation = await this.delegate().findUnique({ where: { id } });
73
+ if (!invitation)
74
+ throw new common_1.NotFoundException('Invitation not found');
75
+ if (invitation.status !== 'pending') {
76
+ throw new common_1.BadRequestException('Only pending invitations can be resent');
77
+ }
78
+ const refreshed = await this.delegate().update({
79
+ where: { id },
80
+ data: { token: this.generateToken(), expiresAt: this.expiresAt() },
81
+ });
82
+ const cfg = this.config.invitationsConfig();
83
+ if (cfg.notificationHandler)
84
+ await cfg.notificationHandler(refreshed);
85
+ return refreshed;
86
+ }
87
+ async cancel(id) {
88
+ const invitation = await this.delegate().findUnique({ where: { id } });
89
+ if (!invitation)
90
+ throw new common_1.NotFoundException('Invitation not found');
91
+ if (invitation.status !== 'pending') {
92
+ throw new common_1.BadRequestException('Only pending invitations can be cancelled');
93
+ }
94
+ return this.delegate().update({
95
+ where: { id },
96
+ data: { status: 'cancelled' },
97
+ });
98
+ }
99
+ async accept(token, userId) {
100
+ const invitation = await this.delegate().findUnique({
101
+ where: { token },
102
+ include: { organization: true, role: true },
103
+ });
104
+ if (!invitation)
105
+ throw new common_1.NotFoundException('Invitation not found');
106
+ const inv = invitation;
107
+ if (inv.status !== 'pending')
108
+ throw new common_1.BadRequestException('Invitation no longer valid');
109
+ if (inv.expiresAt < new Date()) {
110
+ await this.delegate().update({ where: { id: inv.id }, data: { status: 'expired' } });
111
+ throw new common_1.BadRequestException('Invitation expired');
112
+ }
113
+ if (!userId) {
114
+ // User is unauthenticated — return org/role so client can register
115
+ return {
116
+ requiresRegistration: true,
117
+ organization: inv.organization,
118
+ role: inv.role,
119
+ email: inv.email,
120
+ };
121
+ }
122
+ await this.prisma.model('userRole').create({
123
+ data: {
124
+ userId,
125
+ organizationId: inv.organizationId,
126
+ roleId: inv.roleId,
127
+ permissions: [],
128
+ },
129
+ });
130
+ await this.delegate().update({
131
+ where: { id: inv.id },
132
+ data: { status: 'accepted', acceptedAt: new Date() },
133
+ });
134
+ return { accepted: true, organization: inv.organization };
135
+ }
136
+ };
137
+ exports.InvitationService = InvitationService;
138
+ exports.InvitationService = InvitationService = __decorate([
139
+ (0, common_1.Injectable)(),
140
+ __metadata("design:paramtypes", [prisma_service_1.PrismaService,
141
+ rhino_config_1.RhinoConfigService])
142
+ ], InvitationService);
143
+ //# sourceMappingURL=invitation.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invitation.service.js","sourceRoot":"","sources":["../../src/services/invitation.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { PrismaService } from '../prisma/prisma.service';
2
+ import { RhinoConfigService } from '../rhino.config';
3
+ import { ValidationService } from './validation.service';
4
+ export interface NestedOperation {
5
+ model: string;
6
+ action: 'create' | 'update' | 'delete';
7
+ id?: number | string;
8
+ data?: Record<string, any>;
9
+ }
10
+ export interface NestedExecContext {
11
+ user?: any;
12
+ organization?: any;
13
+ }
14
+ export interface NestedResult {
15
+ index: number;
16
+ model: string;
17
+ action: 'create' | 'update' | 'delete';
18
+ id: any;
19
+ data: any;
20
+ }
21
+ /**
22
+ * Executes a batch of nested CRUD operations atomically.
23
+ * Supports `$N.field` references to prior operations' return values.
24
+ */
25
+ export declare class NestedService {
26
+ private readonly prisma;
27
+ private readonly config;
28
+ private readonly validation;
29
+ constructor(prisma: PrismaService, config: RhinoConfigService, validation: ValidationService);
30
+ execute(operations: NestedOperation[], ctx: NestedExecContext): Promise<NestedResult[]>;
31
+ private camelize;
32
+ resolveReferences(data: Record<string, any>, results: NestedResult[]): Record<string, any>;
33
+ private readPath;
34
+ }
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.NestedService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const prisma_service_1 = require("../prisma/prisma.service");
15
+ const rhino_config_1 = require("../rhino.config");
16
+ const validation_service_1 = require("./validation.service");
17
+ const REF_PATTERN = /^\$(\d+)\.([\w.]+)$/;
18
+ /**
19
+ * Executes a batch of nested CRUD operations atomically.
20
+ * Supports `$N.field` references to prior operations' return values.
21
+ */
22
+ let NestedService = class NestedService {
23
+ prisma;
24
+ config;
25
+ validation;
26
+ constructor(prisma, config, validation) {
27
+ this.prisma = prisma;
28
+ this.config = config;
29
+ this.validation = validation;
30
+ }
31
+ async execute(operations, ctx) {
32
+ const maxOps = this.config.nestedConfig().maxOperations;
33
+ const allowed = this.config.nestedConfig().allowedModels;
34
+ if (operations.length === 0) {
35
+ throw new common_1.BadRequestException('No operations provided');
36
+ }
37
+ if (operations.length > maxOps) {
38
+ throw new common_1.BadRequestException(`Too many operations (max ${maxOps})`);
39
+ }
40
+ for (const op of operations) {
41
+ if (!op.model || !op.action) {
42
+ throw new common_1.BadRequestException('Each operation must have model and action');
43
+ }
44
+ if (!['create', 'update', 'delete'].includes(op.action)) {
45
+ throw new common_1.BadRequestException(`Unsupported action: ${op.action}`);
46
+ }
47
+ if ((op.action === 'update' || op.action === 'delete') && op.id == null) {
48
+ throw new common_1.BadRequestException(`Action ${op.action} requires an id`);
49
+ }
50
+ if (!this.config.hasModel(op.model)) {
51
+ throw new common_1.BadRequestException(`Unknown model: ${op.model}`);
52
+ }
53
+ if (allowed && !allowed.includes(op.model)) {
54
+ throw new common_1.BadRequestException(`Model not allowed for nested: ${op.model}`);
55
+ }
56
+ }
57
+ return this.prisma.$transaction(async (tx) => {
58
+ const results = [];
59
+ for (let i = 0; i < operations.length; i++) {
60
+ const op = operations[i];
61
+ const reg = this.config.model(op.model);
62
+ const delegate = tx[this.camelize(reg.model)] ?? tx[reg.model];
63
+ if (!delegate) {
64
+ throw new common_1.BadRequestException(`Prisma delegate missing: ${reg.model}`);
65
+ }
66
+ if (op.action === 'delete') {
67
+ const where = { id: op.id };
68
+ if (reg.belongsToOrganization && ctx.organization) {
69
+ where.organizationId = ctx.organization.id;
70
+ }
71
+ if (reg.softDeletes) {
72
+ const res = await delegate.updateMany({ where, data: { deletedAt: new Date() } });
73
+ if (res.count === 0) {
74
+ throw new common_1.BadRequestException({
75
+ message: 'Record not found or cross-tenant',
76
+ operationIndex: i,
77
+ });
78
+ }
79
+ }
80
+ else {
81
+ const res = await delegate.deleteMany({ where });
82
+ if (res.count === 0) {
83
+ throw new common_1.BadRequestException({
84
+ message: 'Record not found or cross-tenant',
85
+ operationIndex: i,
86
+ });
87
+ }
88
+ }
89
+ results.push({ index: i, model: op.model, action: 'delete', id: op.id, data: null });
90
+ continue;
91
+ }
92
+ const resolvedData = this.resolveReferences(op.data ?? {}, results);
93
+ const validationResult = this.validation.validateForAction(resolvedData, reg, {
94
+ action: op.action === 'create' ? 'store' : 'update',
95
+ user: ctx.user,
96
+ organization: ctx.organization,
97
+ });
98
+ if (!validationResult.valid) {
99
+ throw new common_1.BadRequestException({
100
+ message: 'Validation failed',
101
+ operationIndex: i,
102
+ errors: validationResult.errors,
103
+ });
104
+ }
105
+ const payload = validationResult.data;
106
+ if (reg.belongsToOrganization && ctx.organization && op.action === 'create') {
107
+ payload.organizationId = ctx.organization.id;
108
+ }
109
+ if (op.action === 'create') {
110
+ const record = await delegate.create({ data: payload });
111
+ results.push({ index: i, model: op.model, action: 'create', id: record.id, data: record });
112
+ }
113
+ else {
114
+ const where = { id: op.id };
115
+ if (reg.belongsToOrganization && ctx.organization) {
116
+ where.organizationId = ctx.organization.id;
117
+ }
118
+ const res = await delegate.updateMany({ where, data: payload });
119
+ if (res.count === 0) {
120
+ throw new common_1.BadRequestException({
121
+ message: 'Record not found or cross-tenant',
122
+ operationIndex: i,
123
+ });
124
+ }
125
+ const record = await delegate.findFirst({ where });
126
+ results.push({ index: i, model: op.model, action: 'update', id: record.id, data: record });
127
+ }
128
+ }
129
+ return results;
130
+ });
131
+ }
132
+ camelize(name) {
133
+ return name.charAt(0).toLowerCase() + name.slice(1);
134
+ }
135
+ resolveReferences(data, results) {
136
+ const out = {};
137
+ for (const [k, v] of Object.entries(data)) {
138
+ if (typeof v === 'string') {
139
+ const match = v.match(REF_PATTERN);
140
+ if (match) {
141
+ const idx = parseInt(match[1], 10);
142
+ const path = match[2];
143
+ const prior = results[idx]?.data;
144
+ out[k] = prior ? this.readPath(prior, path) : undefined;
145
+ continue;
146
+ }
147
+ }
148
+ out[k] = v;
149
+ }
150
+ return out;
151
+ }
152
+ readPath(obj, path) {
153
+ return path.split('.').reduce((acc, p) => (acc == null ? acc : acc[p]), obj);
154
+ }
155
+ };
156
+ exports.NestedService = NestedService;
157
+ exports.NestedService = NestedService = __decorate([
158
+ (0, common_1.Injectable)(),
159
+ __metadata("design:paramtypes", [prisma_service_1.PrismaService,
160
+ rhino_config_1.RhinoConfigService,
161
+ validation_service_1.ValidationService])
162
+ ], NestedService);
163
+ //# sourceMappingURL=nested.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nested.service.js","sourceRoot":"","sources":["../../src/services/nested.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { PrismaService } from '../prisma/prisma.service';
2
+ import { RhinoConfigService } from '../rhino.config';
3
+ /**
4
+ * Resolves a route's `organization` parameter to a concrete organization record.
5
+ * Mirrors Laravel's `ResolveOrganizationFromRoute` middleware.
6
+ */
7
+ export declare class OrganizationService {
8
+ private readonly prisma;
9
+ private readonly config;
10
+ constructor(prisma: PrismaService, config: RhinoConfigService);
11
+ resolve(identifier: string | number, user?: any): Promise<any>;
12
+ ensureMembership(user: any, org: any): Promise<void>;
13
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.OrganizationService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const prisma_service_1 = require("../prisma/prisma.service");
15
+ const rhino_config_1 = require("../rhino.config");
16
+ /**
17
+ * Resolves a route's `organization` parameter to a concrete organization record.
18
+ * Mirrors Laravel's `ResolveOrganizationFromRoute` middleware.
19
+ */
20
+ let OrganizationService = class OrganizationService {
21
+ prisma;
22
+ config;
23
+ constructor(prisma, config) {
24
+ this.prisma = prisma;
25
+ this.config = config;
26
+ }
27
+ async resolve(identifier, user) {
28
+ const column = this.config.organizationIdentifierColumn();
29
+ const modelName = this.config.raw().multiTenant?.organizationModel ?? 'organization';
30
+ const value = column === 'id' || /^\d+$/.test(String(identifier))
31
+ ? column === 'id'
32
+ ? Number(identifier)
33
+ : identifier
34
+ : identifier;
35
+ const delegate = this.prisma.model(modelName);
36
+ const org = await delegate.findFirst({ where: { [column]: value } });
37
+ if (!org)
38
+ throw new common_1.NotFoundException('Organization not found');
39
+ if (user) {
40
+ await this.ensureMembership(user, org);
41
+ }
42
+ return org;
43
+ }
44
+ async ensureMembership(user, org) {
45
+ const userOrgModel = this.config.raw().multiTenant?.userOrganizationModel ?? 'userRole';
46
+ const delegate = this.prisma.model(userOrgModel);
47
+ const membership = await delegate.findFirst({
48
+ where: { userId: user.id, organizationId: org.id },
49
+ });
50
+ if (!membership)
51
+ throw new common_1.NotFoundException('Organization not found');
52
+ }
53
+ };
54
+ exports.OrganizationService = OrganizationService;
55
+ exports.OrganizationService = OrganizationService = __decorate([
56
+ (0, common_1.Injectable)(),
57
+ __metadata("design:paramtypes", [prisma_service_1.PrismaService,
58
+ rhino_config_1.RhinoConfigService])
59
+ ], OrganizationService);
60
+ //# sourceMappingURL=organization.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization.service.js","sourceRoot":"","sources":["../../src/services/organization.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA+D;AAC/D,6DAAyD;AACzD,kDAAqD;AAErD;;;GAGG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAEX;IACA;IAFnB,YACmB,MAAqB,EACrB,MAA0B;QAD1B,WAAM,GAAN,MAAM,CAAe;QACrB,WAAM,GAAN,MAAM,CAAoB;IAC1C,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,UAA2B,EAAE,IAAU;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,4BAA4B,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,iBAAiB,IAAI,cAAc,CAAC;QACrF,MAAM,KAAK,GACT,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACjD,CAAC,CAAC,MAAM,KAAK,IAAI;gBACf,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;gBACpB,CAAC,CAAC,UAAU;YACd,CAAC,CAAC,UAAU,CAAC;QAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,0BAAiB,CAAC,wBAAwB,CAAC,CAAC;QAEhE,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAS,EAAE,GAAQ;QACxC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,qBAAqB,IAAI,UAAU,CAAC;QACxF,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACjD,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC;YAC1C,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,EAAE;SACnD,CAAC,CAAC;QACH,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,0BAAiB,CAAC,wBAAwB,CAAC,CAAC;IACzE,CAAC;CACF,CAAA;AAnCY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAGgB,8BAAa;QACb,iCAAkB;GAHlC,mBAAmB,CAmC/B"}
@@ -0,0 +1,31 @@
1
+ import type { ModelRegistration } from '../interfaces/rhino-config.interface';
2
+ export interface ParsedQuery {
3
+ where: Record<string, any>;
4
+ orderBy: any;
5
+ include?: Record<string, any>;
6
+ select?: Record<string, any>;
7
+ page?: number;
8
+ perPage?: number;
9
+ }
10
+ /**
11
+ * Parses query string parameters into Prisma-compatible `findMany` args.
12
+ *
13
+ * Supported shape (match Laravel + Spatie QueryBuilder semantics):
14
+ * ?filter[field]=value — AND match, comma-separated values become IN
15
+ * ?sort=-created_at,title — leading `-` reverses direction
16
+ * ?search=term — fuzzy search across allowedSearch fields
17
+ * ?per_page=25&page=2 — pagination
18
+ * ?fields[slug]=id,title — field selection (Prisma `select`)
19
+ * ?include=user,comments.author — eager loading with dot-notation
20
+ */
21
+ export declare class QueryBuilderService {
22
+ build(query: Record<string, any>, reg: ModelRegistration): ParsedQuery;
23
+ buildWhere(query: Record<string, any>, reg: ModelRegistration): Record<string, any>;
24
+ private parseFilterValue;
25
+ private buildRelationContains;
26
+ buildOrderBy(query: Record<string, any>, reg: ModelRegistration): any;
27
+ buildInclude(query: Record<string, any>, reg: ModelRegistration): Record<string, any> | undefined;
28
+ private assignInclude;
29
+ buildSelect(query: Record<string, any>, reg: ModelRegistration): Record<string, any> | undefined;
30
+ private parseInt;
31
+ }
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.QueryBuilderService = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ /**
12
+ * Parses query string parameters into Prisma-compatible `findMany` args.
13
+ *
14
+ * Supported shape (match Laravel + Spatie QueryBuilder semantics):
15
+ * ?filter[field]=value — AND match, comma-separated values become IN
16
+ * ?sort=-created_at,title — leading `-` reverses direction
17
+ * ?search=term — fuzzy search across allowedSearch fields
18
+ * ?per_page=25&page=2 — pagination
19
+ * ?fields[slug]=id,title — field selection (Prisma `select`)
20
+ * ?include=user,comments.author — eager loading with dot-notation
21
+ */
22
+ let QueryBuilderService = class QueryBuilderService {
23
+ build(query, reg) {
24
+ return {
25
+ where: this.buildWhere(query, reg),
26
+ orderBy: this.buildOrderBy(query, reg),
27
+ include: this.buildInclude(query, reg),
28
+ select: this.buildSelect(query, reg),
29
+ page: this.parseInt(query.page),
30
+ perPage: this.parseInt(query.per_page ?? query.perPage),
31
+ };
32
+ }
33
+ buildWhere(query, reg) {
34
+ const where = {};
35
+ const filter = query.filter ?? {};
36
+ const allowed = new Set(reg.allowedFilters ?? []);
37
+ if (filter && typeof filter === 'object') {
38
+ for (const [key, rawVal] of Object.entries(filter)) {
39
+ if (!allowed.has(key))
40
+ continue;
41
+ where[key] = this.parseFilterValue(rawVal);
42
+ }
43
+ }
44
+ const search = query.search;
45
+ if (search && reg.allowedSearch && reg.allowedSearch.length > 0) {
46
+ const fragments = reg.allowedSearch.map((field) => {
47
+ if (field.includes('.')) {
48
+ return this.buildRelationContains(field, String(search));
49
+ }
50
+ return { [field]: { contains: String(search), mode: 'insensitive' } };
51
+ });
52
+ where.OR = fragments;
53
+ }
54
+ return where;
55
+ }
56
+ parseFilterValue(v) {
57
+ if (Array.isArray(v))
58
+ return { in: v };
59
+ if (typeof v === 'string' && v.includes(',')) {
60
+ return { in: v.split(',').filter(Boolean) };
61
+ }
62
+ return v;
63
+ }
64
+ buildRelationContains(path, value) {
65
+ const parts = path.split('.');
66
+ const leaf = parts.pop();
67
+ let inner = { [leaf]: { contains: value, mode: 'insensitive' } };
68
+ while (parts.length) {
69
+ const seg = parts.pop();
70
+ inner = { [seg]: { is: inner } };
71
+ }
72
+ return inner;
73
+ }
74
+ buildOrderBy(query, reg) {
75
+ const raw = query.sort ?? reg.defaultSort;
76
+ if (!raw)
77
+ return undefined;
78
+ const allowed = new Set(reg.allowedSorts ?? []);
79
+ const tokens = String(raw).split(',').map((s) => s.trim()).filter(Boolean);
80
+ const orderings = [];
81
+ for (const tok of tokens) {
82
+ const desc = tok.startsWith('-');
83
+ const field = desc ? tok.slice(1) : tok;
84
+ if (allowed.size > 0 && !allowed.has(field)) {
85
+ throw new common_1.BadRequestException(`Sort not allowed: ${field}`);
86
+ }
87
+ orderings.push({ [field]: desc ? 'desc' : 'asc' });
88
+ }
89
+ return orderings;
90
+ }
91
+ buildInclude(query, reg) {
92
+ const raw = query.include;
93
+ if (!raw)
94
+ return undefined;
95
+ const allowed = new Set(reg.allowedIncludes ?? []);
96
+ const paths = String(raw).split(',').map((s) => s.trim()).filter(Boolean);
97
+ const include = {};
98
+ for (const path of paths) {
99
+ if (allowed.size > 0 && !allowed.has(path) && !allowed.has(path.split('.')[0])) {
100
+ throw new common_1.BadRequestException(`Include not allowed: ${path}`);
101
+ }
102
+ this.assignInclude(include, path.split('.'));
103
+ }
104
+ return include;
105
+ }
106
+ assignInclude(target, parts) {
107
+ const [head, ...rest] = parts;
108
+ if (!head)
109
+ return;
110
+ if (rest.length === 0) {
111
+ if (!target[head])
112
+ target[head] = true;
113
+ return;
114
+ }
115
+ if (target[head] === true || !target[head])
116
+ target[head] = { include: {} };
117
+ if (!target[head].include)
118
+ target[head].include = {};
119
+ this.assignInclude(target[head].include, rest);
120
+ }
121
+ buildSelect(query, reg) {
122
+ const fields = query.fields;
123
+ if (!fields || typeof fields !== 'object')
124
+ return undefined;
125
+ // Support either ?fields[slug]=... or ?fields[_]=...; pick first non-empty
126
+ const raw = Object.values(fields)[0];
127
+ if (!raw)
128
+ return undefined;
129
+ const allowed = new Set(reg.allowedFields ?? []);
130
+ const names = String(raw).split(',').map((s) => s.trim()).filter(Boolean);
131
+ const select = { id: true };
132
+ for (const name of names) {
133
+ if (allowed.size > 0 && !allowed.has(name)) {
134
+ throw new common_1.BadRequestException(`Field not allowed: ${name}`);
135
+ }
136
+ select[name] = true;
137
+ }
138
+ return select;
139
+ }
140
+ parseInt(v) {
141
+ if (v == null)
142
+ return undefined;
143
+ const n = parseInt(String(v), 10);
144
+ return Number.isFinite(n) && n > 0 ? n : undefined;
145
+ }
146
+ };
147
+ exports.QueryBuilderService = QueryBuilderService;
148
+ exports.QueryBuilderService = QueryBuilderService = __decorate([
149
+ (0, common_1.Injectable)()
150
+ ], QueryBuilderService);
151
+ //# sourceMappingURL=query-builder.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.service.js","sourceRoot":"","sources":["../../src/services/query-builder.service.ts"],"names":[],"mappings":"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"}