@starci/hfs 5.2.0 → 5.3.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 (215) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +1 -1
  3. package/cache/hfs-family.d.mts +2 -3
  4. package/cache/hfs-family.mjs +4 -9
  5. package/cache/secret-records.d.mts +7 -0
  6. package/cache/secret-records.mjs +12 -0
  7. package/cache/session.mjs +4 -2
  8. package/codemod/account-doors.d.mts +36 -0
  9. package/codemod/account-doors.mjs +128 -0
  10. package/codemod/main.mjs +31 -1
  11. package/codemod/module-definition.d.mts +52 -0
  12. package/codemod/module-definition.mjs +242 -0
  13. package/codemod/quality-binding.d.mts +33 -0
  14. package/codemod/quality-binding.mjs +38 -0
  15. package/codemod/secrets-cache.d.mts +35 -0
  16. package/codemod/secrets-cache.mjs +70 -0
  17. package/codemod/sops-rules.d.mts +34 -0
  18. package/codemod/sops-rules.mjs +69 -0
  19. package/codemod/theme-tokens.mjs +48 -2
  20. package/lint/run.d.mts +6 -0
  21. package/lint/run.mjs +63 -10
  22. package/package.json +1 -1
  23. package/runtime/knowledge/hfs/canon-pins.yaml +43 -10
  24. package/runtime/knowledge/hfs/fe-stack.yaml +3 -3
  25. package/runtime/knowledge/hfs/rules.yaml +13 -9
  26. package/runtime/knowledge/hfs/slots.yaml +105 -12
  27. package/runtime/modules/kernel/failure-codes.yaml +5 -4
  28. package/runtime/scripts/hfs/architecture/config.d.mts +4 -0
  29. package/runtime/scripts/hfs/architecture/config.mjs +25 -1
  30. package/runtime/scripts/hfs/architecture/module-per-transport.d.mts +1 -1
  31. package/runtime/scripts/hfs/architecture/module-per-transport.mjs +6 -1
  32. package/runtime/scripts/hfs/architecture/root-packages.d.mts +26 -0
  33. package/runtime/scripts/hfs/architecture/root-packages.mjs +78 -0
  34. package/runtime/scripts/hfs/architecture/type-context.d.mts +4 -1
  35. package/runtime/scripts/hfs/architecture/type-context.mjs +30 -0
  36. package/runtime/scripts/hfs/architecture/typescript.d.mts +7 -1
  37. package/runtime/scripts/hfs/architecture/typescript.mjs +21 -1
  38. package/runtime/scripts/hfs/explicit-surface-rule.mjs +1 -1
  39. package/runtime/scripts/hfs/rules/database-access.mjs +39 -1
  40. package/runtime/scripts/hfs/rules/monorepo.d.mts +4 -0
  41. package/runtime/scripts/hfs/rules/monorepo.mjs +10 -5
  42. package/runtime/scripts/hfs/rules/secrets.mjs +11 -0
  43. package/runtime/scripts/hfs/secret-errors.d.mts +3 -0
  44. package/runtime/scripts/hfs/secret-errors.mjs +8 -0
  45. package/runtime/scripts/hfs/secret-init.d.mts +6 -0
  46. package/runtime/scripts/hfs/secret-init.mjs +23 -0
  47. package/runtime/scripts/hfs/secret-sops.mjs +9 -1
  48. package/runtime/scripts/hfs/secret-standard.d.mts +20 -0
  49. package/runtime/scripts/hfs/secret-standard.mjs +106 -0
  50. package/runtime/scripts/hfs/secret.mjs +5 -1
  51. package/runtime/scripts/hfs/view.d.mts +23 -0
  52. package/runtime/scripts/hfs/view.mjs +68 -0
  53. package/runtime/scripts/lib/declaration-surface.d.mts +4 -0
  54. package/runtime/scripts/lib/declaration-surface.mjs +55 -1
  55. package/runtime/scripts/lib/secret-records.d.mts +13 -0
  56. package/runtime/scripts/lib/secret-records.mjs +83 -0
  57. package/scaffold/add-inbox-lite.mjs +2 -2
  58. package/scaffold/add-queue-lite.mjs +1 -3
  59. package/scaffold/app.d.mts +2 -2
  60. package/scaffold/app.mjs +10 -12
  61. package/scaffold/lite-exports.mjs +1 -15
  62. package/scripts/sync-bundles.d.mts +8 -0
  63. package/stack/images/openclaw-runtime/Dockerfile +18 -0
  64. package/stack/images/openclaw-runtime/entrypoint.sh +23 -0
  65. package/stack/images/openclaw-runtime/openclaw-init.mjs +101 -0
  66. package/stack/images/openclaw-runtime/openclaw-relay.mjs +25 -0
  67. package/stack/local-up.mjs +3 -0
  68. package/stack/runtime-layers.d.mts +21 -0
  69. package/stack/runtime-layers.mjs +67 -0
  70. package/sync/hygiene.mjs +3 -1
  71. package/sync/index.d.mts +2 -0
  72. package/sync/index.mjs +33 -2
  73. package/templates/app/auth-doors.sql.partial +115 -0
  74. package/templates/app/ci-workflows/github/workflows/ci.yml +1 -1
  75. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +1 -1
  76. package/templates/app/package-scripts/core.json +1 -1
  77. package/templates/app/package-scripts/package.json +1 -1
  78. package/templates/app/package-scripts-lite/package.json +1 -1
  79. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +9 -0
  80. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +3 -1
  81. package/templates/app/skeleton-lite/.starcistacks/dev/infra/compose/compose.yaml +19 -1
  82. package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +3 -0
  83. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +5 -0
  84. package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +4 -0
  85. package/templates/app/skeleton-lite/db/migrations/__timestamp___baseline.sql +24 -4
  86. package/templates/be/auth-lite/src/features/api/auth/application/auth.contracts.ts +33 -0
  87. package/templates/be/auth-lite/src/features/api/auth/application/confirm.command.ts +11 -0
  88. package/templates/be/auth-lite/src/features/api/auth/application/confirm.handler.ts +22 -0
  89. package/templates/be/auth-lite/src/features/api/auth/application/forgot.command.ts +11 -0
  90. package/templates/be/auth-lite/src/features/api/auth/application/forgot.handler.ts +22 -0
  91. package/templates/be/auth-lite/src/features/api/auth/application/resend.command.ts +11 -0
  92. package/templates/be/auth-lite/src/features/api/auth/application/resend.handler.ts +22 -0
  93. package/templates/be/auth-lite/src/features/api/auth/application/reset.command.ts +11 -0
  94. package/templates/be/auth-lite/src/features/api/auth/application/reset.handler.ts +22 -0
  95. package/templates/be/auth-lite/src/features/api/auth/application/signup.command.ts +11 -0
  96. package/templates/be/auth-lite/src/features/api/auth/application/signup.handler.ts +22 -0
  97. package/templates/be/auth-lite/src/features/api/auth/auth.module-definition.ts +3 -10
  98. package/templates/be/auth-lite/src/features/api/auth/auth.module.ts +6 -1
  99. package/templates/be/auth-lite/src/features/api/auth/transport/http/auth-http.module-definition.ts +3 -10
  100. package/templates/be/auth-lite/src/features/api/auth/transport/http/auth.controller.ts +56 -1
  101. package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/forgot.request.ts +16 -0
  102. package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/resend.request.ts +16 -0
  103. package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/reset.request.ts +18 -0
  104. package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/signup.request.ts +22 -0
  105. package/templates/be/auth-lite/src/features/api/auth/transport/http/dto/token.request.ts +11 -0
  106. package/templates/be/auth-lite/src/modules/domain/identity/account-directory.service.spec.ts +30 -30
  107. package/templates/be/auth-lite/src/modules/domain/identity/account-directory.service.ts +7 -16
  108. package/templates/be/auth-lite/src/modules/domain/identity/authenticator.service.spec.ts +113 -49
  109. package/templates/be/auth-lite/src/modules/domain/identity/authenticator.service.ts +42 -53
  110. package/templates/be/auth-lite/src/modules/domain/identity/identity-email.log-events.ts +6 -0
  111. package/templates/be/auth-lite/src/modules/domain/identity/identity-email.service.spec.ts +233 -0
  112. package/templates/be/auth-lite/src/modules/domain/identity/identity-email.service.ts +176 -0
  113. package/templates/be/auth-lite/src/modules/domain/identity/identity-sign-in.log-events.ts +6 -0
  114. package/templates/be/auth-lite/src/modules/domain/identity/persistence/account-doors.port.ts +98 -0
  115. package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/identity-email-token.entity.ts +34 -0
  116. package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/index.ts +3 -10
  117. package/templates/be/auth-lite/src/modules/domain/identity/sign-in.service.spec.ts +17 -0
  118. package/templates/be/auth-lite/src/modules/domain/identity/sign-in.service.ts +6 -0
  119. package/templates/be/auth-lite/src/tests/fixtures/builders/identity.builder.ts +29 -33
  120. package/templates/be/inbox/module-definition.ts.tpl +2 -9
  121. package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +2 -11
  122. package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +2 -9
  123. package/templates/be/patterns/api/feature.module-definition.ts.tpl +3 -9
  124. package/templates/be/patterns/api/graphql.module-definition.ts.tpl +3 -9
  125. package/templates/be/patterns/cli/group.module-definition.ts.tpl +2 -9
  126. package/templates/be/patterns/event-bus/platform/event-bus.module-definition.ts.tpl +3 -10
  127. package/templates/be/patterns/idempotency/platform/inbox/inbox.module-definition.ts.tpl +2 -9
  128. package/templates/be/patterns/jobs/job.module-definition.ts.tpl +2 -9
  129. package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +3 -9
  130. package/templates/be/patterns/jobs/platform/jobs.module-definition.ts.tpl +3 -10
  131. package/templates/be/patterns/projections/projection.module-definition.ts.tpl +2 -9
  132. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +3 -10
  133. package/templates/be/patterns/queues/queue.module-definition.ts.tpl +2 -9
  134. package/templates/be/patterns/reactors/message.module-definition.ts.tpl +3 -9
  135. package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +2 -9
  136. package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +3 -9
  137. package/templates/be/patterns/realtime/channel.sse.module-definition.ts.tpl +3 -9
  138. package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +3 -9
  139. package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +3 -9
  140. package/templates/be/patterns/saga/saga.module-definition.ts.tpl +2 -9
  141. package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +3 -9
  142. package/templates/be/platform/graphql/graphql.module-definition.ts +2 -9
  143. package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +3 -9
  144. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +3 -9
  145. package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +2 -9
  146. package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +3 -9
  147. package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +2 -9
  148. package/templates/be/skeleton/src/modules/domain/identity/identity.module-definition.ts +2 -9
  149. package/templates/be/skeleton/src/modules/domain/liveness/liveness.module-definition.ts +2 -9
  150. package/templates/be/skeleton/src/modules/domain/note/note.module-definition.ts +2 -9
  151. package/templates/be/skeleton/src/modules/platform/clock/clock.module-definition.ts +2 -9
  152. package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.contracts.ts +2 -0
  153. package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.module-definition.ts +2 -9
  154. package/templates/be/skeleton/src/modules/platform/database/database.module-definition.ts +3 -13
  155. package/templates/be/skeleton/src/modules/platform/errors/errors.module-definition.ts +4 -11
  156. package/templates/be/skeleton/src/modules/platform/http/http.module-definition.ts +4 -9
  157. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module-definition.ts +5 -11
  158. package/templates/be/skeleton/src/modules/platform/i18n/i18n.module-definition.ts +4 -11
  159. package/templates/be/skeleton/src/modules/platform/ids/ids.module-definition.ts +2 -9
  160. package/templates/be/skeleton/src/modules/platform/logging/logging.module-definition.ts +2 -9
  161. package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +2 -9
  162. package/templates/be/skeleton-lite/apps/api/src/api.env.ts +4 -0
  163. package/templates/be/skeleton-lite/apps/api/src/api.options.ts +3 -0
  164. package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +3 -1
  165. package/templates/be/skeleton-lite/src/modules/domain/identity/errors/identity.error.ts +6 -0
  166. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +3 -0
  167. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +1 -0
  168. package/templates/be/skeleton-lite/src/modules/domain/identity/messages/identity-mail.messages.ts +65 -0
  169. package/templates/be/skeleton-lite/src/modules/domain/identity/messages/identity.messages.ts +4 -0
  170. package/templates/be/skeleton-lite/src/modules/integrations/mail/index.ts +6 -0
  171. package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.config.ts +33 -0
  172. package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.decorators.ts +14 -0
  173. package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.module-definition.ts +12 -0
  174. package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.module.ts +27 -0
  175. package/templates/be/skeleton-lite/src/modules/integrations/mail/mail.options.ts +22 -0
  176. package/templates/be/skeleton-lite/src/modules/integrations/object-storage/object-storage.module-definition.ts +2 -9
  177. package/templates/be/skeleton-lite/src/modules/integrations/passport/index.ts +1 -1
  178. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +1 -0
  179. package/templates/be/skeleton-lite/src/modules/platform/http-security/rate-limit.guard.spec.ts +11 -0
  180. package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +11 -0
  181. package/templates/be/table/api/feature.module-definition.ts.tpl +3 -9
  182. package/templates/be/table/api/graphql.module-definition.ts.tpl +3 -9
  183. package/templates/be/table/module-definition.ts.tpl +2 -9
  184. package/templates/fe/auth-lite/apps/web/src/modules/auth/email-doors.ts +16 -0
  185. package/templates/fe/auth-lite/apps/web/src/modules/auth/index.ts +5 -0
  186. package/templates/fe/skeleton/packages/__project__-i18n/src/index.ts +30 -67
  187. package/templates/fe/skeleton/packages/__project__-i18n/src/proxy.ts +6 -21
  188. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +10 -16
  189. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/confirm/page.tsx +9 -0
  190. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/forgot/page.tsx +9 -0
  191. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/resend/page.tsx +9 -0
  192. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/reset/page.tsx +9 -0
  193. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/auth/signup/page.tsx +9 -0
  194. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/layout.tsx +5 -9
  195. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/EmailDoorForm/component.tsx +51 -0
  196. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/EmailDoorForm/index.tsx +84 -0
  197. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppConfirmPage/index.tsx +25 -0
  198. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppForgotPage/index.tsx +21 -0
  199. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx +11 -3
  200. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +4 -1
  201. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppResendPage/index.tsx +21 -0
  202. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppResetPage/index.tsx +25 -0
  203. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppSignupPage/index.tsx +21 -0
  204. package/templates/fe/skeleton-lite/apps/web/src/hooks/emailAuth/emailAuth.shared.ts +12 -0
  205. package/templates/fe/skeleton-lite/apps/web/src/hooks/emailAuth/index.ts +2 -0
  206. package/templates/fe/skeleton-lite/apps/web/src/hooks/emailAuth/useEmailDoor.ts +32 -0
  207. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/index.ts +2 -2
  208. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +50 -1
  209. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +50 -1
  210. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/request.ts +7 -30
  211. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +13 -14
  212. package/templates/fe/skeleton-lite/apps/web/src/modules/routes/index.ts +5 -0
  213. package/templates/fe/skeleton-lite/apps/web/src/proxy.ts +4 -17
  214. package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/auth-identity.entity.ts +0 -38
  215. package/templates/be/auth-lite/src/modules/domain/identity/persistence/entities/auth-user.entity.ts +0 -54
