@openlup/platform 0.28.0 → 0.30.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 (241) hide show
  1. package/CHANGELOG.md +369 -156
  2. package/README.md +220 -4
  3. package/dist/composition/index.d.ts +1 -0
  4. package/dist/composition/index.js +1 -0
  5. package/dist/composition/marketingContribution.d.ts +21 -0
  6. package/dist/composition/marketingContribution.js +29 -0
  7. package/dist/composition/nodeHost.d.ts +1 -1
  8. package/dist/composition/nodeHost.js +3 -2
  9. package/dist/lifecycle/appUpgrade.d.ts +52 -0
  10. package/dist/lifecycle/appUpgrade.js +180 -0
  11. package/dist/lifecycle/index.d.ts +2 -0
  12. package/dist/lifecycle/index.js +2 -0
  13. package/dist/lifecycle/postgresInstallQualification.d.ts +51 -0
  14. package/dist/lifecycle/postgresInstallQualification.js +74 -0
  15. package/dist/marketing/acquisitionCaseSchemas.d.ts +103 -0
  16. package/dist/marketing/acquisitionCaseSchemas.js +53 -0
  17. package/dist/marketing/acquisitionEvidenceSchemas.d.ts +105 -0
  18. package/dist/marketing/acquisitionEvidenceSchemas.js +55 -0
  19. package/dist/marketing/analytics/dataLayer.d.ts +18 -0
  20. package/dist/marketing/analytics/dataLayer.js +111 -0
  21. package/dist/marketing/analytics/noop.d.ts +9 -0
  22. package/dist/marketing/analytics/noop.js +8 -0
  23. package/dist/marketing/analytics/purchaseFacts.d.ts +4 -0
  24. package/dist/marketing/analytics/purchaseFacts.js +69 -0
  25. package/dist/marketing/analytics/routePolicy.d.ts +10 -0
  26. package/dist/marketing/analytics/routePolicy.js +59 -0
  27. package/dist/marketing/consentEvidence.d.ts +8 -0
  28. package/dist/marketing/consentEvidence.js +32 -0
  29. package/dist/marketing/contactLegal.d.ts +14 -0
  30. package/dist/marketing/contactLegal.js +19 -0
  31. package/dist/marketing/contracts/acquisition.d.ts +88 -0
  32. package/dist/marketing/contracts/acquisition.js +1 -0
  33. package/dist/marketing/contracts/acquisitionPorts.d.ts +49 -0
  34. package/dist/marketing/contracts/acquisitionPorts.js +1 -0
  35. package/dist/marketing/contracts/analytics.d.ts +144 -0
  36. package/dist/marketing/contracts/analytics.js +1 -0
  37. package/dist/marketing/contracts/contactLegal.d.ts +53 -0
  38. package/dist/marketing/contracts/contactLegal.js +1 -0
  39. package/dist/marketing/contracts/index.d.ts +6 -0
  40. package/dist/marketing/contracts/index.js +1 -0
  41. package/dist/marketing/contracts/prelaunch.d.ts +39 -0
  42. package/dist/marketing/contracts/prelaunch.js +1 -0
  43. package/dist/marketing/index.d.ts +16 -0
  44. package/dist/marketing/index.js +14 -0
  45. package/dist/marketing/prelaunchAcquisitionSchemas.d.ts +116 -0
  46. package/dist/marketing/prelaunchAcquisitionSchemas.js +51 -0
  47. package/dist/marketing/seo/jsonLd.d.ts +157 -0
  48. package/dist/marketing/seo/jsonLd.js +127 -0
  49. package/dist/marketing/seo/metadata.d.ts +41 -0
  50. package/dist/marketing/seo/metadata.js +36 -0
  51. package/dist/marketing/seo/serializeJsonLd.d.ts +1 -0
  52. package/dist/marketing/seo/serializeJsonLd.js +6 -0
  53. package/dist/marketing/seo/urls.d.ts +14 -0
  54. package/dist/marketing/seo/urls.js +23 -0
  55. package/dist/marketing/server/acquisitionCaseDirect.d.ts +4 -0
  56. package/dist/marketing/server/acquisitionCaseDirect.js +88 -0
  57. package/dist/marketing/server/acquisitionCaseHandlers.d.ts +28 -0
  58. package/dist/marketing/server/acquisitionCaseHandlers.js +40 -0
  59. package/dist/marketing/server/acquisitionCasePorts.d.ts +42 -0
  60. package/dist/marketing/server/acquisitionCasePorts.js +1 -0
  61. package/dist/marketing/server/acquisitionEvidenceDirect.d.ts +5 -0
  62. package/dist/marketing/server/acquisitionEvidenceDirect.js +100 -0
  63. package/dist/marketing/server/analyticsContext.d.ts +3 -0
  64. package/dist/marketing/server/analyticsContext.js +65 -0
  65. package/dist/marketing/server/analyticsContextPorts.d.ts +31 -0
  66. package/dist/marketing/server/analyticsContextPorts.js +1 -0
  67. package/dist/marketing/server/bindings.d.ts +14 -0
  68. package/dist/marketing/server/bindings.js +18 -0
  69. package/dist/marketing/server/directPorts.d.ts +26 -0
  70. package/dist/marketing/server/directPorts.js +1 -0
  71. package/dist/marketing/server/index.d.ts +14 -0
  72. package/dist/marketing/server/index.js +11 -0
  73. package/dist/marketing/server/postgres/acquisitionCaseRoutines.d.ts +10 -0
  74. package/dist/marketing/server/postgres/acquisitionCaseRoutines.js +204 -0
  75. package/dist/marketing/server/postgres/acquisitionEvidenceRoutines.d.ts +10 -0
  76. package/dist/marketing/server/postgres/acquisitionEvidenceRoutines.js +107 -0
  77. package/dist/marketing/server/postgres/index.d.ts +3 -0
  78. package/dist/marketing/server/postgres/index.js +3 -0
  79. package/dist/marketing/server/prelaunchAcquisitionDirect.d.ts +4 -0
  80. package/dist/marketing/server/prelaunchAcquisitionDirect.js +122 -0
  81. package/dist/marketing/server/privacyContributor.d.ts +66 -0
  82. package/dist/marketing/server/privacyContributor.js +87 -0
  83. package/dist/marketing/server/research/adminSurveyResponsesHandler.d.ts +9 -0
  84. package/dist/marketing/server/research/adminSurveyResponsesHandler.js +53 -0
  85. package/dist/marketing/server/research/managedSurveyResponseSubmit.d.ts +39 -0
  86. package/dist/marketing/server/research/managedSurveyResponseSubmit.js +102 -0
  87. package/dist/marketing/server/research/surveyResponseSubmitHandler.d.ts +8 -0
  88. package/dist/marketing/server/research/surveyResponseSubmitHandler.js +41 -0
  89. package/dist/marketing/validation.d.ts +2 -0
  90. package/dist/marketing/validation.js +3 -0
  91. package/dist/migrations/postgresRunner.d.ts +9 -0
  92. package/dist/migrations/postgresRunner.js +17 -10
  93. package/dist/operations/adminAlertsSchemas.d.ts +153 -0
  94. package/dist/operations/adminAlertsSchemas.js +69 -0
  95. package/dist/operations/adminAlertsView.d.ts +73 -0
  96. package/dist/operations/adminAlertsView.js +184 -0
  97. package/dist/operations/alertPagingPolicy.d.ts +15 -0
  98. package/dist/operations/alertPagingPolicy.js +43 -0
  99. package/dist/operations/alertThrottlePolicy.d.ts +3 -0
  100. package/dist/operations/alertThrottlePolicy.js +18 -0
  101. package/dist/operations/clients.d.ts +17 -0
  102. package/dist/operations/clients.js +32 -0
  103. package/dist/operations/contracts/admin.d.ts +93 -0
  104. package/dist/operations/contracts/admin.js +1 -0
  105. package/dist/operations/contracts/adminAlertsContracts.d.ts +40 -0
  106. package/dist/operations/contracts/adminAlertsContracts.js +1 -0
  107. package/dist/operations/contracts/alertHumanContext.d.ts +7 -0
  108. package/dist/operations/contracts/alertHumanContext.js +1 -0
  109. package/dist/operations/contracts/index.d.ts +6 -0
  110. package/dist/operations/contracts/index.js +6 -0
  111. package/dist/operations/contracts/observabilityContracts.d.ts +41 -0
  112. package/dist/operations/contracts/observabilityContracts.js +1 -0
  113. package/dist/operations/contracts/observabilityPorts.d.ts +18 -0
  114. package/dist/operations/contracts/observabilityPorts.js +1 -0
  115. package/dist/operations/contracts/ports.d.ts +19 -0
  116. package/dist/operations/contracts/ports.js +1 -0
  117. package/dist/operations/errors.d.ts +6 -0
  118. package/dist/operations/errors.js +6 -0
  119. package/dist/operations/index.d.ts +9 -0
  120. package/dist/operations/index.js +9 -0
  121. package/dist/operations/schemas.d.ts +138 -0
  122. package/dist/operations/schemas.js +104 -0
  123. package/dist/operations/server/adminAlertsHandlers.d.ts +16 -0
  124. package/dist/operations/server/adminAlertsHandlers.js +35 -0
  125. package/dist/operations/server/adminPipelineHandlers.d.ts +12 -0
  126. package/dist/operations/server/adminPipelineHandlers.js +48 -0
  127. package/dist/operations/server/adminSettingsHandlers.d.ts +14 -0
  128. package/dist/operations/server/adminSettingsHandlers.js +82 -0
  129. package/dist/operations/server/controlPlaneHandler.d.ts +7 -0
  130. package/dist/operations/server/controlPlaneHandler.js +54 -0
  131. package/dist/operations/server/controlPlaneStore.d.ts +12 -0
  132. package/dist/operations/server/controlPlaneStore.js +138 -0
  133. package/dist/operations/server/controlPlaneWatchdog.d.ts +7 -0
  134. package/dist/operations/server/controlPlaneWatchdog.js +20 -0
  135. package/dist/operations/server/index.d.ts +12 -0
  136. package/dist/operations/server/index.js +12 -0
  137. package/dist/operations/server/migrations.d.ts +14 -0
  138. package/dist/operations/server/migrations.js +7 -0
  139. package/dist/operations/server/platformWatchdogDecision.d.ts +34 -0
  140. package/dist/operations/server/platformWatchdogDecision.js +71 -0
  141. package/dist/operations/server/platformWatchdogDeliveryPolicy.d.ts +10 -0
  142. package/dist/operations/server/platformWatchdogDeliveryPolicy.js +53 -0
  143. package/dist/operations/server/platformWatchdogQueue.d.ts +11 -0
  144. package/dist/operations/server/platformWatchdogQueue.js +94 -0
  145. package/dist/operations/server/platformWatchdogService.d.ts +47 -0
  146. package/dist/operations/server/platformWatchdogService.js +105 -0
  147. package/dist/operations/validation.d.ts +2 -0
  148. package/dist/operations/validation.js +3 -0
  149. package/dist/portability/filesystemObjects.d.ts +12 -0
  150. package/dist/portability/filesystemObjects.js +191 -0
  151. package/dist/portability/index.d.ts +5 -0
  152. package/dist/portability/index.js +4 -0
  153. package/dist/portability/objects.d.ts +63 -0
  154. package/dist/portability/objects.js +138 -0
  155. package/dist/portability/postgresRows.d.ts +64 -0
  156. package/dist/portability/postgresRows.js +182 -0
  157. package/dist/scheduler/advisoryLock.js +20 -2
  158. package/dist/scheduler/nodeScheduler.d.ts +2 -2
  159. package/dist/scheduler/nodeScheduler.js +35 -6
  160. package/package.json +47 -2
  161. package/release-gates.json +143 -9
  162. package/sql/20260814010000_platform_control_plane.sql +286 -0
  163. package/src/composition/index.ts +1 -0
  164. package/src/composition/marketingContribution.ts +37 -0
  165. package/src/composition/nodeHost.ts +4 -3
  166. package/src/lifecycle/appUpgrade.ts +186 -0
  167. package/src/lifecycle/index.ts +19 -0
  168. package/src/lifecycle/postgresInstallQualification.ts +125 -0
  169. package/src/marketing/acquisitionCaseSchemas.ts +75 -0
  170. package/src/marketing/acquisitionEvidenceSchemas.ts +72 -0
  171. package/src/marketing/analytics/dataLayer.ts +100 -0
  172. package/src/marketing/analytics/noop.ts +14 -0
  173. package/src/marketing/analytics/purchaseFacts.ts +63 -0
  174. package/src/marketing/analytics/routePolicy.ts +55 -0
  175. package/src/marketing/consentEvidence.ts +36 -0
  176. package/src/marketing/contactLegal.ts +22 -0
  177. package/src/marketing/contracts/acquisition.ts +50 -0
  178. package/src/marketing/contracts/acquisitionPorts.ts +48 -0
  179. package/src/marketing/contracts/analytics.ts +88 -0
  180. package/src/marketing/contracts/contactLegal.ts +41 -0
  181. package/src/marketing/contracts/index.ts +17 -0
  182. package/src/marketing/contracts/prelaunch.ts +15 -0
  183. package/src/marketing/index.ts +16 -0
  184. package/src/marketing/prelaunchAcquisitionSchemas.ts +64 -0
  185. package/src/marketing/seo/jsonLd.ts +153 -0
  186. package/src/marketing/seo/metadata.ts +62 -0
  187. package/src/marketing/seo/serializeJsonLd.ts +6 -0
  188. package/src/marketing/seo/urls.ts +34 -0
  189. package/src/marketing/server/acquisitionCaseDirect.ts +67 -0
  190. package/src/marketing/server/acquisitionCaseHandlers.ts +57 -0
  191. package/src/marketing/server/acquisitionCasePorts.ts +42 -0
  192. package/src/marketing/server/acquisitionEvidenceDirect.ts +76 -0
  193. package/src/marketing/server/analyticsContext.ts +55 -0
  194. package/src/marketing/server/analyticsContextPorts.ts +28 -0
  195. package/src/marketing/server/bindings.ts +27 -0
  196. package/src/marketing/server/directPorts.ts +27 -0
  197. package/src/marketing/server/index.ts +14 -0
  198. package/src/marketing/server/postgres/acquisitionCaseRoutines.ts +218 -0
  199. package/src/marketing/server/postgres/acquisitionEvidenceRoutines.ts +103 -0
  200. package/src/marketing/server/postgres/index.ts +3 -0
  201. package/src/marketing/server/prelaunchAcquisitionDirect.ts +121 -0
  202. package/src/marketing/server/privacyContributor.ts +123 -0
  203. package/src/marketing/server/research/adminSurveyResponsesHandler.ts +78 -0
  204. package/src/marketing/server/research/managedSurveyResponseSubmit.ts +158 -0
  205. package/src/marketing/server/research/surveyResponseSubmitHandler.ts +57 -0
  206. package/src/marketing/validation.ts +3 -0
  207. package/src/migrations/postgresRunner.ts +24 -9
  208. package/src/operations/adminAlertsSchemas.ts +78 -0
  209. package/src/operations/adminAlertsView.ts +238 -0
  210. package/src/operations/alertPagingPolicy.ts +50 -0
  211. package/src/operations/alertThrottlePolicy.ts +22 -0
  212. package/src/operations/clients.ts +44 -0
  213. package/src/operations/contracts/admin.ts +24 -0
  214. package/src/operations/contracts/adminAlertsContracts.ts +13 -0
  215. package/src/operations/contracts/alertHumanContext.ts +17 -0
  216. package/src/operations/contracts/index.ts +6 -0
  217. package/src/operations/contracts/observabilityContracts.ts +40 -0
  218. package/src/operations/contracts/observabilityPorts.ts +30 -0
  219. package/src/operations/contracts/ports.ts +22 -0
  220. package/src/operations/errors.ts +6 -0
  221. package/src/operations/index.ts +9 -0
  222. package/src/operations/schemas.ts +122 -0
  223. package/src/operations/server/adminAlertsHandlers.ts +61 -0
  224. package/src/operations/server/adminPipelineHandlers.ts +73 -0
  225. package/src/operations/server/adminSettingsHandlers.ts +114 -0
  226. package/src/operations/server/controlPlaneHandler.ts +56 -0
  227. package/src/operations/server/controlPlaneStore.ts +150 -0
  228. package/src/operations/server/controlPlaneWatchdog.ts +28 -0
  229. package/src/operations/server/index.ts +12 -0
  230. package/src/operations/server/migrations.ts +7 -0
  231. package/src/operations/server/platformWatchdogDecision.ts +93 -0
  232. package/src/operations/server/platformWatchdogDeliveryPolicy.ts +92 -0
  233. package/src/operations/server/platformWatchdogQueue.ts +96 -0
  234. package/src/operations/server/platformWatchdogService.ts +209 -0
  235. package/src/operations/validation.ts +3 -0
  236. package/src/portability/filesystemObjects.ts +138 -0
  237. package/src/portability/index.ts +12 -0
  238. package/src/portability/objects.ts +160 -0
  239. package/src/portability/postgresRows.ts +169 -0
  240. package/src/scheduler/advisoryLock.ts +20 -5
  241. package/src/scheduler/nodeScheduler.ts +28 -8
