sitero-server 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/README.md +15 -0
  2. package/dist/export/index.js +4 -2
  3. package/dist/src/application/features/authentication/admin/operations/sign-in/admin-sign-in.js +1 -1
  4. package/dist/src/application/features/inquiry/operations/submit/inquiry-submit.js +13 -15
  5. package/dist/src/application/features/uploads/constraints/create-storage-file-schema.js +1 -1
  6. package/dist/src/application/features/uploads/operations/upload-files/upload-files.js +33 -15
  7. package/dist/src/application/resources/admin/errors/operation-errors.js +1 -0
  8. package/dist/src/application/resources/admin-refresh-token/operations/commands/delete/admin-refresh-token-delete-command.js +3 -0
  9. package/dist/src/application/resources/config/operations/commands/update/cache.js +0 -1
  10. package/dist/src/application/resources/config/operations/commands/update/validation/schema.js +1 -1
  11. package/dist/src/application/resources/config/operations/queries/find-detail/cache.js +0 -1
  12. package/dist/src/application/resources/config/operations/queries/find-detail/config-find-detail-query.js +1 -3
  13. package/dist/src/application/resources/config/operations/queries/find-many/cache.js +0 -1
  14. package/dist/src/application/resources/file/constraints/assert-file-exists.js +1 -1
  15. package/dist/src/application/resources/file/errors/codes.js +1 -0
  16. package/dist/src/application/resources/file/operations/commands/create/file-create-command.js +1 -1
  17. package/dist/src/application/resources/file/operations/commands/create/validation/schema.js +3 -9
  18. package/dist/src/application/resources/file/operations/commands/create-many/file-create-many-command.js +10 -1
  19. package/dist/src/application/resources/file/operations/commands/create-many/validation/schema.js +1 -1
  20. package/dist/src/application/resources/file/operations/commands/purge-many/cache.js +7 -3
  21. package/dist/src/application/resources/file/operations/commands/purge-many/file-purge-many-command.js +14 -34
  22. package/dist/src/application/resources/file/operations/commands/restore-many/file-restore-many-command.js +21 -4
  23. package/dist/src/application/resources/file/operations/commands/update/validation/schema.js +3 -9
  24. package/dist/src/application/resources/file/operations/queries/find-list-cards/cache.js +1 -1
  25. package/dist/src/application/resources/file/operations/queries/find-list-cards/validation/schema.js +1 -1
  26. package/dist/src/application/resources/file/operations/queries/find-relations/cache.js +7 -0
  27. package/dist/src/application/resources/file/operations/queries/find-relations/file-find-relations-query.js +36 -0
  28. package/dist/src/application/resources/file/operations/queries/validate-create/file-validate-create-query.js +17 -0
  29. package/dist/src/application/resources/file/operations/queries/validate-create/validation/schema.js +6 -0
  30. package/dist/src/application/resources/file/operations/queries/validate-create/validation/validate-input.js +7 -0
  31. package/dist/src/application/resources/file/operations/queries/validate-update/file-validate-update-query.js +17 -0
  32. package/dist/src/application/resources/file/validation/file-translations-schema.js +13 -0
  33. package/dist/src/application/resources/inquiry/operations/queries/find/inquiry-find-query.js +1 -3
  34. package/dist/src/application/resources/post/operations/commands/create/validation/schema.js +16 -3
  35. package/dist/src/application/resources/post/operations/commands/update/validation/validate-input.js +1 -2
  36. package/dist/src/application/resources/post/operations/queries/find-list-cards/cache.js +1 -0
  37. package/dist/src/application/resources/post/operations/queries/find-list-cards/validation/schema.js +1 -0
  38. package/dist/src/application/resources/post/operations/queries/find-relations/cache.js +12 -0
  39. package/dist/src/application/resources/post/operations/queries/find-relations/post-find-relations-query.js +32 -0
  40. package/dist/src/application/resources/seo-metadata/operations/commands/upsert/validation/schema.js +3 -3
  41. package/dist/src/application/sessions/admin/authenticate/admin-session-authenticate.js +43 -19
  42. package/dist/src/composition/create-sitero-server.js +20 -2
  43. package/dist/src/kernel/executor/executor.js +1 -1
  44. package/dist/src/kernel/operation/error/normalize-operation-error.js +25 -0
  45. package/dist/src/kernel/operation/error/zod.js +56 -0
  46. package/dist/src/kernel/operation/result.js +1 -1
  47. package/dist/types/src/application/conventions/cache/constants.d.ts +1 -1
  48. package/dist/types/src/application/conventions/cache/constants.d.ts.map +1 -1
  49. package/dist/types/src/application/features/authentication/admin/operations/change-password/types.d.ts +1 -1
  50. package/dist/types/src/application/features/authentication/admin/operations/change-password/types.d.ts.map +1 -1
  51. package/dist/types/src/application/features/authentication/admin/operations/me/types.d.ts +1 -1
  52. package/dist/types/src/application/features/authentication/admin/operations/me/types.d.ts.map +1 -1
  53. package/dist/types/src/application/features/authentication/admin/operations/reset-password/types.d.ts +1 -1
  54. package/dist/types/src/application/features/authentication/admin/operations/reset-password/types.d.ts.map +1 -1
  55. package/dist/types/src/application/features/authentication/admin/operations/verify-email/types.d.ts +1 -1
  56. package/dist/types/src/application/features/authentication/admin/operations/verify-email/types.d.ts.map +1 -1
  57. package/dist/types/src/application/features/email-preview/operations/render-template/types.d.ts +1 -1
  58. package/dist/types/src/application/features/email-preview/operations/render-template/types.d.ts.map +1 -1
  59. package/dist/types/src/application/features/inquiry/operations/submit/inquiry-submit.d.ts.map +1 -1
  60. package/dist/types/src/application/features/uploads/constraints/create-storage-file-schema.d.ts.map +1 -1
  61. package/dist/types/src/application/features/uploads/operations/upload-file/upload-file.d.ts +1 -1
  62. package/dist/types/src/application/features/uploads/operations/upload-file/upload-file.d.ts.map +1 -1
  63. package/dist/types/src/application/features/uploads/operations/upload-files/types.d.ts +7 -1
  64. package/dist/types/src/application/features/uploads/operations/upload-files/types.d.ts.map +1 -1
  65. package/dist/types/src/application/features/uploads/operations/upload-files/upload-files.d.ts +1 -1
  66. package/dist/types/src/application/features/uploads/operations/upload-files/upload-files.d.ts.map +1 -1
  67. package/dist/types/src/application/resources/admin/errors/operation-errors.d.ts.map +1 -1
  68. package/dist/types/src/application/resources/admin-refresh-token/operations/commands/delete/admin-refresh-token-delete-command.d.ts.map +1 -1
  69. package/dist/types/src/application/resources/admin-refresh-token/ports.d.ts +17 -0
  70. package/dist/types/src/application/resources/admin-refresh-token/ports.d.ts.map +1 -1
  71. package/dist/types/src/application/resources/config/index.d.ts +1 -1
  72. package/dist/types/src/application/resources/config/index.d.ts.map +1 -1
  73. package/dist/types/src/application/resources/config/operations/commands/update/cache.d.ts.map +1 -1
  74. package/dist/types/src/application/resources/config/operations/commands/update/validation/schema.d.ts +20 -20
  75. package/dist/types/src/application/resources/config/operations/queries/find-detail/cache.d.ts.map +1 -1
  76. package/dist/types/src/application/resources/config/operations/queries/find-detail/config-find-detail-query.d.ts.map +1 -1
  77. package/dist/types/src/application/resources/config/operations/queries/find-many/cache.d.ts.map +1 -1
  78. package/dist/types/src/application/resources/config/operations/queries/find-many/types.d.ts.map +1 -1
  79. package/dist/types/src/application/resources/file/errors/codes.d.ts +1 -0
  80. package/dist/types/src/application/resources/file/errors/codes.d.ts.map +1 -1
  81. package/dist/types/src/application/resources/file/index.d.ts +3 -3
  82. package/dist/types/src/application/resources/file/index.d.ts.map +1 -1
  83. package/dist/types/src/application/resources/file/operations/commands/create/file-create-command.d.ts +1 -1
  84. package/dist/types/src/application/resources/file/operations/commands/create/file-create-command.d.ts.map +1 -1
  85. package/dist/types/src/application/resources/file/operations/commands/create/validation/schema.d.ts.map +1 -1
  86. package/dist/types/src/application/resources/file/operations/commands/create-many/file-create-many-command.d.ts +1 -1
  87. package/dist/types/src/application/resources/file/operations/commands/create-many/file-create-many-command.d.ts.map +1 -1
  88. package/dist/types/src/application/resources/file/operations/commands/create-many/types.d.ts +2 -0
  89. package/dist/types/src/application/resources/file/operations/commands/create-many/types.d.ts.map +1 -1
  90. package/dist/types/src/application/resources/file/operations/commands/purge-many/cache.d.ts.map +1 -1
  91. package/dist/types/src/application/resources/file/operations/commands/purge-many/file-purge-many-command.d.ts +3 -3
  92. package/dist/types/src/application/resources/file/operations/commands/purge-many/file-purge-many-command.d.ts.map +1 -1
  93. package/dist/types/src/application/resources/file/operations/commands/replace-content/file-replace-content-command.d.ts +1 -1
  94. package/dist/types/src/application/resources/file/operations/commands/replace-content/file-replace-content-command.d.ts.map +1 -1
  95. package/dist/types/src/application/resources/file/operations/commands/replace-content/validation/validate-input.d.ts +1 -1
  96. package/dist/types/src/application/resources/file/operations/commands/replace-content/validation/validate-input.d.ts.map +1 -1
  97. package/dist/types/src/application/resources/file/operations/commands/restore-many/file-restore-many-command.d.ts.map +1 -1
  98. package/dist/types/src/application/resources/file/operations/commands/restore-many/types.d.ts +1 -1
  99. package/dist/types/src/application/resources/file/operations/commands/restore-many/types.d.ts.map +1 -1
  100. package/dist/types/src/application/resources/file/operations/commands/update/validation/schema.d.ts.map +1 -1
  101. package/dist/types/src/application/resources/file/operations/index.d.ts +1 -1
  102. package/dist/types/src/application/resources/file/operations/index.d.ts.map +1 -1
  103. package/dist/types/src/application/resources/file/operations/queries/find-list-cards/types.d.ts +2 -1
  104. package/dist/types/src/application/resources/file/operations/queries/find-list-cards/types.d.ts.map +1 -1
  105. package/dist/types/src/application/resources/file/operations/queries/find-list-cards/validation/schema.d.ts +1 -1
  106. package/dist/types/src/application/resources/file/operations/queries/find-relations/cache.d.ts +4 -0
  107. package/dist/types/src/application/resources/file/operations/queries/find-relations/cache.d.ts.map +1 -0
  108. package/dist/types/src/application/resources/file/operations/queries/find-relations/file-find-relations-query.d.ts +8 -0
  109. package/dist/types/src/application/resources/file/operations/queries/find-relations/file-find-relations-query.d.ts.map +1 -0
  110. package/dist/types/src/application/resources/file/operations/queries/find-relations/index.d.ts +3 -0
  111. package/dist/types/src/application/resources/file/operations/queries/find-relations/index.d.ts.map +1 -0
  112. package/dist/types/src/application/resources/file/operations/queries/find-relations/types.d.ts +11 -0
  113. package/dist/types/src/application/resources/file/operations/queries/find-relations/types.d.ts.map +1 -0
  114. package/dist/types/src/application/resources/file/operations/queries/index.d.ts +3 -0
  115. package/dist/types/src/application/resources/file/operations/queries/index.d.ts.map +1 -1
  116. package/dist/types/src/application/resources/file/operations/queries/validate-create/file-validate-create-query.d.ts +12 -0
  117. package/dist/types/src/application/resources/file/operations/queries/validate-create/file-validate-create-query.d.ts.map +1 -0
  118. package/dist/types/src/application/resources/file/operations/queries/validate-create/index.d.ts +3 -0
  119. package/dist/types/src/application/resources/file/operations/queries/validate-create/index.d.ts.map +1 -0
  120. package/dist/types/src/application/resources/file/operations/queries/validate-create/types.d.ts +16 -0
  121. package/dist/types/src/application/resources/file/operations/queries/validate-create/types.d.ts.map +1 -0
  122. package/dist/types/src/application/resources/file/operations/queries/validate-create/validation/schema.d.ts +9 -0
  123. package/dist/types/src/application/resources/file/operations/queries/validate-create/validation/schema.d.ts.map +1 -0
  124. package/dist/types/src/application/resources/file/operations/queries/validate-create/validation/validate-input.d.ts +3 -0
  125. package/dist/types/src/application/resources/file/operations/queries/validate-create/validation/validate-input.d.ts.map +1 -0
  126. package/dist/types/src/application/resources/file/operations/queries/validate-update/file-validate-update-query.d.ts +14 -0
  127. package/dist/types/src/application/resources/file/operations/queries/validate-update/file-validate-update-query.d.ts.map +1 -0
  128. package/dist/types/src/application/resources/file/operations/queries/validate-update/index.d.ts +3 -0
  129. package/dist/types/src/application/resources/file/operations/queries/validate-update/index.d.ts.map +1 -0
  130. package/dist/types/src/application/resources/file/operations/queries/validate-update/types.d.ts +9 -0
  131. package/dist/types/src/application/resources/file/operations/queries/validate-update/types.d.ts.map +1 -0
  132. package/dist/types/src/application/resources/file/ports.d.ts +38 -8
  133. package/dist/types/src/application/resources/file/ports.d.ts.map +1 -1
  134. package/dist/types/src/application/resources/file/projections/detail.d.ts +1 -1
  135. package/dist/types/src/application/resources/file/projections/detail.d.ts.map +1 -1
  136. package/dist/types/src/application/resources/file/projections/index.d.ts +1 -0
  137. package/dist/types/src/application/resources/file/projections/index.d.ts.map +1 -1
  138. package/dist/types/src/application/resources/file/projections/relations.d.ts +12 -0
  139. package/dist/types/src/application/resources/file/projections/relations.d.ts.map +1 -0
  140. package/dist/types/src/application/resources/file/validation/file-translations-schema.d.ts +8 -0
  141. package/dist/types/src/application/resources/file/validation/file-translations-schema.d.ts.map +1 -0
  142. package/dist/types/src/application/resources/inquiry/operations/queries/find/inquiry-find-query.d.ts.map +1 -1
  143. package/dist/types/src/application/resources/inquiry/operations/queries/find-list-cards/types.d.ts +2 -2
  144. package/dist/types/src/application/resources/inquiry/operations/queries/find-list-cards/types.d.ts.map +1 -1
  145. package/dist/types/src/application/resources/post/index.d.ts +3 -3
  146. package/dist/types/src/application/resources/post/index.d.ts.map +1 -1
  147. package/dist/types/src/application/resources/post/operations/commands/create/validation/schema.d.ts +8 -2
  148. package/dist/types/src/application/resources/post/operations/commands/create/validation/schema.d.ts.map +1 -1
  149. package/dist/types/src/application/resources/post/operations/commands/delete/cache.d.ts +1 -1
  150. package/dist/types/src/application/resources/post/operations/commands/delete/cache.d.ts.map +1 -1
  151. package/dist/types/src/application/resources/post/operations/commands/delete/types.d.ts +1 -1
  152. package/dist/types/src/application/resources/post/operations/commands/delete/types.d.ts.map +1 -1
  153. package/dist/types/src/application/resources/post/operations/commands/update/post-update-command.d.ts +1 -1
  154. package/dist/types/src/application/resources/post/operations/commands/update/post-update-command.d.ts.map +1 -1
  155. package/dist/types/src/application/resources/post/operations/commands/update/validation/schema.d.ts +8 -2
  156. package/dist/types/src/application/resources/post/operations/commands/update/validation/schema.d.ts.map +1 -1
  157. package/dist/types/src/application/resources/post/operations/commands/update/validation/validate-input.d.ts.map +1 -1
  158. package/dist/types/src/application/resources/post/operations/index.d.ts +1 -1
  159. package/dist/types/src/application/resources/post/operations/index.d.ts.map +1 -1
  160. package/dist/types/src/application/resources/post/operations/queries/find-detail/validation/validate-input.d.ts.map +1 -1
  161. package/dist/types/src/application/resources/post/operations/queries/find-list-cards/cache.d.ts.map +1 -1
  162. package/dist/types/src/application/resources/post/operations/queries/find-list-cards/validation/schema.d.ts +1 -0
  163. package/dist/types/src/application/resources/post/operations/queries/find-list-cards/validation/schema.d.ts.map +1 -1
  164. package/dist/types/src/application/resources/post/operations/queries/find-relations/cache.d.ts +4 -0
  165. package/dist/types/src/application/resources/post/operations/queries/find-relations/cache.d.ts.map +1 -0
  166. package/dist/types/src/application/resources/post/operations/queries/find-relations/index.d.ts +3 -0
  167. package/dist/types/src/application/resources/post/operations/queries/find-relations/index.d.ts.map +1 -0
  168. package/dist/types/src/application/resources/post/operations/queries/find-relations/post-find-relations-query.d.ts +6 -0
  169. package/dist/types/src/application/resources/post/operations/queries/find-relations/post-find-relations-query.d.ts.map +1 -0
  170. package/dist/types/src/application/resources/post/operations/queries/find-relations/types.d.ts +11 -0
  171. package/dist/types/src/application/resources/post/operations/queries/find-relations/types.d.ts.map +1 -0
  172. package/dist/types/src/application/resources/post/operations/queries/index.d.ts +1 -0
  173. package/dist/types/src/application/resources/post/operations/queries/index.d.ts.map +1 -1
  174. package/dist/types/src/application/resources/post/ports.d.ts +8 -1
  175. package/dist/types/src/application/resources/post/ports.d.ts.map +1 -1
  176. package/dist/types/src/application/resources/post/projections/index.d.ts +1 -0
  177. package/dist/types/src/application/resources/post/projections/index.d.ts.map +1 -1
  178. package/dist/types/src/application/resources/post/projections/relations.d.ts +10 -0
  179. package/dist/types/src/application/resources/post/projections/relations.d.ts.map +1 -0
  180. package/dist/types/src/application/resources/seo-metadata/operations/commands/upsert/validation/schema.d.ts.map +1 -1
  181. package/dist/types/src/application/sessions/admin/authenticate/admin-session-authenticate.d.ts.map +1 -1
  182. package/dist/types/src/composition/create-sitero-server.d.ts.map +1 -1
  183. package/dist/types/src/composition/policies.d.ts +1 -0
  184. package/dist/types/src/composition/policies.d.ts.map +1 -1
  185. package/dist/types/src/composition/types.d.ts +9 -2
  186. package/dist/types/src/composition/types.d.ts.map +1 -1
  187. package/dist/types/src/contracts/email/template.d.ts +2 -0
  188. package/dist/types/src/contracts/email/template.d.ts.map +1 -1
  189. package/dist/types/src/contracts/operation/index.d.ts +1 -1
  190. package/dist/types/src/contracts/operation/index.d.ts.map +1 -1
  191. package/dist/types/src/contracts/operation/result.d.ts +11 -1
  192. package/dist/types/src/contracts/operation/result.d.ts.map +1 -1
  193. package/dist/types/src/contracts/storage/port.d.ts +1 -1
  194. package/dist/types/src/contracts/storage/port.d.ts.map +1 -1
  195. package/dist/types/src/index.d.ts +6 -4
  196. package/dist/types/src/index.d.ts.map +1 -1
  197. package/dist/types/src/kernel/index.d.ts +1 -1
  198. package/dist/types/src/kernel/index.d.ts.map +1 -1
  199. package/dist/types/src/kernel/operation/error/index.d.ts +2 -0
  200. package/dist/types/src/kernel/operation/error/index.d.ts.map +1 -0
  201. package/dist/types/src/kernel/operation/{error.d.ts → error/normalize-operation-error.d.ts} +2 -2
  202. package/dist/types/src/kernel/operation/error/normalize-operation-error.d.ts.map +1 -0
  203. package/dist/types/src/kernel/operation/error/zod.d.ts +17 -0
  204. package/dist/types/src/kernel/operation/error/zod.d.ts.map +1 -0
  205. package/dist/types/src/kernel/operation/index.d.ts +1 -1
  206. package/dist/types/src/kernel/operation/index.d.ts.map +1 -1
  207. package/package.json +2 -2
  208. package/dist/src/kernel/operation/error.js +0 -33
  209. package/dist/types/src/kernel/operation/error.d.ts.map +0 -1
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # sitero-server
2
+
3
+ `sitero-server` is Sitero's framework-neutral application core. It owns
4
+ resource operations, policies, execution contracts, and cache semantics; it
5
+ does not depend on Next.js, HTTP, Prisma, Redis, or UI code.
6
+
7
+ Use it directly when composing a custom host or delivery adapter. Next.js
8
+ applications using Sitero normally use the higher-level `sitero` package.
9
+
10
+ ````bash
11
+ pnpm add sitero-server@0.2.0 sitero-domain@0.2.0
12
+ ````
13
+
14
+ Keep `sitero-domain`, `sitero-server`, and `sitero` on the same version. The
15
+ source repository documents resource boundaries in `docs/sitero-server/`.
@@ -2,13 +2,15 @@ export { createSiteroServer } from '../src/composition/create-sitero-server.js';
2
2
  export { createNoopRateLimiterPort } from '../src/contracts/rate-limiter/port.js';