@@ -0,0 +1,98 @@
1
+ // Managed by starci app sync (slot be.identity.sign-in); do not edit: run "npx starci app sync --execute".
2
+ import type { EntityManager } from "typeorm"
3
+ import { callDbFunction, returnedRows, rowShape } from "@modules/platform/database"
4
+
5
+ /** The account an address stands for, with the stored hash the password is checked against. */
6
+ export interface AccountByEmail {
7
+ /** The account id. */
8
+ readonly id: string
9
+ /** The sign-in address. */
10
+ readonly email: string
11
+ /** The stored bcrypt hash, or null for an account that signs in with Google only. */
12
+ readonly encrypted_password: string | null
13
+ /** When the mailbox was confirmed, or null. */
14
+ readonly email_confirmed_at: Date | null
15
+ /** True when the account is deleted or banned at the database's now(). */
16
+ readonly disabled: boolean
17
+ }
18
+
19
+ /** The standing of an account found by id. */
20
+ export interface AccountById {
21
+ /** The account id. */
22
+ readonly id: string
23
+ /** The sign-in address, or null. */
24
+ readonly email: string | null
25
+ /** True when the account is deleted or banned at the database's now(). */
26
+ readonly disabled: boolean
27
+ }
28
+
29
+ /** An account to create: the id, the address, the profile keys as JSON text and the instant. */
30
+ export interface NewAccount {
31
+ /** The account id. */
32
+ readonly id: string
33
+ /** The sign-in address, lower-cased. */
34
+ readonly email: string
35
+ /** The bcrypt hash, or null for an account that signs in with Google only. */
36
+ readonly hash: string | null
37
+ /** Whether the mailbox counts as confirmed. */
38
+ readonly confirmed: boolean
39
+ /** The profile keys as JSON text. */
40
+ readonly meta: string
41
+ /** The instant of creation. */
42
+ readonly now: Date
43
+ }
44
+
45
+ const isAccountByEmail: (value: unknown) => value is AccountByEmail = rowShape({
46
+ id: "string",
47
+ email: "string",
48
+ encrypted_password: "string?",
49
+ email_confirmed_at: "date?",
50
+ disabled: "boolean",
51
+ })
52
+ const isAccountById: (value: unknown) => value is AccountById = rowShape({ id: "string", email: "string?", disabled: "boolean" })
53
+ const isLinkedAccount = rowShape({ be_auth_user_by_google: "string?" })
54
+ const isCreatedAccount = rowShape({ be_auth_create_user: "string" })
55
+
56
+ /**
57
+ * The account doors: the SECURITY DEFINER functions of the baseline migration through which the application role reads and writes
58
+ * auth.users and auth.identities. It holds no grant on schema auth, so no other path reaches an account.
59
+ */
60
+ export const accountDoors = {
61
+ /** The account of an exact address, or undefined. */
62
+ async userByEmail(manager: EntityManager, email: string): Promise<AccountByEmail | undefined> {
63
+ const [row] = returnedRows(await callDbFunction(manager, "public.be_auth_user_by_email", [email]), isAccountByEmail)
64
+ return row
65
+ },
66
+ /** The standing of an account by id, or undefined. */
67
+ async userById(manager: EntityManager, userId: string): Promise<AccountById | undefined> {
68
+ const [row] = returnedRows(await callDbFunction(manager, "public.be_auth_user_by_id", [userId]), isAccountById)
69
+ return row
70
+ },
71
+ /** The account a Google subject is linked to, or null. */
72
+ async userByGoogle(manager: EntityManager, subject: string): Promise<string | null> {
73
+ const [row] = returnedRows(await callDbFunction(manager, "public.be_auth_user_by_google", [subject]), isLinkedAccount)
74
+ return row?.be_auth_user_by_google ?? null
75
+ },
76
+ /** Creates an account and answers its id. */
77
+ async createUser(manager: EntityManager, account: NewAccount): Promise<string | undefined> {
78
+ const args = [account.id, account.email, account.hash, account.confirmed, account.meta, account.now]
79
+ const [row] = returnedRows(await callDbFunction(manager, "public.be_auth_create_user", args), isCreatedAccount)
80
+ return row?.be_auth_create_user
81
+ },
82
+ /** Links a Google subject to an account, or refreshes the link. */
83
+ async linkGoogle(manager: EntityManager, userId: string, subject: string, data: string, now: Date): Promise<void> {
84
+ await callDbFunction(manager, "public.be_auth_link_google", [userId, subject, data, now])
85
+ },
86
+ /** Stamps the confirmation of a mailbox (a spent confirmation link) without recording a sign-in. */
87
+ async confirmUser(manager: EntityManager, userId: string, now: Date): Promise<void> {
88
+ await callDbFunction(manager, "public.be_auth_confirm_user", [userId, now])
89
+ },
90
+ /** Sets the password hash of an account; `confirm` also confirms the mailbox, as a spent reset link proves it. */
91
+ async setPassword(manager: EntityManager, userId: string, hash: string, confirm: boolean, now: Date): Promise<void> {
92
+ await callDbFunction(manager, "public.be_auth_set_password", [userId, hash, confirm, now])
93
+ },
94
+ /** Records a sign-in, confirms the mailbox when asked, and fills the profile keys the person has not set. */
95
+ async touchUser(manager: EntityManager, userId: string, now: Date, confirm: boolean, meta: string): Promise<void> {
96
+ await callDbFunction(manager, "public.be_auth_touch_user", [userId, now, confirm, meta])
97
+ },
98
+ }
@@ -0,0 +1,34 @@
1
+ // Managed by starci app sync (slot be.identity.sign-in); do not edit: run "npx starci app sync --execute".
2
+ import { Column, Entity, PrimaryColumn } from "typeorm"
3
+
4
+ @Entity({ schema: "public", name: "identity_email_tokens" })
5
+ /** One single-use link token that confirms a mailbox or resets a password, mapped from public.identity_email_tokens; only its digest is kept. */
6
+ export class IdentityEmailTokenEntity {
7
+ /** The token row id. */
8
+ @PrimaryColumn({ name: "id", type: "uuid" })
9
+ id!: string
10
+
11
+ /** The account the link is for. */
12
+ @Column({ name: "user_id", type: "uuid" })
13
+ userId!: string
14
+
15
+ /** What the link does: `confirm` or `reset`. */
16
+ @Column({ name: "purpose", type: "varchar", length: 16 })
17
+ purpose!: string
18
+
19
+ /** The SHA-256 digest of the token in the link; the token itself is never stored. */
20
+ @Column({ name: "token_hash", type: "varchar", length: 64 })
21
+ tokenHash!: string
22
+
23
+ /** When the link stops working. */
24
+ @Column({ name: "expires_at", type: "timestamptz" })
25
+ expiresAt!: Date
26
+
27
+ /** When the link was spent, or null while it is live. */
28
+ @Column({ name: "used_at", type: "timestamptz", nullable: true })
29
+ usedAt!: Date | null
30
+
31
+ /** When the link was issued. */
32
+ @Column({ name: "created_at", type: "timestamptz" })
33
+ createdAt!: Date
34
+ }
@@ -1,17 +1,10 @@
1
1
  // Managed by starci app sync (slot be.identity.sign-in); do not edit: run "npx starci app sync --execute".