@@ -0,0 +1,17 @@
1
+ import type { z } from "zod";
2
+ import type { AdminSettingsReadResponse, AdminSettingsUpdateRequest, AdminSettingsUpdateResponse, AdminPipelineReadResponse } from "./contracts/admin.js";
3
+ import type { AdminAlertsOverviewResponse } from "./contracts/adminAlertsContracts.js";
4
+ /** The existing BFF requester owns fetch, envelope validation, cancellation and diagnostics. */
5
+ export interface OperationsRequestOptions extends Omit<RequestInit, "body"> {
6
+ body?: unknown;
7
+ fetcher?: typeof fetch;
8
+ timeoutMs?: number;
9
+ }
10
+ export type OperationsRequestBff = <T>(path: string, schema: z.ZodType<T>, options?: OperationsRequestOptions) => Promise<T>;
11
+ /** Bind the existing browser calls without installing an ambient fetch implementation. */
12
+ export declare function createOperationsClients(requestBff: OperationsRequestBff): {
13
+ getAdminSettings(accessToken: string, options?: OperationsRequestOptions): Promise<AdminSettingsReadResponse>;
14
+ updateAdminSetting(accessToken: string, request: AdminSettingsUpdateRequest, options?: OperationsRequestOptions): Promise<AdminSettingsUpdateResponse>;
15
+ getAdminPipeline(accessToken: string, options?: OperationsRequestOptions): Promise<AdminPipelineReadResponse>;
16
+ getAdminAlertsOverview(accessToken: string, options?: OperationsRequestOptions): Promise<AdminAlertsOverviewResponse>;
17
+ };
@@ -0,0 +1,32 @@
1
+ import { adminSettingsReadResponseSchema, adminSettingsUpdateResponseSchema, adminPipelineReadResponseSchema } from "./schemas.js";
2
+ import { adminAlertsOverviewResponseSchema } from "./adminAlertsSchemas.js";
3
+ /** Bind the existing browser calls without installing an ambient fetch implementation. */
4
+ export function createOperationsClients(requestBff) {
5
+ return {
6
+ getAdminSettings(accessToken, options = {}) {
7
+ return requestBff("/api/bff/admin/platform/settings", adminSettingsReadResponseSchema, {
8
+ ...options, method: "GET", headers: authHeaders(accessToken, options),
9
+ });
10
+ },
11
+ updateAdminSetting(accessToken, request, options = {}) {
12
+ return requestBff("/api/bff/admin/platform/settings/update", adminSettingsUpdateResponseSchema, {
13
+ ...options, method: "POST", headers: authHeaders(accessToken, options), body: request,
14
+ });
15
+ },
16
+ getAdminPipeline(accessToken, options = {}) {
17
+ return requestBff("/api/bff/admin/platform/pipeline", adminPipelineReadResponseSchema, {
18
+ ...options, method: "GET", headers: authHeaders(accessToken, options),
19
+ });
20
+ },
21
+ getAdminAlertsOverview(accessToken, options = {}) {
22
+ return requestBff("/api/bff/admin/platform/alerts", adminAlertsOverviewResponseSchema, {
23
+ ...options, method: "GET", headers: authHeaders(accessToken, options),
24
+ });
25
+ },
26
+ };
27
+ }
28
+ function authHeaders(accessToken, options) {
29
+ const headers = new Headers(options.headers);
30
+ headers.set("Authorization", `Bearer ${accessToken}`);
31
+ return headers;
32
+ }
@@ -0,0 +1,93 @@
1
+ /** DTOs for the existing operational settings, pipeline and control-plane surfaces. */
2
+ export type AdminPipelineTester = {
3
+ id: string;
4
+ status: string;
5
+ email_sequence_step: number | null;
6
+ email_sequence_paused: boolean | null;
7
+ };
8
+ export type AdminPipelineEmailTemplate = {
9
+ id: string;
10
+ name: string;
11
+ sequence_order: number | null;
12
+ };
13
+ export type AdminPipelineEmailEvent = {
14
+ event_type: string;
15
+ };
16
+ export type AdminPipelineReadRequest = Record<string, never>;
17
+ export type AdminPipelineReadResponse = {
18
+ testers: AdminPipelineTester[];
19
+ templates: AdminPipelineEmailTemplate[];
20
+ emailSendCount: number;
21
+ emailEvents: AdminPipelineEmailEvent[];
22
+ };
23
+ export type AdminPipelineDhlTrackingRefreshRequest = Record<string, never>;
24
+ export type AdminPipelineDhlTrackingRefreshResponse = {
25
+ checked: number;
26
+ updated: number;
27
+ };
28
+ export type AdminSettingsAdminUser = {
29
+ id: string;
30
+ email: string | null;
31
+ role: string | null;
32
+ };
33
+ export type AdminSettingsReadRequest = Record<string, never>;
34
+ export type AdminSettingsReadResponse = {
35
+ settings: Record<string, unknown>;
36
+ adminUsers: AdminSettingsAdminUser[];
37
+ };
38
+ export type AdminSettingWriteValue = string | number | boolean | null;
39
+ export type AdminSettingsUpdateRequest = {
40
+ key: string;
41
+ value: AdminSettingWriteValue;
42
+ };
43
+ export type AdminSettingsUpdateResponse = {
44
+ key: string;
45
+ saved: true;
46
+ };
47
+ export type PlatformControlPlaneReadRequest = Record<string, never>;
48
+ export type PlatformControlPlaneReadResponse = {
49
+ controls: {
50
+ controlKey: string;
51
+ enabled: boolean;
52
+ revision: number;
53
+ updatedAt: string;
54
+ }[];
55
+ jobs: {
56
+ jobName: string;
57
+ enabled: boolean;
58
+ activeDriver: "worker" | "scheduler" | "operator";
59
+ lastStatus: "running" | "success" | "failed" | "skipped" | null;
60
+ lastStartedAt: string | null;
61
+ lastFinishedAt: string | null;
62
+ lastSuccessAt: string | null;
63
+ }[];
64
+ alerts: {
65
+ dedupeKey: string;
66
+ severity: "p0" | "p1" | "p2" | "p3";
67
+ status: "open" | "acknowledged" | "resolved";
68
+ owner: string;
69
+ title: string;
70
+ firstSeenAt: string;
71
+ lastSeenAt: string;
72
+ resolvedAt: string | null;
73
+ }[];
74
+ };
75
+ export type PlatformControlPlaneMutation = {
76
+ action: "set-control";
77
+ idempotencyKey: string;
78
+ controlKey: string;
79
+ enabled: boolean;
80
+ } | {
81
+ action: "record-heartbeat";
82
+ idempotencyKey: string;
83
+ health: "healthy" | "degraded" | "failed";
84
+ firingCount: number;
85
+ maxSeverity: "p0" | "p1" | "p2" | "p3" | null;
86
+ promotionReady: boolean;
87
+ };
88
+ export type PlatformControlPlaneMutationResponse = {
89
+ action: "set-control" | "record-heartbeat";
90
+ replayed: boolean;
91
+ revision: number | null;
92
+ recordedAt: string;
93
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ /** Operator projection; persistence and read authority remain host-owned. */
2
+ export type AdminAlertSeverity = "p0" | "p1" | "p2" | "p3";
3
+ export type AdminAlertLane = "commerce" | "platform";
4
+ export type AdminAlertHealth = "ok" | "degraded" | "down" | "unknown";
5
+ export type AdminAlert = {
6
+ id: string;
7
+ dedupeKey: string;
8
+ lane: AdminAlertLane;
9
+ owner: string;
10
+ severity: AdminAlertSeverity;
11
+ status: "open" | "acknowledged";
12
+ pageable: boolean;
13
+ title: string;
14
+ message: string;
15
+ supportCode: string | null;
16
+ runbookUrl: string | null;
17
+ firstSeenAt: string;
18
+ lastSeenAt: string;
19
+ snoozedUntil: string | null;
20
+ };
21
+ export type AdminAlertsHeartbeat = {
22
+ lastSuccessAt: string | null;
23
+ staleAfterSeconds: number;
24
+ stale: boolean;
25
+ };
26
+ export type AdminAlertsSummary = {
27
+ commercePageableCount: number;
28
+ commerceTotalCount: number;
29
+ platformPageableCount: number;
30
+ snoozedCount: number;
31
+ maxOpenSeverity: AdminAlertSeverity | null;
32
+ };
33
+ export type AdminAlertsOverviewResponse = {
34
+ health: AdminAlertHealth;
35
+ summary: AdminAlertsSummary;
36
+ heartbeat: AdminAlertsHeartbeat;
37
+ alerts: AdminAlert[];
38
+ snoozedAlerts: AdminAlert[];
39
+ generatedAt: string;
40
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export type AlertIncidentClass = "customer_communication_failure" | "scheduled_job_failed" | "scheduled_job_missed" | "fulfillment_tracking_stalled" | "configuration_drift" | "data_integrity" | "queue_backlog" | "recipient_configuration_failure" | "platform_watchdog";
2
+ export type AlertHumanContext = {
3
+ incidentClass: AlertIncidentClass;
4
+ impact: string;
5
+ firstAction: string;
6
+ urgency: string;
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export * from "./admin.js";
2
+ export * from "./adminAlertsContracts.js";
3
+ export * from "./ports.js";
4
+ export * from "./observabilityContracts.js";
5
+ export * from "./observabilityPorts.js";
6
+ export * from "./alertHumanContext.js";
@@ -0,0 +1,6 @@
1
+ export * from "./admin.js";
2
+ export * from "./adminAlertsContracts.js";
3
+ export * from "./ports.js";
4
+ export * from "./observabilityContracts.js";
5
+ export * from "./observabilityPorts.js";
6
+ export * from "./alertHumanContext.js";
@@ -0,0 +1,41 @@
1
+ export type AlertSeverity = "p0" | "p1" | "p2" | "p3";
2
+ /** Opaque host-owned transport key; this module declares no vendor capability. */
3
+ export type AlertChannel = string;
4
+ export type WatchdogSnapshot = {
5
+ checkedAt: string;
6
+ };
7
+ export type AlertDecision<Channel extends string = AlertChannel> = {
8
+ dedupeKey: string;
9
+ severity: AlertSeverity;
10
+ owner: string;
11
+ runbookUrl: string;
12
+ title: string;
13
+ message: string;
14
+ humanContext?: import("./alertHumanContext.js").AlertHumanContext;
15
+ channels: Channel[];
16
+ payload: Record<string, unknown>;
17
+ paging?: "default" | "never";
18
+ };
19
+ export type OpenAlert = {
20
+ id: string;
21
+ dedupeKey: string;
22
+ status: "open" | "acknowledged";
23
+ severity: AlertSeverity;
24
+ lastNotifiedAt: string | null;
25
+ /** Most recent watchdog delivery decision, including skipped/failed attempts. */
26
+ lastNotificationAttemptAt?: string | null;
27
+ lastNotificationStatus?: AlertNotificationOutcome["status"] | null;
28
+ /** Earliest time the watchdog may create another delivery-attempt ledger row. */
29
+ nextNotificationAttemptAt?: string | null;
30
+ /** Consecutive failed webhook attempts; reset by sent/skipped outcomes. */
31
+ notificationFailureCount?: number;
32
+ /** Operator silence window; when set and in the future, paging is suppressed. */
33
+ snoozedUntil?: string | null;
34
+ };
35
+ export type AlertNotificationOutcome<Channel extends string = AlertChannel> = {
36
+ channel: Channel;
37
+ status: "sent" | "failed" | "skipped";
38
+ provider?: string | null;
39
+ providerResponse?: Record<string, unknown> | null;
40
+ error?: string | null;
41
+ };
@@ -0,0 +1,18 @@
1
+ import type { AlertDecision, AlertNotificationOutcome, WatchdogSnapshot, OpenAlert } from "./observabilityContracts.js";
2
+ export type ObservabilityEvidencePort<Snapshot extends WatchdogSnapshot = WatchdogSnapshot> = {
3
+ collectSnapshot(now: Date): Promise<Snapshot>;
4
+ };
5
+ export type AlertLedgerPort<Channel extends string = string> = {
6
+ listOpenAlerts(): Promise<OpenAlert[]>;
7
+ upsertOpenAlert: (decision: AlertDecision<Channel>, now: Date) => Promise<OpenAlert>;
8
+ resolveAlert(dedupeKey: string, now: Date): Promise<void>;
9
+ recordNotification: (alertId: string,
10
+ /** The kernel retains its existing webhook-keyed skipped-attempt audit rows. */
11
+ outcome: AlertNotificationOutcome<Channel | "webhook">, now: Date, schedule: {
12
+ nextAttemptAt: Date;
13
+ failureCount: number;
14
+ }) => Promise<void>;
15
+ };
16
+ export type AlertSinkPort<Channel extends string = string> = {
17
+ send: (decision: AlertDecision<Channel>, alert: OpenAlert) => Promise<AlertNotificationOutcome<Channel>>;
18
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { AdminPipelineReadRequest, AdminPipelineReadResponse, AdminSettingsReadRequest, AdminSettingsReadResponse, AdminSettingsUpdateRequest, AdminSettingsUpdateResponse, PlatformControlPlaneReadRequest, PlatformControlPlaneReadResponse, PlatformControlPlaneMutation, PlatformControlPlaneMutationResponse } from "./admin.js";
2
+ export interface AdminPipelineReadPort {
3
+ readPipeline(request: AdminPipelineReadRequest): Promise<AdminPipelineReadResponse>;
4
+ }
5
+ export interface AdminSettingsOperationsPort {
6
+ readSettings(request: AdminSettingsReadRequest): Promise<AdminSettingsReadResponse>;
7
+ updateSetting(request: AdminSettingsUpdateRequest): Promise<AdminSettingsUpdateResponse>;
8
+ }
9
+ export interface PlatformControlPlanePort {
10
+ readControlPlane(request: PlatformControlPlaneReadRequest): Promise<PlatformControlPlaneReadResponse>;
11
+ mutateControlPlane(request: PlatformControlPlaneMutation): Promise<PlatformControlPlaneMutationResponse>;
12
+ }
13
+ export type OperationsAuthorizationResult = {
14
+ ok: true;
15
+ } | {
16
+ ok: false;
17
+ code: "UNAUTHORIZED" | "FORBIDDEN";
18
+ message: string;
19
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export declare class PlatformControlPlaneConflictError extends Error {
2
+ readonly name = "PlatformControlPlaneConflictError";
3
+ }
4
+ export declare class PlatformControlPlaneUnavailableError extends Error {
5
+ readonly name = "PlatformControlPlaneUnavailableError";
6
+ }
@@ -0,0 +1,6 @@
1
+ export class PlatformControlPlaneConflictError extends Error {
2
+ name = "PlatformControlPlaneConflictError";
3
+ }
4
+ export class PlatformControlPlaneUnavailableError extends Error {
5
+ name = "PlatformControlPlaneUnavailableError";
6
+ }
@@ -0,0 +1,9 @@
1
+ /** Browser-safe operational contracts, validation and operator projections. */
2
+ export * from "./contracts/index.js";
3
+ export * from "./schemas.js";
4
+ export * from "./adminAlertsSchemas.js";
5
+ export * from "./adminAlertsView.js";
6
+ export * from "./alertPagingPolicy.js";
7
+ export * from "./alertThrottlePolicy.js";
8
+ export * from "./errors.js";
9
+ export * from "./clients.js";
@@ -0,0 +1,9 @@
1
+ /** Browser-safe operational contracts, validation and operator projections. */
2
+ export * from "./contracts/index.js";
3
+ export * from "./schemas.js";
4
+ export * from "./adminAlertsSchemas.js";
5
+ export * from "./adminAlertsView.js";
6
+ export * from "./alertPagingPolicy.js";
7
+ export * from "./alertThrottlePolicy.js";
8
+ export * from "./errors.js";
9
+ export * from "./clients.js";
@@ -0,0 +1,138 @@
1
+ import { z } from "./validation.js";
2
+ export declare const adminPipelineTesterSchema: z.ZodObject<{
3
+ id: z.ZodString;
4
+ status: z.ZodString;
5
+ email_sequence_step: z.ZodNullable<z.ZodNumber>;
6
+ email_sequence_paused: z.ZodNullable<z.ZodBoolean>;
7
+ }, z.core.$strip>;
8
+ export declare const adminPipelineEmailTemplateSchema: z.ZodObject<{
9
+ id: z.ZodString;
10
+ name: z.ZodString;
11
+ sequence_order: z.ZodNullable<z.ZodNumber>;
12
+ }, z.core.$strip>;
13
+ export declare const adminPipelineEmailEventSchema: z.ZodObject<{
14
+ event_type: z.ZodString;
15
+ }, z.core.$strip>;
16
+ export declare const adminPipelineReadRequestSchema: z.ZodObject<{}, z.core.$strict>;
17
+ export declare const adminPipelineReadResponseSchema: z.ZodObject<{
18
+ testers: z.ZodArray<z.ZodObject<{
19
+ id: z.ZodString;
20
+ status: z.ZodString;
21
+ email_sequence_step: z.ZodNullable<z.ZodNumber>;
22
+ email_sequence_paused: z.ZodNullable<z.ZodBoolean>;
23
+ }, z.core.$strip>>;
24
+ templates: z.ZodArray<z.ZodObject<{
25
+ id: z.ZodString;
26
+ name: z.ZodString;
27
+ sequence_order: z.ZodNullable<z.ZodNumber>;
28
+ }, z.core.$strip>>;
29
+ emailSendCount: z.ZodNumber;
30
+ emailEvents: z.ZodArray<z.ZodObject<{
31
+ event_type: z.ZodString;
32
+ }, z.core.$strip>>;
33
+ }, z.core.$strip>;
34
+ export declare const adminPipelineDhlTrackingRefreshRequestSchema: z.ZodObject<{}, z.core.$strict>;
35
+ export declare const adminPipelineDhlTrackingRefreshResponseSchema: z.ZodObject<{
36
+ checked: z.ZodNumber;
37
+ updated: z.ZodNumber;
38
+ }, z.core.$strip>;
39
+ export declare const adminSettingsReadRequestSchema: z.ZodObject<{}, z.core.$strict>;
40
+ export declare const adminSettingsAdminUserSchema: z.ZodObject<{
41
+ id: z.ZodString;
42
+ email: z.ZodNullable<z.ZodString>;
43
+ role: z.ZodNullable<z.ZodString>;
44
+ }, z.core.$strip>;
45
+ export declare const adminSettingsReadResponseSchema: z.ZodObject<{
46
+ settings: z.ZodRecord<z.ZodString, z.ZodUnknown>;
47
+ adminUsers: z.ZodArray<z.ZodObject<{
48
+ id: z.ZodString;
49
+ email: z.ZodNullable<z.ZodString>;
50
+ role: z.ZodNullable<z.ZodString>;
51
+ }, z.core.$strip>>;
52
+ }, z.core.$strip>;
53
+ export declare const adminSettingWriteValueSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
54
+ export declare const adminSettingsUpdateRequestSchema: z.ZodObject<{
55
+ key: z.ZodString;
56
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
57
+ }, z.core.$strip>;
58
+ export declare const adminSettingsUpdateResponseSchema: z.ZodObject<{
59
+ key: z.ZodString;
60
+ saved: z.ZodLiteral<true>;
61
+ }, z.core.$strip>;
62
+ export declare const platformControlPlaneReadRequestSchema: z.ZodObject<{}, z.core.$strict>;
63
+ export declare const platformControlPlaneReadResponseSchema: z.ZodObject<{
64
+ controls: z.ZodArray<z.ZodObject<{
65
+ controlKey: z.ZodString;
66
+ enabled: z.ZodBoolean;
67
+ revision: z.ZodNumber;
68
+ updatedAt: z.ZodString;
69
+ }, z.core.$strip>>;
70
+ jobs: z.ZodArray<z.ZodObject<{
71
+ jobName: z.ZodString;
72
+ enabled: z.ZodBoolean;
73
+ activeDriver: z.ZodEnum<{
74
+ operator: "operator";
75
+ scheduler: "scheduler";
76
+ worker: "worker";
77
+ }>;
78
+ lastStatus: z.ZodNullable<z.ZodEnum<{
79
+ failed: "failed";
80
+ skipped: "skipped";
81
+ success: "success";
82
+ running: "running";
83
+ }>>;
84
+ lastStartedAt: z.ZodNullable<z.ZodString>;
85
+ lastFinishedAt: z.ZodNullable<z.ZodString>;
86
+ lastSuccessAt: z.ZodNullable<z.ZodString>;
87
+ }, z.core.$strip>>;
88
+ alerts: z.ZodArray<z.ZodObject<{
89
+ dedupeKey: z.ZodString;
90
+ severity: z.ZodEnum<{
91
+ p0: "p0";
92
+ p1: "p1";
93
+ p2: "p2";
94
+ p3: "p3";
95
+ }>;
96
+ status: z.ZodEnum<{
97
+ open: "open";
98
+ resolved: "resolved";
99
+ acknowledged: "acknowledged";
100
+ }>;
101
+ owner: z.ZodString;
102
+ title: z.ZodString;
103
+ firstSeenAt: z.ZodString;
104
+ lastSeenAt: z.ZodString;
105
+ resolvedAt: z.ZodNullable<z.ZodString>;
106
+ }, z.core.$strip>>;
107
+ }, z.core.$strip>;
108
+ export declare const platformControlPlaneMutationSchema: z.ZodUnion<readonly [z.ZodObject<{
109
+ action: z.ZodLiteral<"set-control">;
110
+ idempotencyKey: z.ZodString;
111
+ controlKey: z.ZodString;
112
+ enabled: z.ZodBoolean;
113
+ }, z.core.$strict>, z.ZodObject<{
114
+ action: z.ZodLiteral<"record-heartbeat">;
115
+ idempotencyKey: z.ZodString;
116
+ health: z.ZodEnum<{
117
+ failed: "failed";
118
+ degraded: "degraded";
119
+ healthy: "healthy";
120
+ }>;
121
+ firingCount: z.ZodNumber;
122
+ maxSeverity: z.ZodNullable<z.ZodEnum<{
123
+ p0: "p0";
124
+ p1: "p1";
125
+ p2: "p2";
126
+ p3: "p3";
127
+ }>>;
128
+ promotionReady: z.ZodBoolean;
129
+ }, z.core.$strict>]>;
130
+ export declare const platformControlPlaneMutationResponseSchema: z.ZodObject<{
131
+ action: z.ZodEnum<{
132
+ "set-control": "set-control";
133
+ "record-heartbeat": "record-heartbeat";
134
+ }>;
135
+ replayed: z.ZodBoolean;
136
+ revision: z.ZodNullable<z.ZodNumber>;
137
+ recordedAt: z.ZodString;
138
+ }, z.core.$strip>;
@@ -0,0 +1,104 @@
1
+ import { z } from "./validation.js";
2
+ export const adminPipelineTesterSchema = z.object({
3
+ id: z.string().min(1),
4
+ status: z.string().min(1),
5
+ email_sequence_step: z.number().int().min(0).nullable(),
6
+ email_sequence_paused: z.boolean().nullable(),
7
+ });
8
+ export const adminPipelineEmailTemplateSchema = z.object({
9
+ id: z.string().min(1),
10
+ name: z.string().min(1),
11
+ sequence_order: z.number().int().min(0).nullable(),
12
+ });
13
+ export const adminPipelineEmailEventSchema = z.object({
14
+ event_type: z.string().min(1),
15
+ });
16
+ export const adminPipelineReadRequestSchema = z.object({}).strict();
17
+ export const adminPipelineReadResponseSchema = z.object({
18
+ testers: z.array(adminPipelineTesterSchema),
19
+ templates: z.array(adminPipelineEmailTemplateSchema),
20
+ emailSendCount: z.number().int().min(0),
21
+ emailEvents: z.array(adminPipelineEmailEventSchema),
22
+ });
23
+ export const adminPipelineDhlTrackingRefreshRequestSchema = z.object({}).strict();
24
+ export const adminPipelineDhlTrackingRefreshResponseSchema = z.object({
25
+ checked: z.number().int().min(0),
26
+ updated: z.number().int().min(0),
27
+ });
28
+ export const adminSettingsReadRequestSchema = z.object({}).strict();
29
+ export const adminSettingsAdminUserSchema = z.object({
30
+ id: z.string().min(1),
31
+ email: z.string().nullable(),
32
+ role: z.string().nullable(),
33
+ });
34
+ export const adminSettingsReadResponseSchema = z.object({
35
+ settings: z.record(z.string(), z.unknown()),
36
+ adminUsers: z.array(adminSettingsAdminUserSchema),
37
+ });
38
+ export const adminSettingWriteValueSchema = z.union([
39
+ z.string(),
40
+ z.number(),
41
+ z.boolean(),
42
+ z.null(),
43
+ ]);
44
+ export const adminSettingsUpdateRequestSchema = z.object({
45
+ key: z.string().trim().min(1),
46
+ value: adminSettingWriteValueSchema,
47
+ });
48
+ export const adminSettingsUpdateResponseSchema = z.object({
49
+ key: z.string().min(1),
50
+ saved: z.literal(true),
51
+ });
52
+ const platformControlKeySchema = z.string().trim().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$/);
53
+ const platformOperationKeySchema = z.string().trim().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/);
54
+ const platformTimestampSchema = z.string().datetime({ offset: true });
55
+ export const platformControlPlaneReadRequestSchema = z.object({}).strict();
56
+ export const platformControlPlaneReadResponseSchema = z.object({
57
+ controls: z.array(z.object({
58
+ controlKey: platformControlKeySchema,
59
+ enabled: z.boolean(),
60
+ revision: z.number().int().min(1),
61
+ updatedAt: platformTimestampSchema,
62
+ })),
63
+ jobs: z.array(z.object({
64
+ jobName: z.string().min(1),
65
+ enabled: z.boolean(),
66
+ activeDriver: z.enum(["worker", "scheduler", "operator"]),
67
+ lastStatus: z.enum(["running", "success", "failed", "skipped"]).nullable(),
68
+ lastStartedAt: platformTimestampSchema.nullable(),
69
+ lastFinishedAt: platformTimestampSchema.nullable(),
70
+ lastSuccessAt: platformTimestampSchema.nullable(),
71
+ })),
72
+ alerts: z.array(z.object({
73
+ dedupeKey: z.string().min(1),
74
+ severity: z.enum(["p0", "p1", "p2", "p3"]),
75
+ status: z.enum(["open", "acknowledged", "resolved"]),
76
+ owner: z.string().min(1),
77
+ title: z.string().min(1),
78
+ firstSeenAt: platformTimestampSchema,
79
+ lastSeenAt: platformTimestampSchema,
80
+ resolvedAt: platformTimestampSchema.nullable(),
81
+ })),
82
+ });
83
+ export const platformControlPlaneMutationSchema = z.union([
84
+ z.object({
85
+ action: z.literal("set-control"),
86
+ idempotencyKey: platformOperationKeySchema,
87
+ controlKey: platformControlKeySchema,
88
+ enabled: z.boolean(),
89
+ }).strict(),
90
+ z.object({
91
+ action: z.literal("record-heartbeat"),
92
+ idempotencyKey: platformOperationKeySchema,
93
+ health: z.enum(["healthy", "degraded", "failed"]),
94
+ firingCount: z.number().int().min(0),
95
+ maxSeverity: z.enum(["p0", "p1", "p2", "p3"]).nullable(),
96
+ promotionReady: z.boolean(),
97
+ }).strict(),
98
+ ]);
99
+ export const platformControlPlaneMutationResponseSchema = z.object({
100
+ action: z.enum(["set-control", "record-heartbeat"]),
101
+ replayed: z.boolean(),
102
+ revision: z.number().int().min(1).nullable(),
103
+ recordedAt: platformTimestampSchema,
104
+ });
@@ -0,0 +1,16 @@
1
+ import { type BffResponderOptions } from "../../bff/index.js";
2
+ import type { HttpRequest, HttpResponse } from "../../http/index.js";
3
+ import type { PlatformAlertLedgerRow, WatchdogHeartbeatRow } from "../index.js";
4
+ import type { OperationsAuthorizationResult } from "../contracts/index.js";
5
+ type AuthorizeAdmin = () => Promise<OperationsAuthorizationResult>;
6
+ export interface AdminAlertsReadPort {
7
+ listLiveAlerts(): Promise<PlatformAlertLedgerRow[]>;
8
+ readWatchdogHeartbeat(): Promise<WatchdogHeartbeatRow>;
9
+ }
10
+ export interface AdminAlertsOverviewDeps extends BffResponderOptions {
11
+ readPort: AdminAlertsReadPort;
12
+ authorizeAdmin: AuthorizeAdmin;
13
+ now?: () => Date;
14
+ }
15
+ export declare function createAdminAlertsOverviewHandler({ readPort, authorizeAdmin, now, responseRequestId, }: AdminAlertsOverviewDeps): (req: HttpRequest, res: HttpResponse) => Promise<void>;
16
+ export {};
@@ -0,0 +1,35 @@
1
+ import { createBffResponder } from "../../bff/index.js";
2
+ import { adminAlertsOverviewResponseSchema } from "../index.js";
3
+ import { buildAlertsOverview } from "../index.js";
4
+ export function createAdminAlertsOverviewHandler({ readPort, authorizeAdmin, now = () => new Date(), responseRequestId, }) {
5
+ const { sendBffError, sendBffSuccess, sendMethodNotAllowed } = createBffResponder({ responseRequestId });
6
+ return async function handler(req, res) {
7
+ if (req.method !== "GET") {
8
+ sendMethodNotAllowed(res, ["GET"]);
9
+ return;
10
+ }
11
+ const authorization = await authorizeAdmin();
12
+ if (authorization.ok === false) {
13
+ sendBffError(res, authorization.code, authorization.message);
14
+ return;
15
+ }
16
+ try {
17
+ // Heartbeat and alerts are read together: an empty alert list is only
18
+ // "healthy" if the watchdog actually reported recently.
19
+ const [alerts, heartbeat] = await Promise.all([
20
+ readPort.listLiveAlerts(),
21
+ readPort.readWatchdogHeartbeat(),
22
+ ]);
23
+ const overview = buildAlertsOverview(alerts, heartbeat, now());
24
+ const response = adminAlertsOverviewResponseSchema.safeParse(overview);
25
+ if (!response.success) {
26
+ sendBffError(res, "INVALID_RESPONSE", "Admin alerts overview returned invalid response");
27
+ return;
28
+ }
29
+ sendBffSuccess(res, response.data);
30
+ }
31
+ catch {
32
+ sendBffError(res, "UPSTREAM_UNAVAILABLE", "Admin alerts overview failed");
33
+ }
34
+ };
35
+ }
@@ -0,0 +1,12 @@
1
+ import { type BffResponderOptions } from "../../bff/index.js";
2
+ import type { HttpRequest, HttpResponse } from "../../http/index.js";
3
+ import type { AdminPipelineReadPort } from "../contracts/index.js";
4
+ import type { OperationsAuthorizationResult } from "../contracts/index.js";
5
+ interface AdminPipelineBaseDeps extends BffResponderOptions {
6
+ authorizeAdmin: (req: HttpRequest) => Promise<OperationsAuthorizationResult>;
7
+ }
8
+ export interface AdminPipelineReadDeps extends AdminPipelineBaseDeps {
9
+ pipelinePort: Pick<AdminPipelineReadPort, "readPipeline">;
10
+ }
11
+ export declare function createAdminPipelineReadHandler({ pipelinePort, authorizeAdmin, responseRequestId, }: AdminPipelineReadDeps): (req: HttpRequest, res: HttpResponse) => Promise<void>;
12
+ export {};