3
3
  export { OperationError } from '../src/contracts/operation/error.js';
4
4
  export { operationResult } from '../src/contracts/operation/result.js';
5
- export { AUTH_ADMIN_FIELD_ERROR_CODES } from '../src/application/features/authentication/admin/errors/codes.js';
6
5
  export { createOperation } from '../src/kernel/operation/operation.js';
7
- import 'zod';
6
+ export { normalizeOperationError } from '../src/kernel/operation/error/normalize-operation-error.js';
8
7
  export { ExecutorError, RateLimitedExecutorError, UnauthenticatedExecutorError, UnauthorizedExecutorError, executorError } from '../src/kernel/executor/error.js';
9
8
  export { createOperationExecutor } from '../src/kernel/executor/executor.js';
9
+ export { AUTH_ADMIN_FIELD_ERROR_CODES } from '../src/application/features/authentication/admin/errors/codes.js';
10
10
  export { ADMIN_SIGN_IN_ERROR_CODES } from '../src/application/features/authentication/admin/operations/sign-in/errors.js';
11
+ import 'zod';
11
12
  import 'sitero-domain';
13
+ export { FileNotFoundError } from '../src/application/resources/file/errors/operation-errors.js';
12
14
  import 'p-limit';
13
15
  export { ADMIN_ME_ERROR_CODES } from '../src/application/features/authentication/admin/operations/me/errors.js';
