@nextsparkjs/theme-default 0.1.0-beta.20 → 0.1.0-beta.21

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 (220) hide show
  1. package/package.json +1 -1
  2. package/tests/cypress/e2e/_devtools/access.bdd.md +262 -0
  3. package/tests/cypress/e2e/_devtools/access.cy.ts +171 -0
  4. package/tests/cypress/e2e/_devtools/navigation.bdd.md +261 -0
  5. package/tests/cypress/e2e/_devtools/navigation.cy.ts +157 -0
  6. package/tests/cypress/e2e/_devtools/pages.bdd.md +303 -0
  7. package/tests/cypress/e2e/_devtools/pages.cy.ts +184 -0
  8. package/tests/cypress/e2e/_docs/README.md +215 -0
  9. package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin-teams.narration.json +155 -0
  10. package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin.cy.ts +390 -0
  11. package/tests/cypress/e2e/_docs/tutorials/teams-system.doc.cy.ts +349 -0
  12. package/tests/cypress/e2e/_docs/tutorials/teams-system.narration.json +165 -0
  13. package/tests/cypress/e2e/_selectors/auth.cy.ts +306 -0
  14. package/tests/cypress/e2e/_selectors/billing.cy.ts +89 -0
  15. package/tests/cypress/e2e/_selectors/dashboard-mobile.cy.ts +113 -0
  16. package/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +89 -0
  17. package/tests/cypress/e2e/_selectors/dashboard-sidebar.cy.ts +60 -0
  18. package/tests/cypress/e2e/_selectors/dashboard-topnav.cy.ts +146 -0
  19. package/tests/cypress/e2e/_selectors/devtools.cy.ts +210 -0
  20. package/tests/cypress/e2e/_selectors/global-search.cy.ts +88 -0
  21. package/tests/cypress/e2e/_selectors/pages-editor.cy.ts +179 -0
  22. package/tests/cypress/e2e/_selectors/posts-editor.cy.ts +282 -0
  23. package/tests/cypress/e2e/_selectors/public.cy.ts +112 -0
  24. package/tests/cypress/e2e/_selectors/settings-api-keys.cy.ts +228 -0
  25. package/tests/cypress/e2e/_selectors/settings-billing.cy.ts +105 -0
  26. package/tests/cypress/e2e/_selectors/settings-layout.cy.ts +119 -0
  27. package/tests/cypress/e2e/_selectors/settings-password.cy.ts +71 -0
  28. package/tests/cypress/e2e/_selectors/settings-profile.cy.ts +82 -0
  29. package/tests/cypress/e2e/_selectors/settings-teams.cy.ts +68 -0
  30. package/tests/cypress/e2e/_selectors/superadmin.cy.ts +185 -0
  31. package/tests/cypress/e2e/_selectors/tasks.cy.ts +242 -0
  32. package/tests/cypress/e2e/_selectors/taxonomies.cy.ts +126 -0
  33. package/tests/cypress/e2e/_selectors/teams.cy.ts +142 -0
  34. package/tests/cypress/e2e/_superadmin/all-teams.bdd.md +261 -0
  35. package/tests/cypress/e2e/_superadmin/all-teams.cy.ts +177 -0
  36. package/tests/cypress/e2e/_superadmin/all-users.bdd.md +406 -0
  37. package/tests/cypress/e2e/_superadmin/all-users.cy.ts +294 -0
  38. package/tests/cypress/e2e/_superadmin/dashboard.bdd.md +235 -0
  39. package/tests/cypress/e2e/_superadmin/dashboard.cy.ts +149 -0
  40. package/tests/cypress/e2e/_superadmin/subscriptions-overview.bdd.md +290 -0
  41. package/tests/cypress/e2e/_superadmin/subscriptions-overview.cy.ts +194 -0
  42. package/tests/cypress/e2e/ai/ai-usage.cy.ts +209 -0
  43. package/tests/cypress/e2e/ai/chat-api.cy.ts +107 -0
  44. package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
  45. package/tests/cypress/e2e/api/billing/BillingAPIController.js +319 -0
  46. package/tests/cypress/e2e/api/billing/check-action.cy.ts +326 -0
  47. package/tests/cypress/e2e/api/billing/checkout.cy.ts +358 -0
  48. package/tests/cypress/e2e/api/billing/lifecycle.cy.ts +423 -0
  49. package/tests/cypress/e2e/api/billing/plans/README.md +345 -0
  50. package/tests/cypress/e2e/api/billing/plans/business.cy.ts +412 -0
  51. package/tests/cypress/e2e/api/billing/plans/downgrade.cy.ts +510 -0
  52. package/tests/cypress/e2e/api/billing/plans/fixtures/billing-plans.json +163 -0
  53. package/tests/cypress/e2e/api/billing/plans/free.cy.ts +500 -0
  54. package/tests/cypress/e2e/api/billing/plans/pro.cy.ts +497 -0
  55. package/tests/cypress/e2e/api/billing/plans/starter.cy.ts +342 -0
  56. package/tests/cypress/e2e/api/billing/portal.cy.ts +313 -0
  57. package/tests/cypress/e2e/api/devtools/registries.bdd.md +300 -0
  58. package/tests/cypress/e2e/api/devtools/registries.cy.ts +368 -0
  59. package/tests/cypress/e2e/api/entities/blocks-scope.cy.ts +396 -0
  60. package/tests/cypress/e2e/api/entities/customers-crud.cy.ts +648 -0
  61. package/tests/cypress/e2e/api/entities/customers-metas.cy.ts +839 -0
  62. package/tests/cypress/e2e/api/entities/pages-crud.cy.ts +425 -0
  63. package/tests/cypress/e2e/api/entities/pages-status.cy.ts +335 -0
  64. package/tests/cypress/e2e/api/entities/post-categories-crud.cy.ts +610 -0
  65. package/tests/cypress/e2e/api/entities/posts-crud.cy.ts +709 -0
  66. package/tests/cypress/e2e/api/entities/posts-status.cy.ts +396 -0
  67. package/tests/cypress/e2e/api/entities/tasks-crud.cy.ts +602 -0
  68. package/tests/cypress/e2e/api/entities/tasks-metas.cy.ts +878 -0
  69. package/tests/cypress/e2e/api/entities/users-crud.cy.ts +469 -0
  70. package/tests/cypress/e2e/api/entities/users-metas.cy.ts +913 -0
  71. package/tests/cypress/e2e/api/entities/users-security.cy.ts +375 -0
  72. package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.bdd.md +375 -0
  73. package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.cy.ts +346 -0
  74. package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.bdd.md +451 -0
  75. package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.cy.ts +447 -0
  76. package/tests/cypress/e2e/api/scheduled-actions/scheduling.bdd.md +649 -0
  77. package/tests/cypress/e2e/api/scheduled-actions/scheduling.cy.ts +333 -0
  78. package/tests/cypress/e2e/api/settings/api-keys.crud.cy.ts +923 -0
  79. package/tests/cypress/e2e/uat/auth/app-roles/developer-login.bdd.md +231 -0
  80. package/tests/cypress/e2e/uat/auth/app-roles/developer-login.cy.ts +144 -0
  81. package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.bdd.md +118 -0
  82. package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.cy.ts +84 -0
  83. package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.bdd.md +288 -0
  84. package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.cy.ts +188 -0
  85. package/tests/cypress/e2e/uat/auth/login-logout.bdd.md +160 -0
  86. package/tests/cypress/e2e/uat/auth/login-logout.cy.ts +116 -0
  87. package/tests/cypress/e2e/uat/auth/password-reset.bdd.md +289 -0
  88. package/tests/cypress/e2e/uat/auth/password-reset.cy.ts +200 -0
  89. package/tests/cypress/e2e/uat/auth/team-roles/admin-login.bdd.md +225 -0
  90. package/tests/cypress/e2e/uat/auth/team-roles/admin-login.cy.ts +148 -0
  91. package/tests/cypress/e2e/uat/auth/team-roles/member-login.bdd.md +251 -0
  92. package/tests/cypress/e2e/uat/auth/team-roles/member-login.cy.ts +163 -0
  93. package/tests/cypress/e2e/uat/auth/team-roles/owner-login.bdd.md +231 -0
  94. package/tests/cypress/e2e/uat/auth/team-roles/owner-login.cy.ts +141 -0
  95. package/tests/cypress/e2e/uat/billing/extended.bdd.md +273 -0
  96. package/tests/cypress/e2e/uat/billing/extended.cy.ts +209 -0
  97. package/tests/cypress/e2e/uat/billing/feature-gates.bdd.md +407 -0
  98. package/tests/cypress/e2e/uat/billing/feature-gates.cy.ts +307 -0
  99. package/tests/cypress/e2e/uat/billing/page.bdd.md +329 -0
  100. package/tests/cypress/e2e/uat/billing/page.cy.ts +250 -0
  101. package/tests/cypress/e2e/uat/billing/status.bdd.md +190 -0
  102. package/tests/cypress/e2e/uat/billing/status.cy.ts +145 -0
  103. package/tests/cypress/e2e/uat/billing/team-switch.bdd.md +156 -0
  104. package/tests/cypress/e2e/uat/billing/team-switch.cy.ts +122 -0
  105. package/tests/cypress/e2e/uat/billing/usage.bdd.md +218 -0
  106. package/tests/cypress/e2e/uat/billing/usage.cy.ts +176 -0
  107. package/tests/cypress/e2e/uat/blocks/hero.bdd.md +124 -0
  108. package/tests/cypress/e2e/uat/blocks/hero.cy.ts +56 -0
  109. package/tests/cypress/e2e/uat/devtools/api-tester.cy.ts +390 -0
  110. package/tests/cypress/e2e/uat/entities/customers/member.bdd.md +275 -0
  111. package/tests/cypress/e2e/uat/entities/customers/member.cy.ts +122 -0
  112. package/tests/cypress/e2e/uat/entities/customers/owner.bdd.md +243 -0
  113. package/tests/cypress/e2e/uat/entities/customers/owner.cy.ts +165 -0
  114. package/tests/cypress/e2e/uat/entities/pages/block-crud.bdd.md +476 -0
  115. package/tests/cypress/e2e/uat/entities/pages/block-crud.cy.ts +486 -0
  116. package/tests/cypress/e2e/uat/entities/pages/block-editor.bdd.md +460 -0
  117. package/tests/cypress/e2e/uat/entities/pages/block-editor.cy.ts +301 -0
  118. package/tests/cypress/e2e/uat/entities/pages/list.bdd.md +432 -0
  119. package/tests/cypress/e2e/uat/entities/pages/list.cy.ts +273 -0
  120. package/tests/cypress/e2e/uat/entities/pages/public-rendering.bdd.md +696 -0
  121. package/tests/cypress/e2e/uat/entities/pages/public-rendering.cy.ts +340 -0
  122. package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.bdd.md +161 -0
  123. package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.cy.ts +104 -0
  124. package/tests/cypress/e2e/uat/entities/posts/categories.bdd.md +375 -0
  125. package/tests/cypress/e2e/uat/entities/posts/categories.cy.ts +241 -0
  126. package/tests/cypress/e2e/uat/entities/posts/editor.bdd.md +429 -0
  127. package/tests/cypress/e2e/uat/entities/posts/editor.cy.ts +257 -0
  128. package/tests/cypress/e2e/uat/entities/posts/list.bdd.md +340 -0
  129. package/tests/cypress/e2e/uat/entities/posts/list.cy.ts +177 -0
  130. package/tests/cypress/e2e/uat/entities/posts/public.bdd.md +614 -0
  131. package/tests/cypress/e2e/uat/entities/posts/public.cy.ts +249 -0
  132. package/tests/cypress/e2e/uat/entities/tasks/member.bdd.md +222 -0
  133. package/tests/cypress/e2e/uat/entities/tasks/member.cy.ts +165 -0
  134. package/tests/cypress/e2e/uat/entities/tasks/owner.bdd.md +419 -0
  135. package/tests/cypress/e2e/uat/entities/tasks/owner.cy.ts +191 -0
  136. package/tests/cypress/e2e/uat/roles/editor-role.bdd.md +552 -0
  137. package/tests/cypress/e2e/uat/roles/editor-role.cy.ts +210 -0
  138. package/tests/cypress/e2e/uat/roles/member-restrictions.bdd.md +450 -0
  139. package/tests/cypress/e2e/uat/roles/member-restrictions.cy.ts +189 -0
  140. package/tests/cypress/e2e/uat/roles/owner-full-crud.bdd.md +530 -0
  141. package/tests/cypress/e2e/uat/roles/owner-full-crud.cy.ts +247 -0
  142. package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.bdd.md +736 -0
  143. package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.cy.ts +740 -0
  144. package/tests/cypress/e2e/uat/teams/roles-matrix.bdd.md +553 -0
  145. package/tests/cypress/e2e/uat/teams/roles-matrix.cy.ts +185 -0
  146. package/tests/cypress/e2e/uat/teams/switcher.bdd.md +1151 -0
  147. package/tests/cypress/e2e/uat/teams/switcher.cy.ts +497 -0
  148. package/tests/cypress/e2e/uat/teams/team-switcher.md +198 -0
  149. package/tests/cypress/fixtures/blocks.json +218 -0
  150. package/tests/cypress/fixtures/entities.json +78 -0
  151. package/tests/cypress/fixtures/page-builder.json +21 -0
  152. package/tests/cypress/src/components/CategoriesPOM.ts +382 -0
  153. package/tests/cypress/src/components/CustomersPOM.ts +439 -0
  154. package/tests/cypress/src/components/DevKeyringPOM.ts +160 -0
  155. package/tests/cypress/src/components/EntityForm.ts +375 -0
  156. package/tests/cypress/src/components/EntityList.ts +389 -0
  157. package/tests/cypress/src/components/PageBuilderPOM.ts +710 -0
  158. package/tests/cypress/src/components/PostEditorPOM.ts +370 -0
  159. package/tests/cypress/src/components/PostsListPOM.ts +223 -0
  160. package/tests/cypress/src/components/PublicPagePOM.ts +447 -0
  161. package/tests/cypress/src/components/PublicPostPOM.ts +146 -0
  162. package/tests/cypress/src/components/TasksPOM.ts +272 -0
  163. package/tests/cypress/src/components/TeamSwitcherPOM.ts +450 -0
  164. package/tests/cypress/src/components/index.ts +21 -0
  165. package/tests/cypress/src/controllers/ApiKeysAPIController.js +178 -0
  166. package/tests/cypress/src/controllers/BaseAPIController.js +317 -0
  167. package/tests/cypress/src/controllers/CustomerAPIController.js +251 -0
  168. package/tests/cypress/src/controllers/PagesAPIController.js +226 -0
  169. package/tests/cypress/src/controllers/PostsAPIController.js +250 -0
  170. package/tests/cypress/src/controllers/TaskAPIController.js +240 -0
  171. package/tests/cypress/src/controllers/UsersAPIController.js +242 -0
  172. package/tests/cypress/src/controllers/index.js +25 -0
  173. package/tests/cypress/src/core/AuthPOM.ts +450 -0
  174. package/tests/cypress/src/core/BasePOM.ts +86 -0
  175. package/tests/cypress/src/core/BlockEditorBasePOM.ts +576 -0
  176. package/tests/cypress/src/core/DashboardEntityPOM.ts +692 -0
  177. package/tests/cypress/src/core/index.ts +14 -0
  178. package/tests/cypress/src/entities/CustomersPOM.ts +172 -0
  179. package/tests/cypress/src/entities/PagesPOM.ts +137 -0
  180. package/tests/cypress/src/entities/PostsPOM.ts +137 -0
  181. package/tests/cypress/src/entities/TasksPOM.ts +176 -0
  182. package/tests/cypress/src/entities/index.ts +14 -0
  183. package/tests/cypress/src/features/BillingPOM.ts +385 -0
  184. package/tests/cypress/src/features/DashboardPOM.ts +245 -0
  185. package/tests/cypress/src/features/DevtoolsPOM.ts +739 -0
  186. package/tests/cypress/src/features/PageBuilderPOM.ts +263 -0
  187. package/tests/cypress/src/features/PostEditorPOM.ts +313 -0
  188. package/tests/cypress/src/features/ScheduledActionsPOM.ts +463 -0
  189. package/tests/cypress/src/features/SettingsPOM.ts +362 -0
  190. package/tests/cypress/src/features/SuperadminPOM.ts +331 -0
  191. package/tests/cypress/src/features/SuperadminTeamRolesPOM.ts +285 -0
  192. package/tests/cypress/src/features/index.ts +28 -0
  193. package/tests/cypress/src/helpers/ApiInterceptor.ts +177 -0
  194. package/tests/cypress/src/index.ts +101 -0
  195. package/tests/cypress/src/pages/dashboard/Dashboard.js +677 -0
  196. package/tests/cypress/src/pages/dashboard/DashboardPage.js +43 -0
  197. package/tests/cypress/src/pages/dashboard/DashboardStats.js +546 -0
  198. package/tests/cypress/src/pages/dashboard/index.js +6 -0
  199. package/tests/cypress/src/pages/index.js +5 -0
  200. package/tests/cypress/src/pages/public/FeaturesPage.js +28 -0
  201. package/tests/cypress/src/pages/public/LandingPage.js +69 -0
  202. package/tests/cypress/src/pages/public/PricingPage.js +33 -0
  203. package/tests/cypress/src/pages/public/index.js +6 -0
  204. package/tests/cypress/src/selectors.ts +46 -0
  205. package/tests/cypress/src/session-helpers.ts +500 -0
  206. package/tests/cypress/support/doc-commands.ts +260 -0
  207. package/tests/cypress.config.ts +150 -0
  208. package/tests/jest/components/post-header.test.tsx +377 -0
  209. package/tests/jest/config/role-config.test.ts +529 -0
  210. package/tests/jest/jest.config.ts +81 -0
  211. package/tests/jest/langchain/COVERAGE.md +372 -0
  212. package/tests/jest/langchain/guardrails.test.ts +465 -0
  213. package/tests/jest/langchain/streaming.test.ts +367 -0
  214. package/tests/jest/langchain/token-tracker.test.ts +455 -0
  215. package/tests/jest/langchain/tracer-callbacks.test.ts +881 -0
  216. package/tests/jest/langchain/tracer.test.ts +823 -0
  217. package/tests/jest/user-roles/role-helpers.test.ts +432 -0
  218. package/tests/jest/validation/categories.test.ts +429 -0
  219. package/tests/jest/validation/posts.test.ts +546 -0
  220. package/tests/tsconfig.json +15 -0
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Default Theme - Components Index
3
+ *
4
+ * Export all POM components for the Default theme.
5
+ */
6
+
7
+ // Generic POMs (entity-agnostic)
8
+ export { EntityList, type EntityConfig as EntityListConfig } from './EntityList'
9
+ export { EntityForm, type EntityConfig as EntityFormConfig } from './EntityForm'
10
+
11
+ // Entity-specific POMs (using new convention)
12
+ export { TasksPOM, type TaskFormData } from './TasksPOM'
13
+ export { CustomersPOM, type CustomerFormData } from './CustomersPOM'
14
+
15
+ // Page Builder POMs
16
+ export { PageBuilderPOM, type PageFormData, type BlockData } from './PageBuilderPOM'
17
+ export { PublicPagePOM, type PageData } from './PublicPagePOM'
18
+
19
+ // Feature Component POMs (multi-tenant, auth)
20
+ export { TeamSwitcherPOM } from './TeamSwitcherPOM'
21
+ export { DevKeyringPOM } from './DevKeyringPOM'
@@ -0,0 +1,178 @@
1
+ /**
2
+ * ApiKeysAPIController - Controller for API Keys API
3
+ *
4
+ * Extends BaseAPIController for CRUD operations on /api/v1/api-keys endpoint.
5
+ *
6
+ * IMPORTANT: API Keys is a GLOBAL entity - NO teamId required
7
+ * NOTE: api-keys is NOT in entities.json, so slug is hardcoded
8
+ *
9
+ * @endpoint /api/v1/api-keys
10
+ */
11
+
12
+ const BaseAPIController = require('./BaseAPIController')
13
+
14
+ // NOTA: api-keys NO está en entities.json - hardcodeamos el slug
15
+ const slug = 'api-keys'
16
+
17
+ class ApiKeysAPIController extends BaseAPIController {
18
+ /**
19
+ * @param {string} baseUrl - Base URL for API requests
20
+ * @param {string|null} apiKey - API key for authentication (superadmin key)
21
+ * NO acepta teamId - api-keys es entidad global
22
+ */
23
+ constructor(baseUrl = 'http://localhost:5173', apiKey = null) {
24
+ // NO pasar teamId (null) para entidades globales
25
+ super(baseUrl, apiKey, null, { slug })
26
+ }
27
+
28
+ // ============================================
29
+ // SEMANTIC ALIASES
30
+ // ============================================
31
+
32
+ /**
33
+ * GET /api/v1/api-keys - List all API keys
34
+ * @param {Object} options - Query options (page, limit, etc.)
35
+ */
36
+ getApiKeys(options = {}) {
37
+ return this.list(options)
38
+ }
39
+
40
+ /**
41
+ * GET /api/v1/api-keys/{id} - Get API key by ID
42
+ * @param {string} id - API key ID
43
+ * @param {Object} options - Additional options
44
+ */
45
+ getApiKeyById(id, options = {}) {
46
+ return this.getById(id, options)
47
+ }
48
+
49
+ /**
50
+ * POST /api/v1/api-keys - Create new API key
51
+ * @param {Object} apiKeyData - API key data (name, scopes, expiresAt)
52
+ * @param {Object} options - Additional options
53
+ */
54
+ createApiKey(apiKeyData, options = {}) {
55
+ return this.create(apiKeyData, options)
56
+ }
57
+
58
+ /**
59
+ * PATCH /api/v1/api-keys/{id} - Update API key
60
+ * @param {string} id - API key ID
61
+ * @param {Object} updateData - Fields to update
62
+ * @param {Object} options - Additional options
63
+ */
64
+ updateApiKey(id, updateData, options = {}) {
65
+ return this.update(id, updateData, options)
66
+ }
67
+
68
+ /**
69
+ * DELETE /api/v1/api-keys/{id} - Revoke API key
70
+ * @param {string} id - API key ID
71
+ * @param {Object} options - Additional options
72
+ */
73
+ deleteApiKey(id, options = {}) {
74
+ return this.delete(id, options)
75
+ }
76
+
77
+ // ============================================
78
+ // DATA GENERATORS
79
+ // ============================================
80
+
81
+ /**
82
+ * Generate random API key data (required by createTestEntity)
83
+ * @param {Object} overrides - Fields to override
84
+ */
85
+ generateRandomData(overrides = {}) {
86
+ return this.generateRandomApiKeyData(overrides)
87
+ }
88
+
89
+ /**
90
+ * Generate random API key data for testing
91
+ * @param {Object} overrides - Fields to override
92
+ */
93
+ generateRandomApiKeyData(overrides = {}) {
94
+ const timestamp = Date.now()
95
+ const randomId = Math.random().toString(36).substring(2, 8)
96
+
97
+ return {
98
+ name: `Cypress Test Key ${randomId} - ${timestamp}`,
99
+ scopes: ['users:read', 'tasks:read'],
100
+ expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
101
+ ...overrides
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Create a test API key
107
+ * @param {Object} apiKeyData - API key data overrides
108
+ */
109
+ createTestApiKey(apiKeyData = {}) {
110
+ return this.createTestEntity(apiKeyData)
111
+ }
112
+
113
+ /**
114
+ * Cleanup (delete) a test API key
115
+ * @param {string} id - API key ID
116
+ */
117
+ cleanupTestApiKey(id) {
118
+ return this.cleanup(id)
119
+ }
120
+
121
+ // ============================================
122
+ // ENTITY-SPECIFIC VALIDATORS
123
+ // ============================================
124
+
125
+ /**
126
+ * Validate API key object structure
127
+ * @param {Object} apiKey - API key object from response
128
+ */
129
+ validateApiKeyObject(apiKey) {
130
+ // Base fields
131
+ this.validateBaseEntityFields(apiKey)
132
+
133
+ // Required entity fields
134
+ expect(apiKey).to.have.property('name')
135
+ expect(apiKey.name).to.be.a('string')
136
+
137
+ expect(apiKey).to.have.property('keyPrefix')
138
+ expect(apiKey.keyPrefix).to.be.a('string')
139
+
140
+ expect(apiKey).to.have.property('scopes')
141
+ expect(apiKey.scopes).to.be.an('array')
142
+
143
+ expect(apiKey).to.have.property('status')
144
+ expect(apiKey.status).to.be.oneOf(['active', 'inactive', 'expired'])
145
+ }
146
+
147
+ /**
148
+ * Validate API key response on creation (includes full key)
149
+ * @param {Object} response - API response
150
+ */
151
+ validateCreatedApiKey(response) {
152
+ expect(response.status).to.eq(201)
153
+ expect(response.body).to.have.property('success', true)
154
+ expect(response.body.data).to.have.property('id')
155
+ expect(response.body.data).to.have.property('key') // Full key only on creation
156
+ expect(response.body.data).to.have.property('name')
157
+ expect(response.body.data).to.have.property('scopes')
158
+ expect(response.body.data).to.have.property('warning') // Security warning about key visibility
159
+ }
160
+
161
+ /**
162
+ * Validate revoked API key response
163
+ * @param {Object} response - API response
164
+ */
165
+ validateRevokedApiKey(response) {
166
+ expect(response.status).to.eq(200)
167
+ expect(response.body).to.have.property('success', true)
168
+ expect(response.body.data).to.have.property('revoked', true)
169
+ expect(response.body.data).to.have.property('id')
170
+ }
171
+ }
172
+
173
+ module.exports = ApiKeysAPIController
174
+
175
+ // For global use in Cypress
176
+ if (typeof window !== 'undefined') {
177
+ window.ApiKeysAPIController = ApiKeysAPIController
178
+ }
@@ -0,0 +1,317 @@
1
+ /**
2
+ * BaseAPIController - Base class for all API Controllers
3
+ *
4
+ * Provides:
5
+ * - Consistent header handling (x-team-id ALWAYS included)
6
+ * - Standard CRUD operations
7
+ * - Common validators
8
+ * - Extensibility via configuration
9
+ *
10
+ * All entity-specific controllers should extend this class.
11
+ */
12
+ class BaseAPIController {
13
+ /**
14
+ * @param {string} baseUrl - Base URL for API requests
15
+ * @param {string|null} apiKey - API key for authentication
16
+ * @param {string|null} teamId - Team ID for x-team-id header
17
+ * @param {Object} config - Entity-specific configuration
18
+ * @param {string} config.slug - Entity slug (e.g., 'tasks', 'customers')
19
+ * @param {string} [config.endpoint] - Custom endpoint (default: /api/v1/{slug})
20
+ * @param {string} [config.updateMethod='PATCH'] - HTTP method for updates
21
+ */
22
+ constructor(baseUrl = 'http://localhost:5173', apiKey = null, teamId = null, config = {}) {
23
+ this.baseUrl = baseUrl
24
+ this.apiKey = apiKey
25
+ this.teamId = teamId
26
+ this.entitySlug = config.slug || 'entity'
27
+ this.endpoint = config.endpoint || `/api/v1/${this.entitySlug}`
28
+ this.updateMethod = config.updateMethod || 'PATCH'
29
+ }
30
+
31
+ // ============================================================
32
+ // SETTERS (Fluent API)
33
+ // ============================================================
34
+
35
+ /**
36
+ * Set the API key for requests
37
+ * @param {string|null} apiKey - Valid API key or null
38
+ * @returns {this} For method chaining
39
+ */
40
+ setApiKey(apiKey) {
41
+ this.apiKey = apiKey
42
+ return this
43
+ }
44
+
45
+ /**
46
+ * Set the team ID for requests
47
+ * @param {string|null} teamId - Valid team ID or null
48
+ * @returns {this} For method chaining
49
+ */
50
+ setTeamId(teamId) {
51
+ this.teamId = teamId
52
+ return this
53
+ }
54
+
55
+ // ============================================================
56
+ // HEADERS - CRITICAL: x-team-id is ALWAYS included
57
+ // ============================================================
58
+
59
+ /**
60
+ * Build headers for requests
61
+ * GUARANTEES x-team-id is present if teamId is configured
62
+ *
63
+ * @param {Object} additionalHeaders - Additional headers to include
64
+ * @returns {Object} Complete headers object
65
+ */
66
+ getHeaders(additionalHeaders = {}) {
67
+ const headers = {
68
+ 'Content-Type': 'application/json',
69
+ ...additionalHeaders
70
+ }
71
+
72
+ if (this.apiKey) {
73
+ headers['Authorization'] = `Bearer ${this.apiKey}`
74
+ }
75
+
76
+ // CRITICAL: Always include x-team-id if configured
77
+ if (this.teamId) {
78
+ headers['x-team-id'] = this.teamId
79
+ }
80
+
81
+ return headers
82
+ }
83
+
84
+ // ============================================================
85
+ // URL BUILDER
86
+ // ============================================================
87
+
88
+ /**
89
+ * Build full URL with optional query parameters
90
+ * @param {string} path - Path to append to endpoint
91
+ * @param {Object} queryParams - Query parameters
92
+ * @returns {string} Full URL
93
+ */
94
+ buildUrl(path = '', queryParams = {}) {
95
+ const baseEndpoint = `${this.baseUrl}${this.endpoint}${path}`
96
+
97
+ // Filter out undefined/null/empty values
98
+ const filteredParams = Object.entries(queryParams)
99
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
100
+
101
+ if (filteredParams.length === 0) {
102
+ return baseEndpoint
103
+ }
104
+
105
+ const params = new URLSearchParams()
106
+ filteredParams.forEach(([key, value]) => {
107
+ params.append(key, String(value))
108
+ })
109
+
110
+ return `${baseEndpoint}?${params.toString()}`
111
+ }
112
+
113
+ // ============================================================
114
+ // CRUD OPERATIONS
115
+ // ============================================================
116
+
117
+ /**
118
+ * GET /api/v1/{entity} - List entities
119
+ * @param {Object} options - Query options
120
+ * @param {number} [options.page] - Page number
121
+ * @param {number} [options.limit] - Results per page
122
+ * @param {string} [options.search] - Search term
123
+ * @param {string} [options.metas] - Metadata parameter ('all', 'key1,key2', etc.)
124
+ * @param {string} [options.sortBy] - Sort field
125
+ * @param {string} [options.sortOrder] - Sort order ('asc' or 'desc')
126
+ * @param {Object} [options.headers] - Additional headers
127
+ * @returns {Cypress.Chainable} Cypress response
128
+ */
129
+ list(options = {}) {
130
+ const { headers = {}, ...queryParams } = options
131
+
132
+ return cy.request({
133
+ method: 'GET',
134
+ url: this.buildUrl('', queryParams),
135
+ headers: this.getHeaders(headers),
136
+ failOnStatusCode: false
137
+ })
138
+ }
139
+
140
+ /**
141
+ * GET /api/v1/{entity}/{id} - Get entity by ID
142
+ * @param {string} id - Entity ID
143
+ * @param {Object} options - Additional options
144
+ * @param {string} [options.metas] - Metadata parameter
145
+ * @param {Object} [options.headers] - Additional headers
146
+ * @returns {Cypress.Chainable} Cypress response
147
+ */
148
+ getById(id, options = {}) {
149
+ const { metas, headers = {} } = options
150
+ const queryParams = metas ? { metas } : {}
151
+
152
+ return cy.request({
153
+ method: 'GET',
154
+ url: this.buildUrl(`/${id}`, queryParams),
155
+ headers: this.getHeaders(headers),
156
+ failOnStatusCode: false
157
+ })
158
+ }
159
+
160
+ /**
161
+ * POST /api/v1/{entity} - Create entity
162
+ * @param {Object} data - Entity data
163
+ * @param {Object} options - Additional options
164
+ * @param {Object} [options.headers] - Additional headers
165
+ * @returns {Cypress.Chainable} Cypress response
166
+ */
167
+ create(data, options = {}) {
168
+ const { headers = {} } = options
169
+
170
+ return cy.request({
171
+ method: 'POST',
172
+ url: this.buildUrl(''),
173
+ headers: this.getHeaders(headers),
174
+ body: data,
175
+ failOnStatusCode: false
176
+ })
177
+ }
178
+
179
+ /**
180
+ * PATCH/PUT /api/v1/{entity}/{id} - Update entity
181
+ * Uses the updateMethod configured for this controller
182
+ * @param {string} id - Entity ID
183
+ * @param {Object} data - Update data
184
+ * @param {Object} options - Additional options
185
+ * @param {Object} [options.headers] - Additional headers
186
+ * @returns {Cypress.Chainable} Cypress response
187
+ */
188
+ update(id, data, options = {}) {
189
+ const { headers = {} } = options
190
+
191
+ return cy.request({
192
+ method: this.updateMethod,
193
+ url: this.buildUrl(`/${id}`),
194
+ headers: this.getHeaders(headers),
195
+ body: data,
196
+ failOnStatusCode: false
197
+ })
198
+ }
199
+
200
+ /**
201
+ * DELETE /api/v1/{entity}/{id} - Delete entity
202
+ * @param {string} id - Entity ID
203
+ * @param {Object} options - Additional options
204
+ * @param {Object} [options.headers] - Additional headers
205
+ * @returns {Cypress.Chainable} Cypress response
206
+ */
207
+ delete(id, options = {}) {
208
+ const { headers = {} } = options
209
+
210
+ return cy.request({
211
+ method: 'DELETE',
212
+ url: this.buildUrl(`/${id}`),
213
+ headers: this.getHeaders(headers),
214
+ failOnStatusCode: false
215
+ })
216
+ }
217
+
218
+ // ============================================================
219
+ // COMMON VALIDATORS
220
+ // ============================================================
221
+
222
+ /**
223
+ * Validate success response structure
224
+ * @param {Object} response - API response
225
+ * @param {number} expectedStatus - Expected status code (default: 200)
226
+ */
227
+ validateSuccessResponse(response, expectedStatus = 200) {
228
+ expect(response.status).to.eq(expectedStatus)
229
+ expect(response.body).to.have.property('success', true)
230
+ expect(response.body).to.have.property('data')
231
+ expect(response.body).to.have.property('info')
232
+ expect(response.body.info).to.have.property('timestamp')
233
+ }
234
+
235
+ /**
236
+ * Validate error response structure
237
+ * @param {Object} response - API response
238
+ * @param {number} expectedStatus - Expected status code
239
+ * @param {string|null} expectedCode - Expected error code (optional)
240
+ */
241
+ validateErrorResponse(response, expectedStatus, expectedCode = null) {
242
+ expect(response.status).to.eq(expectedStatus)
243
+ expect(response.body).to.have.property('success', false)
244
+ expect(response.body).to.have.property('error')
245
+
246
+ if (expectedCode) {
247
+ expect(response.body).to.have.property('code', expectedCode)
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Validate paginated response structure
253
+ * @param {Object} response - API response
254
+ */
255
+ validatePaginatedResponse(response) {
256
+ this.validateSuccessResponse(response)
257
+ expect(response.body.data).to.be.an('array')
258
+
259
+ const info = response.body.info
260
+ expect(info).to.have.property('page')
261
+ expect(info).to.have.property('limit')
262
+ expect(info).to.have.property('total')
263
+ expect(info).to.have.property('totalPages')
264
+ }
265
+
266
+ /**
267
+ * Validate base entity fields (id, createdAt, updatedAt)
268
+ * @param {Object} entity - Entity object
269
+ */
270
+ validateBaseEntityFields(entity) {
271
+ expect(entity).to.have.property('id')
272
+ expect(entity).to.have.property('createdAt')
273
+ expect(entity).to.have.property('updatedAt')
274
+ }
275
+
276
+ // ============================================================
277
+ // TEST HELPERS
278
+ // ============================================================
279
+
280
+ /**
281
+ * Create a test entity and return its data
282
+ * Subclasses should override generateRandomData() for this to work
283
+ * @param {Object} overrides - Data overrides
284
+ * @returns {Cypress.Chainable} Promise resolving with created entity data
285
+ */
286
+ createTestEntity(overrides = {}) {
287
+ if (typeof this.generateRandomData !== 'function') {
288
+ throw new Error(`generateRandomData() not implemented for ${this.entitySlug}`)
289
+ }
290
+
291
+ const testData = this.generateRandomData(overrides)
292
+
293
+ return this.create(testData).then((response) => {
294
+ if (response.status === 201) {
295
+ return { ...testData, ...response.body.data }
296
+ }
297
+ throw new Error(`Failed to create test ${this.entitySlug}: ${response.body?.error || 'Unknown error'}`)
298
+ })
299
+ }
300
+
301
+ /**
302
+ * Clean up a test entity (delete it)
303
+ * @param {string} id - Entity ID
304
+ * @returns {Cypress.Chainable} Delete response
305
+ */
306
+ cleanup(id) {
307
+ return this.delete(id)
308
+ }
309
+ }
310
+
311
+ // Export for CommonJS
312
+ module.exports = BaseAPIController
313
+
314
+ // For global use in Cypress
315
+ if (typeof window !== 'undefined') {
316
+ window.BaseAPIController = BaseAPIController
317
+ }