2
- import { AuthIdentityEntity } from "./auth-identity.entity"
3
- import { AuthUserEntity } from "./auth-user.entity"
4
2
  import { IdentityAttemptEntity } from "./identity-attempt.entity"
3
+ import { IdentityEmailTokenEntity } from "./identity-email-token.entity"
5
4
  import { IdentityRefreshTokenEntity } from "./identity-refresh-token.entity"
6
5
  import { IdentitySessionEntity } from "./identity-session.entity"
7
6
 
8
- export { AuthIdentityEntity, AuthUserEntity, IdentityAttemptEntity, IdentityRefreshTokenEntity, IdentitySessionEntity }
7
+ export { IdentityAttemptEntity, IdentityEmailTokenEntity, IdentityRefreshTokenEntity, IdentitySessionEntity }
9
8
 
10
9
  /** The entities of the identity capability, named in PRIMARY_ENTITIES of platform/database/entities.ts. */
11
- export const identityEntities: ReadonlyArray<new () => object> = [
12
- AuthIdentityEntity,
13
- AuthUserEntity,
14
- IdentityAttemptEntity,
15
- IdentityRefreshTokenEntity,
16
- IdentitySessionEntity,
17
- ]
10
+ export const identityEntities: ReadonlyArray<new () => object> = [IdentityAttemptEntity, IdentityEmailTokenEntity, IdentityRefreshTokenEntity, IdentitySessionEntity]
@@ -48,6 +48,23 @@ describe("IdentitySignInService", () => {
48
48
  expect(await subject.jwks()).toEqual({ keys: [] })
49
49
  })