14
16
  export { ADMIN_VERIFY_EMAIL_ERROR_CODES } from '../src/application/features/authentication/admin/operations/verify-email/errors.js';
@@ -52,7 +52,7 @@ function createAdminSignIn(input) {
52
52
  return adminRefreshTokenCommandPort.create({
53
53
  tokenHash,
54
54
  email: admin.email,
55
- ip,
55
+ lastIp: ip,
56
56
  deviceInfo: deviceInfo ?? null,
57
57
  expiresAt,
58
58
  adminId: admin.id
@@ -25,28 +25,26 @@ function createInquirySubmitOperation(input) {
25
25
  async (input2, context) => {
26
26
  const inquiry = await inquiryCommandPort.create(input2.formData);
27
27
  if (newInquiryEmail) {
28
- const recipients = await adminInquiryNotificationRecipientQueryPort.findInquiryNotificationRecipients();
29
- if (recipients.length > 0) {
28
+ const reportEmailError = (error) => notifyObserverSafely(
29
+ observer,
30
+ (observer2) => observer2.onEffectError?.({ context, effect: "email", error })
31
+ );
32
+ void (async () => {
30
33
  try {
34
+ const recipients = await adminInquiryNotificationRecipientQueryPort.findInquiryNotificationRecipients();
31
35
  await Promise.all(
32
36
  recipients.map(async ({ email, preferredLocale }) => {
33
- await newInquiryEmail({
34
- email,
35
- locale: preferredLocale
36
- });
37
+ try {
38
+ await newInquiryEmail({ email, locale: preferredLocale });
39
+ } catch (error) {
40
+ await reportEmailError(error);
41
+ }
37
42
  })
38
43
  );
39
44
  } catch (error) {
40
- await notifyObserverSafely(
41
- observer,
42
- (observer2) => observer2.onEffectError?.({
43
- context,
44
- effect: "email",
45
- error
46
- })
47
- );
45
+ await reportEmailError(error);
48
46
  }
49
- }
47
+ })();
50
48
  }
51
49
  return operationResult.success({ inquiry });
52
50
  }
@@ -3,7 +3,7 @@ import { isStorageFile } from '../../../../contracts/storage/file.js';
3
3
  import { UPLOAD_FIELD_ERROR_CODES } from '../validation-codes.js';
4
4
 
5
5
  function createStorageFileSchema(policy) {
6
- return z.custom(isStorageFile).refine(
6
+ return z.custom(isStorageFile).refine((file) => file.size > 0, { message: "validation.file.required" }).refine(
7
7
  (file) => policy?.maxFileSizeInBytes === void 0 || file.size <= policy.maxFileSizeInBytes,
8
8
  { message: UPLOAD_FIELD_ERROR_CODES.FILE_TOO_LARGE }
9
9
  ).refine(
@@ -22,25 +22,43 @@ function createUploadFilesOperation(input) {
22
22
  },
23
23
  async (input2) => {
24
24
  const limit = pLimit(concurrency);
25
- const uploadedFiles = await Promise.all(
25
+ const outcomes = await Promise.all(
26
26
  input2.files.map(
27
- (file) => limit(async () => {
28
- const key = await storageUploadPort.upload({ file });
29
- return {
30
- key,
31
- fileMeta: {
32
- name: file.name,
33
- size: file.size,
34
- type: file.type
35
- },
36
- width: file.width,
37
- height: file.height,
38
- duration: file.duration
39
- };
27
+ (file, index) => limit(async () => {
28
+ try {
29
+ const key = await storageUploadPort.upload({ file });
30
+ return {
31
+ status: "uploaded",
32
+ file: {
33
+ index,
34
+ key,
35
+ fileMeta: {
36
+ name: file.name,
37
+ size: file.size,
38
+ type: file.type
39
+ },
40
+ width: file.width,
41
+ height: file.height,
42
+ duration: file.duration
43
+ }
44
+ };
45
+ } catch {
46
+ return {
47
+ status: "failed",
48
+ failure: { index, code: "INTERNAL_ERROR" }
49
+ };
50
+ }
40
51
  })
41
52
  )
42
53
  );
43
- return operationResult.success({ uploadedFiles });
54
+ return operationResult.success({
55
+ uploadedFiles: outcomes.flatMap(
56
+ (outcome) => outcome.status === "uploaded" ? [outcome.file] : []
57
+ ),
58
+ failed: outcomes.flatMap(
59
+ (outcome) => outcome.status === "failed" ? [outcome.failure] : []
60
+ )
61
+ });
44
62
  }
45
63
  );
46
64
  }
@@ -14,6 +14,7 @@ class AdminEmailAlreadyExistsError extends OperationError {
14
14
  fields: [
15
15
  {
16
16
  path: ["email"],
17
+ kind: "custom",
17
18
  code: ADMIN_FIELD_ERROR_CODES.EMAIL_ALREADY_EXISTS
18
19
  }
19
20
  ]
@@ -27,6 +27,9 @@ function createAdminRefreshTokenDeleteCommand(input) {
27
27
  if (!adminRefreshToken) {
28
28
  throw new AdminRefreshTokenNotFoundError();
29
29
  }
30
+ if (input2.id === context.session?.id) {
31
+ throw new AdminRefreshTokenDeleteForbiddenError();
32
+ }
30
33
  const isSelf = actor.id === adminRefreshToken.adminId;
31
34
  const canModifyOthers = actor.role === ADMIN_ROLES.SUPER_ADMIN;
32
35
  if (!isSelf && !canModifyOthers) {
@@ -12,7 +12,6 @@ const createConfigUpdateInvalidationTags = (input, result) => {
12
12
  ...configs.flatMap((config) => [
13
13
  createResourceTag("config", { id: config.id }),
14
14
  createResourceTag("config", { slug: config.slug }),
15
- createRelationTag("config", "translation", { id: config.id }),
16
15
  // Relation: [File] files1, files2, file1, file2, file3, file4
17
16
  createRelationTag("config", "file", { id: config.id })
18
17
  ]),
@@ -5,7 +5,7 @@ import { textSchema, requiredTextSchema, singleItemSchema, multiItemsSchema, idS
5
5
  const nullableText = textSchema().nullable();
6
6
  const nullableDecimal = z.number().nullable();
7
7
  const nullableInteger = z.number().int().nullable();
8
- const data = z.array(z.unknown());
8
+ const data = z.array(textSchema());
9
9
  const configUpdateInputSchema = () => z.object({
10
10
  id: idSchema(),
11
11
  config: z.object({
@@ -11,7 +11,6 @@ const createConfigFindDetailCacheTags = (_, result) => {
11
11
  return [
12
12
  createResourceTag("config", { id: config.id }),
13
13
  createResourceTag("config", { slug: config.slug }),
14
- createRelationTag("config", "translation", { id: config.id }),
15
14
  // Relation: [File] files1, files2, file1, file2, file3, file4
16
15
  ...fileIds.map((fileId) => createResourceTag("file", { id: fileId })),
17
16
  createRelationTag("config", "file", { id: config.id })
@@ -25,9 +25,7 @@ function createConfigFindDetailQuery(input) {
25
25
  slug: input2.slug
26
26
  });
27
27
  if (!config) {
28
- return operationResult.failure(
29
- new ConfigNotFoundError()
30
- );
28
+ return operationResult.failure(new ConfigNotFoundError());
31
29
  }
32
30
  return operationResult.success({
33
31
  config
@@ -19,7 +19,6 @@ const createConfigFindManyCacheTags = (input, result) => {
19
19
  ...configs.flatMap((config) => [
20
20
  createResourceTag("config", { id: config.id }),
21
21
  createResourceTag("config", { slug: config.slug }),
22
- createRelationTag("config", "translation", { id: config.id }),
23
22
  // Relation: [File] files1, files2, file1, file2, file3, file4
24
23
  ...collectConfigFileIds(config).map(
25
24
  (fileId) => createResourceTag("file", { id: fileId })
@@ -6,7 +6,7 @@ async function assertFileExists(input) {
6
6
  return;
7
7
  }
8
8
  const file = await fileQueryPort.find({ id });
9
- if (!file) {
9
+ if (!file || file.deletedAt || file.purgeStartedAt) {
10
10
  throw new FileNotFoundError();
11
11
  }
12
12
  }
@@ -8,6 +8,7 @@ const FILE_ERROR_CODES = {
8
8
  REPLACE_CONTENT_LOCKED: "FILE_REPLACE_CONTENT_LOCKED",
9
9
  REPLACE_CONTENT_IN_USE: "FILE_REPLACE_CONTENT_IN_USE",
10
10
  REPLACE_CONTENT_SAME_KEY: "FILE_REPLACE_CONTENT_SAME_KEY",
11
+ RESTORE_PURGE_STARTED: "FILE_RESTORE_PURGE_STARTED",
11
12
  RESTORE_NOT_DELETED: "FILE_RESTORE_NOT_DELETED",
12
13
  PURGE_NOT_DELETED: "FILE_PURGE_NOT_DELETED",
13
14
  PURGE_LOCKED: "FILE_PURGE_LOCKED",
@@ -1,8 +1,8 @@
1
1
  import { createOperation } from '../../../../../../kernel/operation/operation.js';
2
2
  import 'zod';
3
3
  import { operationResult } from '../../../../../../contracts/operation/result.js';
4
- import { createFileCreateInvalidationTags } from './cache.js';
5
4
  import { registerUploadedFile } from '../register-uploaded-file.js';
5
+ import { createFileCreateInvalidationTags } from './cache.js';
6
6
  import { validateInput } from './validation/validate-input.js';
7
7
 
8
8
  function createFileCreateCommand(input) {
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { addDuplicateLocaleIssues } from '../../../../../../conventions/validation/add-duplicate-locale-issues.js';
3
- import { textSchema, requiredTextSchema } from '../../../../../../conventions/validation/schema.js';
2
+ import { requiredTextSchema } from '../../../../../../conventions/validation/schema.js';
3
+ import { fileTranslationsSchema } from '../../../../validation/file-translations-schema.js';
4
4
 
5
5
  const fileCreateInputSchema = () => z.object({
6
6
  key: requiredTextSchema(),
@@ -10,13 +10,7 @@ const fileCreateInputSchema = () => z.object({
10
10
  width: z.number().int().nonnegative().nullable(),
11
11
  height: z.number().int().nonnegative().nullable(),
12
12
  duration: z.number().nonnegative().nullable(),
13
- translations: z.array(
14
- z.object({
15
- locale: requiredTextSchema(),
16
- name: textSchema().nullable(),
17
- alt: textSchema().nullable()
18
- })
19
- ).min(1).superRefine(addDuplicateLocaleIssues)
13
+ translations: fileTranslationsSchema()
20
14
  });
21
15
 
22
16
  export { fileCreateInputSchema };
@@ -43,9 +43,18 @@ function createFileCreateManyCommand(input) {
43
43
  });
44
44
  return { status: "created", file: created2 };
45
45
  } catch (error) {
46
+ let retryable = false;
47
+ try {
48
+ const existing = await fileLookupPort.find({ key: file.key });
49
+ if (existing)
50
+ return { status: "created", file: existing };
51
+ retryable = true;
52
+ } catch {
53
+ }
46
54
  const failure = {
47
55
  key: file.key,
48
- code: "INTERNAL_ERROR"
56
+ code: "INTERNAL_ERROR",
57
+ retryable
49
58
  };
50
59
  await notifyObserverSafely(
51
60
  observer,
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { fileCreateInputSchema } from '../../create/validation/schema.js';
3
2
  import { FILE_FIELD_ERROR_CODES } from '../../../../errors/codes.js';
3
+ import { fileCreateInputSchema } from '../../create/validation/schema.js';
4
4
 
5
5
  const fileCreateManyInputSchema = () => z.object({
6
6
  files: z.array(fileCreateInputSchema()).min(1).superRefine((files, context) => {
@@ -1,11 +1,15 @@
1
1
  import { createResourceTag } from '../../../../../conventions/cache/cache-tag.js';
2
2
 
3
3
  const createFilePurgeManyInvalidationTags = (_, result) => {
4
- const { purged } = result.data;
5
- if (purged.length === 0) return [];
4
+ const { purged, failed } = result.data;
5
+ const ids = [
6
+ ...purged.map((file) => file.id),
7
+ ...failed.map((file) => file.id)
8
+ ];
9
+ if (ids.length === 0) return [];
6
10
  return [
7
11
  createResourceTag("file"),
8
- ...purged.map((file) => createResourceTag("file", { id: file.id }))
12
+ ...ids.map((id) => createResourceTag("file", { id }))
9
13
  ].flat();
10
14
  };
11
15
 
@@ -1,9 +1,9 @@
1
- import { FILE_ERROR_CODES } from '../../../errors/codes.js';
2
- import { operationResult } from '../../../../../../contracts/operation/result.js';
3
1
  import pLimit from 'p-limit';
4
2
  import { createOperation } from '../../../../../../kernel/operation/operation.js';
5
3
  import 'zod';
4
+ import { operationResult } from '../../../../../../contracts/operation/result.js';
6
5
  import { notifyObserverSafely } from '../../../../../../kernel/observer/notify-observer-safely.js';
6
+ import { FILE_ERROR_CODES } from '../../../errors/codes.js';
7
7
  import { createFilePurgeManyInvalidationTags } from './cache.js';
8
8
  import { validateInput } from './validation/validate-input.js';
9
9
 
@@ -11,7 +11,7 @@ const MAX_CONCURRENCY = 5;
11
11
  function createFilePurgeManyCommand(input) {
12
12
  const {
13
13
  authorization,
14
- fileCommandPort,
14
+ filePurgePort,
15
15
  fileQueryPort,
16
16
  storageRemovePort,
17
17
  observer
@@ -32,6 +32,7 @@ function createFilePurgeManyCommand(input) {
32
32
  const outcomes = await Promise.all(
33
33
  input2.ids.map(
34
34
  (id) => limit(async () => {
35
+ let effect = "persistence";
35
36
  try {
36
37
  const file = await fileQueryPort.findDetail({ id });
37
38
  if (!file) {
@@ -62,36 +63,15 @@ function createFilePurgeManyCommand(input) {
62
63
  code: FILE_ERROR_CODES.PURGE_IN_USE
63
64
  };
64
65
  }
65
- let purged;
66
- try {
67
- purged = await fileCommandPort.purge({ id });
68
- } catch (error) {
69
- const failure = {
70
- id,
71
- code: "INTERNAL_ERROR"
72
- };
73
- await notifyObserverSafely(
74
- observer,
75
- (observer2) => observer2.onEffectError?.({
76
- context,
77
- effect: "persistence",
78
- error: { id, error }
79
- })
80
- );
81
- return { status: "failed", failure };
82
- }
83
- try {
84
- await storageRemovePort.remove({ key: file.key });
85
- } catch (error) {
86
- await notifyObserverSafely(
87
- observer,
88
- (observer2) => observer2.onEffectError?.({
89
- context,
90
- effect: "storage",
91
- error: { id, key: file.key, error }
92
- })
93
- );
94
- }
66
+ await filePurgePort.prepare({ id });
67
+ const purged = await filePurgePort.complete(
68
+ { id },
69
+ async (object) => {
70
+ effect = "storage";
71
+ await storageRemovePort.remove(object);
72
+ effect = "persistence";
73
+ }
74
+ );
95
75
  return { status: "purged", file: purged };
96
76
  } catch (error) {
97
77
  const failure = {
@@ -102,7 +82,7 @@ function createFilePurgeManyCommand(input) {
102
82
  observer,
103
83
  (observer2) => observer2.onEffectError?.({
104
84
  context,
105
- effect: "persistence",
85
+ effect,
106
86
  error: { id, error }
107
87
  })
108
88
  );
@@ -1,9 +1,9 @@
1
- import { FILE_ERROR_CODES } from '../../../errors/codes.js';
2
- import { operationResult } from '../../../../../../contracts/operation/result.js';
3
1
  import pLimit from 'p-limit';
4
2
  import { createOperation } from '../../../../../../kernel/operation/operation.js';
5
3
  import 'zod';
4
+ import { operationResult } from '../../../../../../contracts/operation/result.js';
6
5
  import { notifyObserverSafely } from '../../../../../../kernel/observer/notify-observer-safely.js';
6
+ import { FILE_ERROR_CODES } from '../../../errors/codes.js';
7
7
  import { createFileRestoreManyInvalidationTags } from './cache.js';
8
8
  import { validateInput } from './validation/validate-input.js';
9
9
 
@@ -42,8 +42,25 @@ function createFileRestoreManyCommand(input) {
42
42
  code: FILE_ERROR_CODES.RESTORE_NOT_DELETED
43
43
  };
44
44
  }
45
- const restored = await fileCommandPort.restore({ id });
46
- return { status: "restored", file: restored };
45
+ if (file.purgeStartedAt) {
46
+ return {
47
+ status: "skipped",
48
+ id,
49
+ code: FILE_ERROR_CODES.RESTORE_PURGE_STARTED
50
+ };
51
+ }
52
+ const result = await fileCommandPort.restore({ id });
53
+ if (result.status === "restored") return result;
54
+ const codes = {
55
+ "not-found": FILE_ERROR_CODES.NOT_FOUND,
56
+ "not-deleted": FILE_ERROR_CODES.RESTORE_NOT_DELETED,
57
+ "purge-started": FILE_ERROR_CODES.RESTORE_PURGE_STARTED
58
+ };
59
+ return {
60
+ status: "skipped",
61
+ id,
62
+ code: codes[result.status]
63
+ };
47
64
  } catch (error) {
48
65
  const failure = {
49
66
  id,
@@ -1,16 +1,10 @@
1
1
  import { z } from 'zod';
2
- import { addDuplicateLocaleIssues } from '../../../../../../conventions/validation/add-duplicate-locale-issues.js';
3
- import { textSchema, requiredTextSchema, idSchema } from '../../../../../../conventions/validation/schema.js';
2
+ import { idSchema } from '../../../../../../conventions/validation/schema.js';
3
+ import { fileTranslationsSchema } from '../../../../validation/file-translations-schema.js';
4
4
 
5
5
  const fileUpdateInputSchema = () => z.object({
6
6
  id: idSchema(),
7
- translations: z.array(
8
- z.object({
9
- locale: requiredTextSchema(),
10
- name: textSchema().nullable(),
11
- alt: textSchema().nullable()
12
- })
13
- ).min(1).superRefine(addDuplicateLocaleIssues)
7
+ translations: fileTranslationsSchema()
14
8
  });
15
9
 
16
10
  export { fileUpdateInputSchema };
@@ -4,7 +4,7 @@ import { createResourceTag } from '../../../../../conventions/cache/cache-tag.js
4
4
  const createFileFindListCardsCacheKey = (input) => createCacheKey("file", "find-list-cards", {
5
5
  locale: input.locale,
6
6
  searchString: input.searchString,
7
- type: input.type,
7
+ types: normalizeSelection(input.types),
8
8
  isDeleted: input.isDeleted,
9
9
  isLocked: input.isLocked,
10
10
  isInUse: input.isInUse,
@@ -5,7 +5,7 @@ import { idSchema, textSchema, requiredTextSchema } from '../../../../../../conv
5
5
  const fileFindListCardsInputSchema = () => z.object({
6
6
  locale: requiredTextSchema(),
7
7
  searchString: textSchema().optional(),
8
- type: z.enum(FILE_TYPES).nullable().optional(),
8
+ types: z.array(z.enum(FILE_TYPES)).optional(),
9
9
  isDeleted: z.boolean().optional(),
10
10
  isLocked: z.boolean().nullable().optional(),
11
11
  isInUse: z.boolean().nullable().optional(),
@@ -0,0 +1,7 @@
1
+ import { createCacheKey } from '../../../../../conventions/cache/cache-key.js';
2
+ import { createResourceTag } from '../../../../../conventions/cache/cache-tag.js';
3
+
4
+ const createFileFindRelationsCacheKey = (input) => createCacheKey("file", "find-relations", { id: input.id });
5
+ const createFileFindRelationsCacheTags = (input) => [createResourceTag("file", { id: input.id })].flat();
6
+
7
+ export { createFileFindRelationsCacheKey, createFileFindRelationsCacheTags };
@@ -0,0 +1,36 @@
1
+ import { createOperation } from '../../../../../../kernel/operation/operation.js';
2
+ import 'zod';
3
+ import { operationResult } from '../../../../../../contracts/operation/result.js';
4
+ import { FileNotFoundError } from '../../../errors/operation-errors.js';
5
+ import { fileFindDetailInputSchema } from '../find-detail/validation/schema.js';
6
+ import { createFileFindRelationsCacheTags, createFileFindRelationsCacheKey } from './cache.js';
7
+
8
+ function createFileFindRelationsQuery(input) {
9
+ const { authorization, fileRelationsQueryPort } = input;
10
+ return createOperation(
11
+ {
12
+ authorization,
13
+ behavior: {
14
+ kind: "query",
15
+ cache: {
16
+ key: createFileFindRelationsCacheKey,
17
+ tags: createFileFindRelationsCacheTags
18
+ }
19
+ },
20
+ validate(input2) {
21
+ return fileFindDetailInputSchema().parse(input2);
22
+ }
23
+ },
24
+ async (input2) => {
25
+ const relations = await fileRelationsQueryPort.findRelations({
26
+ id: input2.id
27
+ });
28
+ if (!relations) {
29
+ return operationResult.failure(new FileNotFoundError());
30
+ }
31
+ return operationResult.success({ relations });
32
+ }
33
+ );
34
+ }
35
+
36
+ export { createFileFindRelationsQuery };
@@ -0,0 +1,17 @@
1
+ import { createOperation } from '../../../../../../kernel/operation/operation.js';
2
+ import 'zod';
3
+ import { operationResult } from '../../../../../../contracts/operation/result.js';
4
+ import { validateInput } from './validation/validate-input.js';
5
+
6
+ function createFileValidateCreateQuery(input) {
7
+ return createOperation(
8
+ {
9
+ authorization: input.authorization,
10
+ behavior: { kind: "query" },
11
+ validate: validateInput
12
+ },
13
+ () => Promise.resolve(operationResult.success({ valid: true }))
14
+ );
15
+ }
16
+
17
+ export { createFileValidateCreateQuery };
@@ -0,0 +1,6 @@
1
+ import { z } from 'zod';
2
+ import { fileTranslationsSchema } from '../../../../validation/file-translations-schema.js';
3
+
4
+ const fileValidateCreateInputSchema = () => z.object({ translations: fileTranslationsSchema() });
5
+
6
+ export { fileValidateCreateInputSchema };
@@ -0,0 +1,7 @@
1
+ import { fileValidateCreateInputSchema } from './schema.js';
2
+
3
+ function validateInput(input) {
4
+ return fileValidateCreateInputSchema().parse(input);
5
+ }
6
+
7
+ export { validateInput };
@@ -0,0 +1,17 @@
1
+ import { createOperation } from '../../../../../../kernel/operation/operation.js';
2
+ import 'zod';
3
+ import { operationResult } from '../../../../../../contracts/operation/result.js';
4
+ import { validateInput } from '../../commands/update/validation/validate-input.js';
5
+
6
+ function createFileValidateUpdateQuery(input) {
7
+ return createOperation(
8
+ {
9
+ authorization: input.authorization,
10
+ behavior: { kind: "query" },
11
+ validate: (rawInput) => validateInput({ input: rawInput, fileQueryPort: input.fileQueryPort })
12
+ },
13
+ () => Promise.resolve(operationResult.success({ valid: true }))
14
+ );
15
+ }
16
+
17
+ export { createFileValidateUpdateQuery };
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ import { addDuplicateLocaleIssues } from '../../../conventions/validation/add-duplicate-locale-issues.js';
3
+ import { textSchema, requiredTextSchema } from '../../../conventions/validation/schema.js';
4
+
5
+ const fileTranslationsSchema = () => z.array(
6
+ z.object({
7
+ locale: requiredTextSchema(),
8
+ name: textSchema().nullable(),
9
+ alt: textSchema().nullable()
10
+ })
11
+ ).min(1).superRefine(addDuplicateLocaleIssues);
12
+
13
+ export { fileTranslationsSchema };
@@ -24,9 +24,7 @@ function createInquiryFindQuery(input) {
24
24
  async (input2) => {
25
25
  const inquiry = await inquiryQueryPort.find(input2);
26
26
  if (!inquiry) {
27
- return operationResult.failure(
28
- new InquiryNotFoundError()
29
- );
27
+ return operationResult.failure(new InquiryNotFoundError());
30
28
  }
31
29
  return operationResult.success({ inquiry });
32
30
  }