50
50
 
51
+ it("signs the caller out of every other device, keeping the session of the token", async () => {
52
+ const { subject, sessions } = await build()
53
+ sessions.endOthers.mockResolvedValue()
54
+
55
+ await subject.endOthers({ id: "u-1", role: "authenticated", sessionId: "s-1" })
56
+
57
+ expect(sessions.endOthers).toHaveBeenCalledWith("u-1", "s-1")
58
+ })
59
+
60
+ it("refuses to sign out the other devices of a token that names no session", async () => {
61
+ const { subject, sessions } = await build()
62
+ sessions.endOthers.mockRejectedValue(new AuthError("IDENTITY_UNAUTHENTICATED"))
63
+
64
+ await expect(subject.endOthers({ id: "u-1", role: "authenticated" })).rejects.toMatchObject({ code: IdentityErrorCode.Unauthenticated })
65
+ expect(sessions.endOthers).toHaveBeenCalledWith("u-1", undefined)
66
+ })
67
+
51
68
  it("turns a refusal of the package into the error family that owns its code", async () => {
52
69
  const { subject, doors } = await build()
53
70
  doors.refresh.mockRejectedValue(new AuthError("IDENTITY_REFRESH_REUSED"))
@@ -1,6 +1,7 @@
1
1
  // Managed by starci app sync (slot be.identity.sign-in); do not edit: run "npx starci app sync --execute".
2
2
  import { Injectable } from "@nestjs/common"
3
3
  import { AuthError, PassportError, PassportErrorCode } from "@modules/integrations/passport"
4
+ import type { Principal } from "@modules/platform/cqrs"
4
5
  import { IdentityError, IdentityErrorCode } from "./errors/identity.error"
5
6
  import { InjectAuthDoors, InjectAuthSessions } from "./identity.decorators"
6
7
  import type { AccessGrant, AuthDoors, AuthSessions, GoogleRedirect, HttpExchange, JwksDocument } from "@modules/integrations/passport"
@@ -71,6 +72,11 @@ export class IdentitySignInService {
71
72
  return this.refusing(() => this.doors.completeGoogle(exchange))
72
73
  }
73
74
 
75
+ /** Signs the person out of every other device; the session of the caller stays. */
76
+ endOthers(principal: Principal): Promise<void> {
77
+ return this.refusing(() => this.sessions.endOthers(principal.id, principal.sessionId))
78
+ }
79
+
74
80
  /** The public key document access tokens verify against. */
75
81
  jwks(): Promise<JwksDocument> {
76
82
  return this.refusing(() => this.sessions.jwks())
@@ -1,44 +1,40 @@
1
1
  // Managed by starci app sync (slot be.identity.sign-in); do not edit: run "npx starci app sync --execute".
2
2
  const BEFORE = new Date("2026-02-03T04:00:00.000Z")
3
- const AFTER = new Date("2026-02-03T05:00:00.000Z")
4
3
 
5
- /** The kinds of account a sign-in spec needs. */
6
- export type AuthUserVariant = "live" | "banned" | "ban-ended" | "deleted" | "unconfirmed" | "addressless" | "passwordless" | "created"
4
+ /** The kinds of account the sign-in reads by address. */
5
+ export type AccountByEmailVariant = "live" | "disabled" | "unconfirmed" | "passwordless" | "invited"
7
6
 
8
- /** A row of auth.users as the sign-in reads it (the shape of AuthUserEntity). */
9
- export interface AuthUserRow {
7
+ /** The kinds of account the sign-in reads by id. */
8
+ export type AccountByIdVariant = "live" | "disabled" | "addressless"
9
+
10
+ /** A row of the by-address door: `disabled` is what the database decided at its own now(). */
11
+ export interface AccountByEmailRow {
10
12
  id: string
11
- aud: string | null
12
- role: string | null
13
- email: string | null
14
- encryptedPassword: string | null
15
- emailConfirmedAt: Date | null
16
- lastSignInAt: Date | null
17
- bannedUntil: Date | null
18
- deletedAt: Date | null
19
- isAnonymous: boolean
20
- createdAt: Date | null
21
- updatedAt: Date | null
13
+ email: string
14
+ encrypted_password: string | null
15
+ email_confirmed_at: Date | null
16
+ disabled: boolean
22
17
  }
23
18
 
24
- /** Until when an account of this variant is banned, or null. */
25
- const bannedUntilOf = (variant: AuthUserVariant): Date | null => {
26
- if (variant === "banned") return AFTER
27
- return variant === "ban-ended" ? BEFORE : null
19
+ /** A row of the by-id door. */
20
+ export interface AccountByIdRow {
21
+ id: string
22
+ email: string | null
23
+ disabled: boolean
28
24
  }
29
25
 
30
- /** A confirmed, live password account of the given variant; \`created\` is the account the first Google sign-in makes (the first id the fake ids hand out). */
31
- export const authUserRow = (variant: AuthUserVariant = "live"): AuthUserRow => ({
32
- id: variant === "created" ? "00000000-0000-4000-8000-000000000001" : "u-1",
33
- aud: "authenticated",
34
- role: "authenticated",
26
+ /** The row the by-address door answers for a confirmed password account of the given variant. */
27
+ export const accountByEmailRow = (variant: AccountByEmailVariant = "live"): AccountByEmailRow => ({
28
+ id: "u-1",
29
+ email: "a@example.test",
30
+ encrypted_password: variant === "passwordless" || variant === "invited" ? null : "hash",
31
+ email_confirmed_at: variant === "unconfirmed" || variant === "invited" ? null : BEFORE,
32
+ disabled: variant === "disabled",
33
+ })
34
+
35
+ /** The row the by-id door answers for the account of the given variant; `id` is the account the spec stands for. */
36
+ export const accountByIdRow = (variant: AccountByIdVariant = "live", id = "u-1"): AccountByIdRow => ({
37
+ id,
35
38
  email: variant === "addressless" ? null : "a@example.test",
36
- encryptedPassword: variant === "passwordless" || variant === "created" ? null : "hash",
37
- emailConfirmedAt: variant === "unconfirmed" ? null : BEFORE,
38
- lastSignInAt: null,
39
- bannedUntil: bannedUntilOf(variant),
40
- deletedAt: variant === "deleted" ? BEFORE : null,
41
- isAnonymous: false,
42
- createdAt: BEFORE,
43
- updatedAt: BEFORE,
39
+ disabled: variant === "disabled",
44
40
  })
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import type { @@Provider@@InboxOptions } from "./@@provider@@-inbox.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Provider@@InboxOptions>()
5
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
6
- .build()
7
- type Host = ConfigurableModuleHost<@@Provider@@InboxOptions, "register", "create", { isGlobal: boolean }>
8
-
9
4
  /** The configurable-module class the module extends. */
10
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = defineCapabilityModule<@@Provider@@InboxOptions>()
@@ -1,14 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import type { EventBusOptions } from "./event-bus.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<EventBusOptions>()
5
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
6
- .build()
7
- type Host = ConfigurableModuleHost<EventBusOptions, "register", "create", { isGlobal: boolean }>
8
-
9
4
  /** The configurable-module class the module extends. */
10
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
11
- /** The injection token of the registered options. */
12
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
13
- /** The options of a synchronous registration, for the register signature. */
14
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } = defineCapabilityModule<EventBusOptions>()
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import type { InboxOptions } from "./inbox.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<InboxOptions>()
5
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
6
- .build()
7
- type Host = ConfigurableModuleHost<InboxOptions, "register", "create", { isGlobal: boolean }>
8
-
9
4
  /** The configurable-module class the module extends. */
10
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = defineCapabilityModule<InboxOptions>()
@@ -1,12 +1,6 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Feature@@ApiOptions } from "./@@feature@@.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Feature@@ApiOptions>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Feature@@ApiOptions, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@feature@@ module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ defineConfigurableModule<@@Feature@@ApiOptions>()
@@ -1,12 +1,6 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Feature@@GraphqlOptions } from "./@@feature@@-graphql.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Feature@@GraphqlOptions>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Feature@@GraphqlOptions, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@feature@@-graphql module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ defineConfigurableModule<@@Feature@@GraphqlOptions>()
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Group@@Options } from "./@@group@@.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Group@@Options>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Group@@Options, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@group@@ module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } = defineConfigurableModule<@@Group@@Options>()
@@ -1,15 +1,8 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import { EVENT_BUS_OPTIONS } from "./event-bus.decorators"
3
3
  import type { EventBusOptions } from "./event-bus.options"
4
4
 
5
- const built = new ConfigurableModuleBuilder<EventBusOptions>({
5
+ /** The configurable-module base of the event bus; `isGlobal` is decided by the app root. */
6
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = defineCapabilityModule<EventBusOptions>({
6
7
  optionsInjectionToken: EVENT_BUS_OPTIONS,
7
8
  })
8
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
9
- .build()
10
- type Host = ConfigurableModuleHost<EventBusOptions, "register", "create", { isGlobal: boolean }>
11
-
12
- /** The configurable-module base of the event bus; `isGlobal` is decided by the app root. */
13
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
14
- /** The options of a synchronous registration, for the register signature. */
15
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import type { InboxOptions } from "./inbox.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<InboxOptions>()
5
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
6
- .build()
7
- type Host = ConfigurableModuleHost<InboxOptions, "register", "create", { isGlobal: boolean }>
8
-
9
4
  /** The configurable-module base of the inbox capability; `isGlobal` is decided by the app root. */
10
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = defineCapabilityModule<InboxOptions>()
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Job@@Options } from "./@@job@@.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Job@@Options>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Job@@Options, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@job@@ module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } = defineConfigurableModule<@@Job@@Options>()
@@ -1,12 +1,6 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Job@@QueueOptions } from "./@@job@@-queue.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Job@@QueueOptions>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Job@@QueueOptions, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@job@@-queue module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ defineConfigurableModule<@@Job@@QueueOptions>()
@@ -1,15 +1,8 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import { JOBS_OPTIONS } from "./jobs.decorators"
3
3
  import type { JobsOptions } from "./jobs.options"
4
4
 
5
- const built = new ConfigurableModuleBuilder<JobsOptions>({
5
+ /** The configurable-module base of the jobs; `isGlobal` is decided by the app root. */
6
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = defineCapabilityModule<JobsOptions>({
6
7
  optionsInjectionToken: JOBS_OPTIONS,
7
8
  })
8
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
9
- .build()
10
- type Host = ConfigurableModuleHost<JobsOptions, "register", "create", { isGlobal: boolean }>
11
-
12
- /** The configurable-module base of the jobs; `isGlobal` is decided by the app root. */
13
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
14
- /** The options of a synchronous registration, for the register signature. */
15
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import type { @@Name@@Options } from "./@@name@@.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Name@@Options>()
5
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
6
- .build()
7
- type Host = ConfigurableModuleHost<@@Name@@Options, "register", "create", { isGlobal: boolean }>
8
-
9
4
  /** The configurable-module base of the @@name@@ projection; `isGlobal` is decided by the app root. */
10
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = defineCapabilityModule<@@Name@@Options>()
@@ -1,15 +1,8 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineCapabilityModule } from "@starci/nest-kit"
2
2
  import { QUEUE_OPTIONS } from "./queue.decorators"
3
3
  import type { QueueRegistrationOptions } from "./queue.options"
4
4
 
5
- const built = new ConfigurableModuleBuilder<QueueRegistrationOptions>({
5
+ /** The configurable-module base of the queues; `isGlobal` is decided by the app root. */
6
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = defineCapabilityModule<QueueRegistrationOptions>({
6
7
  optionsInjectionToken: QUEUE_OPTIONS,
7
8
  })
8
- .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
9
- .build()
10
- type Host = ConfigurableModuleHost<QueueRegistrationOptions, "register", "create", { isGlobal: boolean }>
11
-
12
- /** The configurable-module base of the queues; `isGlobal` is decided by the app root. */
13
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
14
- /** The options of a synchronous registration, for the register signature. */
15
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Queue@@Options } from "./@@queue@@.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Queue@@Options>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Queue@@Options, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@queue@@ module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } = defineConfigurableModule<@@Queue@@Options>()
@@ -1,12 +1,6 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Reactor@@MessageOptions } from "./@@reactor@@-message.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Reactor@@MessageOptions>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Reactor@@MessageOptions, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@reactor@@-message module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ defineConfigurableModule<@@Reactor@@MessageOptions>()
@@ -1,12 +1,5 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Reactor@@Options } from "./@@reactor@@.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Reactor@@Options>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Reactor@@Options, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@reactor@@ module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } = defineConfigurableModule<@@Reactor@@Options>()
@@ -1,12 +1,6 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Channel@@GraphqlOptions } from "./@@channel@@-graphql.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Channel@@GraphqlOptions>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Channel@@GraphqlOptions, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@channel@@-graphql module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ defineConfigurableModule<@@Channel@@GraphqlOptions>()
@@ -1,12 +1,6 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Channel@@SseOptions } from "./@@channel@@-sse.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Channel@@SseOptions>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Channel@@SseOptions, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@channel@@-sse module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ defineConfigurableModule<@@Channel@@SseOptions>()
@@ -1,12 +1,6 @@
1
- import { ConfigurableModuleBuilder, type ConfigurableModuleHost } from "@nestjs/common"
1
+ import { defineConfigurableModule } from "@starci/nest-kit"
2
2
  import type { @@Channel@@WebsocketOptions } from "./@@channel@@-websocket.options"
3
3
 
4
- const built = new ConfigurableModuleBuilder<@@Channel@@WebsocketOptions>().setClassMethodName("register").build()
5
- type Host = ConfigurableModuleHost<@@Channel@@WebsocketOptions, "register", "create", {}>
6
-
7
4
  /** The configurable-module base of the @@channel@@-websocket module. */
8
- export const ConfigurableModuleClass: Host["ConfigurableModuleClass"] = built.ConfigurableModuleClass
9
- /** The injection token of the registered options. */
10
- export const MODULE_OPTIONS_TOKEN: Host["MODULE_OPTIONS_TOKEN"] = built.MODULE_OPTIONS_TOKEN
11
- /** The options of a synchronous registration, for the register signature. */
12
- export const OPTIONS_TYPE: Host["OPTIONS_TYPE"] = built.OPTIONS_TYPE
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ defineConfigurableModule<@@Channel@@WebsocketOptions>()