@krak-stack/registry 0.1.18 → 0.1.19

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.
package/README.md CHANGED
@@ -33,6 +33,11 @@ import { Query } from "@krak-stack/registry/query";
33
33
  import { createSeo } from "@krak-stack/registry/seo";
34
34
  import { FileExtractionService } from "@krak-stack/registry/service-file-extraction";
35
35
  import { FileExtractedTextSchema } from "@krak-stack/registry/service-file-extraction/schema";
36
+ import {
37
+ HealthApiGroup,
38
+ healthHandler,
39
+ HealthService,
40
+ } from "@krak-stack/registry/service-health";
36
41
  import { NotificationService } from "@krak-stack/registry/service-notification";
37
42
  ```
38
43
 
@@ -0,0 +1,66 @@
1
+ import { HttpRouter } from "effect/unstable/http";
2
+ import { HttpApiBuilder, HttpApiGroup } from "effect/unstable/httpapi";
3
+ import { HealthApiGroup } from "./api.group.js";
4
+ import { HealthService } from "./index.js";
5
+ export declare const healthHandler: <const Prefix extends HttpRouter.PathInput>(handlers: HttpApiBuilder.Handlers.FromGroup<HttpApiGroup.AddPrefix<typeof HealthApiGroup, Prefix>>) => HttpApiBuilder.Handlers<HttpRouter.Request<"Requires", HealthService>, {
6
+ readonly getHealth: import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"getHealth", "GET", `${Prefix}/health`, never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
7
+ readonly status: import("effect/Schema").Literal<"UP">;
8
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
9
+ readonly name: import("effect/Schema").NonEmptyString;
10
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
11
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
12
+ }>>;
13
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
14
+ readonly status: import("effect/Schema").Literal<"DOWN">;
15
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
16
+ readonly name: import("effect/Schema").NonEmptyString;
17
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
18
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
19
+ }>>;
20
+ }> | typeof import("effect/unstable/httpapi/HttpApiError").InternalServerError>, never, never>;
21
+ readonly getLiveness: import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"getLiveness", "GET", `${Prefix}/health/live`, never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
22
+ readonly status: import("effect/Schema").Literal<"UP">;
23
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
24
+ readonly name: import("effect/Schema").NonEmptyString;
25
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
26
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
27
+ }>>;
28
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
29
+ readonly status: import("effect/Schema").Literal<"DOWN">;
30
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
31
+ readonly name: import("effect/Schema").NonEmptyString;
32
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
33
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
34
+ }>>;
35
+ }> | typeof import("effect/unstable/httpapi/HttpApiError").InternalServerError>, never, never>;
36
+ readonly getReadiness: import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"getReadiness", "GET", `${Prefix}/health/ready`, never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
37
+ readonly status: import("effect/Schema").Literal<"UP">;
38
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
39
+ readonly name: import("effect/Schema").NonEmptyString;
40
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
41
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
42
+ }>>;
43
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
44
+ readonly status: import("effect/Schema").Literal<"DOWN">;
45
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
46
+ readonly name: import("effect/Schema").NonEmptyString;
47
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
48
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
49
+ }>>;
50
+ }> | typeof import("effect/unstable/httpapi/HttpApiError").InternalServerError>, never, never>;
51
+ readonly getStartup: import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"getStartup", "GET", `${Prefix}/health/started`, never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
52
+ readonly status: import("effect/Schema").Literal<"UP">;
53
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
54
+ readonly name: import("effect/Schema").NonEmptyString;
55
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
56
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
57
+ }>>;
58
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
59
+ readonly status: import("effect/Schema").Literal<"DOWN">;
60
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
61
+ readonly name: import("effect/Schema").NonEmptyString;
62
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
63
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
64
+ }>>;
65
+ }> | typeof import("effect/unstable/httpapi/HttpApiError").InternalServerError>, never, never>;
66
+ }, "getHealth" | "getLiveness" | "getReadiness" | "getStartup">;
@@ -0,0 +1,58 @@
1
+ import { HttpApiEndpoint, HttpApiError, HttpApiGroup } from "effect/unstable/httpapi";
2
+ export declare const HealthApiGroup: HttpApiGroup.HttpApiGroup<"health", HttpApiEndpoint.HttpApiEndpoint<"getHealth", "GET", "/health", never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
3
+ readonly status: import("effect/Schema").Literal<"UP">;
4
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
5
+ readonly name: import("effect/Schema").NonEmptyString;
6
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
7
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
8
+ }>>;
9
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
10
+ readonly status: import("effect/Schema").Literal<"DOWN">;
11
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
12
+ readonly name: import("effect/Schema").NonEmptyString;
13
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
14
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
15
+ }>>;
16
+ }> | typeof HttpApiError.InternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"getLiveness", "GET", "/health/live", never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
17
+ readonly status: import("effect/Schema").Literal<"UP">;
18
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
19
+ readonly name: import("effect/Schema").NonEmptyString;
20
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
21
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
22
+ }>>;
23
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
24
+ readonly status: import("effect/Schema").Literal<"DOWN">;
25
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
26
+ readonly name: import("effect/Schema").NonEmptyString;
27
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
28
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
29
+ }>>;
30
+ }> | typeof HttpApiError.InternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"getReadiness", "GET", "/health/ready", never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
31
+ readonly status: import("effect/Schema").Literal<"UP">;
32
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
33
+ readonly name: import("effect/Schema").NonEmptyString;
34
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
35
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
36
+ }>>;
37
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
38
+ readonly status: import("effect/Schema").Literal<"DOWN">;
39
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
40
+ readonly name: import("effect/Schema").NonEmptyString;
41
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
42
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
43
+ }>>;
44
+ }> | typeof HttpApiError.InternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"getStartup", "GET", "/health/started", never, never, never, never, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
45
+ readonly status: import("effect/Schema").Literal<"UP">;
46
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
47
+ readonly name: import("effect/Schema").NonEmptyString;
48
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
49
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
50
+ }>>;
51
+ }>>, import("effect/Schema").toCodecJson<import("effect/Schema").Struct<{
52
+ readonly status: import("effect/Schema").Literal<"DOWN">;
53
+ readonly checks: import("effect/Schema").$Array<import("effect/Schema").Struct<{
54
+ readonly name: import("effect/Schema").NonEmptyString;
55
+ readonly status: import("effect/Schema").Literals<readonly ["UP", "DOWN"]>;
56
+ readonly data: import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Boolean, import("effect/Schema").Number]>>>;
57
+ }>>;
58
+ }> | typeof HttpApiError.InternalServerError>, never, never>, false>;
@@ -0,0 +1,253 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import type { HealthCheckData, HealthCheckOutcome } from "./schema.js";
3
+ export type HealthCheck<Requirements = never> = {
4
+ readonly name: string;
5
+ readonly check: Effect.Effect<HealthCheckOutcome, unknown, Requirements>;
6
+ };
7
+ export type HealthServiceChecks<Requirements = never> = {
8
+ readonly live?: ReadonlyArray<HealthCheck<Requirements>>;
9
+ readonly ready?: ReadonlyArray<HealthCheck<Requirements>>;
10
+ readonly started?: ReadonlyArray<HealthCheck<Requirements>>;
11
+ };
12
+ export type HealthServiceOptions<Requirements = never> = {
13
+ readonly checks?: HealthServiceChecks<Requirements>;
14
+ };
15
+ type RegisteredHealthChecks = {
16
+ readonly live: ReadonlyArray<HealthCheck>;
17
+ readonly ready: ReadonlyArray<HealthCheck>;
18
+ readonly started: ReadonlyArray<HealthCheck>;
19
+ };
20
+ declare const HealthServiceConfig_base: Context.ServiceClass<HealthServiceConfig, "@krak-stack/registry/HealthServiceConfig", RegisteredHealthChecks>;
21
+ declare class HealthServiceConfig extends HealthServiceConfig_base {
22
+ static readonly layerWith: <Requirements = never>({ checks, }?: HealthServiceOptions<Requirements>) => Layer.Layer<HealthServiceConfig, never, Exclude<Requirements, import("effect/Scope").Scope>>;
23
+ }
24
+ declare const HealthService_base: Context.ServiceClass<HealthService, "@krak-stack/registry/HealthService", {
25
+ aggregate: () => Effect.Effect<{
26
+ status: "UP";
27
+ checks: ({
28
+ name: string;
29
+ status: "DOWN" | "UP";
30
+ data?: undefined;
31
+ } | {
32
+ name: string;
33
+ status: "DOWN" | "UP";
34
+ data: {
35
+ readonly [x: string]: string | number | boolean;
36
+ };
37
+ })[];
38
+ } | {
39
+ status: "DOWN";
40
+ checks: ({
41
+ name: string;
42
+ status: "DOWN" | "UP";
43
+ data?: undefined;
44
+ } | {
45
+ name: string;
46
+ status: "DOWN" | "UP";
47
+ data: {
48
+ readonly [x: string]: string | number | boolean;
49
+ };
50
+ })[];
51
+ }, never, never>;
52
+ live: () => Effect.Effect<{
53
+ status: "UP";
54
+ checks: ({
55
+ name: string;
56
+ status: "DOWN" | "UP";
57
+ data?: undefined;
58
+ } | {
59
+ name: string;
60
+ status: "DOWN" | "UP";
61
+ data: {
62
+ readonly [x: string]: string | number | boolean;
63
+ };
64
+ })[];
65
+ } | {
66
+ status: "DOWN";
67
+ checks: ({
68
+ name: string;
69
+ status: "DOWN" | "UP";
70
+ data?: undefined;
71
+ } | {
72
+ name: string;
73
+ status: "DOWN" | "UP";
74
+ data: {
75
+ readonly [x: string]: string | number | boolean;
76
+ };
77
+ })[];
78
+ }, never, never>;
79
+ ready: () => Effect.Effect<{
80
+ status: "UP";
81
+ checks: ({
82
+ name: string;
83
+ status: "DOWN" | "UP";
84
+ data?: undefined;
85
+ } | {
86
+ name: string;
87
+ status: "DOWN" | "UP";
88
+ data: {
89
+ readonly [x: string]: string | number | boolean;
90
+ };
91
+ })[];
92
+ } | {
93
+ status: "DOWN";
94
+ checks: ({
95
+ name: string;
96
+ status: "DOWN" | "UP";
97
+ data?: undefined;
98
+ } | {
99
+ name: string;
100
+ status: "DOWN" | "UP";
101
+ data: {
102
+ readonly [x: string]: string | number | boolean;
103
+ };
104
+ })[];
105
+ }, never, never>;
106
+ started: () => Effect.Effect<{
107
+ status: "UP";
108
+ checks: ({
109
+ name: string;
110
+ status: "DOWN" | "UP";
111
+ data?: undefined;
112
+ } | {
113
+ name: string;
114
+ status: "DOWN" | "UP";
115
+ data: {
116
+ readonly [x: string]: string | number | boolean;
117
+ };
118
+ })[];
119
+ } | {
120
+ status: "DOWN";
121
+ checks: ({
122
+ name: string;
123
+ status: "DOWN" | "UP";
124
+ data?: undefined;
125
+ } | {
126
+ name: string;
127
+ status: "DOWN" | "UP";
128
+ data: {
129
+ readonly [x: string]: string | number | boolean;
130
+ };
131
+ })[];
132
+ }, never, never>;
133
+ }> & {
134
+ readonly make: Effect.Effect<{
135
+ aggregate: () => Effect.Effect<{
136
+ status: "UP";
137
+ checks: ({
138
+ name: string;
139
+ status: "DOWN" | "UP";
140
+ data?: undefined;
141
+ } | {
142
+ name: string;
143
+ status: "DOWN" | "UP";
144
+ data: {
145
+ readonly [x: string]: string | number | boolean;
146
+ };
147
+ })[];
148
+ } | {
149
+ status: "DOWN";
150
+ checks: ({
151
+ name: string;
152
+ status: "DOWN" | "UP";
153
+ data?: undefined;
154
+ } | {
155
+ name: string;
156
+ status: "DOWN" | "UP";
157
+ data: {
158
+ readonly [x: string]: string | number | boolean;
159
+ };
160
+ })[];
161
+ }, never, never>;
162
+ live: () => Effect.Effect<{
163
+ status: "UP";
164
+ checks: ({
165
+ name: string;
166
+ status: "DOWN" | "UP";
167
+ data?: undefined;
168
+ } | {
169
+ name: string;
170
+ status: "DOWN" | "UP";
171
+ data: {
172
+ readonly [x: string]: string | number | boolean;
173
+ };
174
+ })[];
175
+ } | {
176
+ status: "DOWN";
177
+ checks: ({
178
+ name: string;
179
+ status: "DOWN" | "UP";
180
+ data?: undefined;
181
+ } | {
182
+ name: string;
183
+ status: "DOWN" | "UP";
184
+ data: {
185
+ readonly [x: string]: string | number | boolean;
186
+ };
187
+ })[];
188
+ }, never, never>;
189
+ ready: () => Effect.Effect<{
190
+ status: "UP";
191
+ checks: ({
192
+ name: string;
193
+ status: "DOWN" | "UP";
194
+ data?: undefined;
195
+ } | {
196
+ name: string;
197
+ status: "DOWN" | "UP";
198
+ data: {
199
+ readonly [x: string]: string | number | boolean;
200
+ };
201
+ })[];
202
+ } | {
203
+ status: "DOWN";
204
+ checks: ({
205
+ name: string;
206
+ status: "DOWN" | "UP";
207
+ data?: undefined;
208
+ } | {
209
+ name: string;
210
+ status: "DOWN" | "UP";
211
+ data: {
212
+ readonly [x: string]: string | number | boolean;
213
+ };
214
+ })[];
215
+ }, never, never>;
216
+ started: () => Effect.Effect<{
217
+ status: "UP";
218
+ checks: ({
219
+ name: string;
220
+ status: "DOWN" | "UP";
221
+ data?: undefined;
222
+ } | {
223
+ name: string;
224
+ status: "DOWN" | "UP";
225
+ data: {
226
+ readonly [x: string]: string | number | boolean;
227
+ };
228
+ })[];
229
+ } | {
230
+ status: "DOWN";
231
+ checks: ({
232
+ name: string;
233
+ status: "DOWN" | "UP";
234
+ data?: undefined;
235
+ } | {
236
+ name: string;
237
+ status: "DOWN" | "UP";
238
+ data: {
239
+ readonly [x: string]: string | number | boolean;
240
+ };
241
+ })[];
242
+ }, never, never>;
243
+ }, never, HealthServiceConfig>;
244
+ };
245
+ export declare class HealthService extends HealthService_base {
246
+ static readonly up: (data?: HealthCheckData) => HealthCheckOutcome;
247
+ static readonly down: (data?: HealthCheckData) => HealthCheckOutcome;
248
+ static readonly layer: Layer.Layer<HealthService, never, never>;
249
+ static readonly layerWith: <Requirements = never>(options: HealthServiceOptions<Requirements>) => Layer.Layer<HealthService, never, Exclude<Requirements, import("effect/Scope").Scope>>;
250
+ }
251
+ export * from "./api.builder.js";
252
+ export * from "./api.group.js";
253
+ export * from "./schema.js";
@@ -0,0 +1,186 @@
1
+ // ../../src/services/health/index.ts
2
+ import { Context, Effect as Effect2, Exit, Layer } from "effect";
3
+
4
+ // ../../src/services/health/api.builder.ts
5
+ import { Effect } from "effect";
6
+ var respond = (check) => check.pipe(Effect.flatMap((response) => response.status === "UP" ? Effect.succeed(response) : Effect.fail(response)));
7
+ var healthHandler = (handlers) => handlers.handle("getHealth", () => Effect.flatMap(HealthService, ({ aggregate }) => respond(aggregate()))).handle("getLiveness", () => Effect.flatMap(HealthService, ({ live }) => respond(live()))).handle("getReadiness", () => Effect.flatMap(HealthService, ({ ready }) => respond(ready()))).handle("getStartup", () => Effect.flatMap(HealthService, ({ started }) => respond(started())));
8
+ // ../../src/services/health/api.group.ts
9
+ import {
10
+ HttpApiEndpoint,
11
+ HttpApiError,
12
+ HttpApiGroup,
13
+ OpenApi
14
+ } from "effect/unstable/httpapi";
15
+
16
+ // ../../src/services/health/schema.ts
17
+ import { Schema } from "effect";
18
+ import { HttpApiSchema } from "effect/unstable/httpapi";
19
+ var HealthStatus = Schema.Literals(["UP", "DOWN"]).annotate({
20
+ identifier: "HealthStatus",
21
+ title: "Health Status",
22
+ description: "Whether a health check is up or down"
23
+ });
24
+ var HealthCheckData = Schema.Record(Schema.String, Schema.Union([Schema.String, Schema.Boolean, Schema.Number])).annotate({
25
+ identifier: "HealthCheckData",
26
+ title: "Health Check Data",
27
+ description: "Non-sensitive diagnostic values for a health check"
28
+ });
29
+ var HealthCheckOutcome = Schema.Struct({
30
+ status: HealthStatus,
31
+ data: Schema.optionalKey(HealthCheckData)
32
+ }).annotate({
33
+ identifier: "HealthCheckOutcome",
34
+ title: "Health Check Outcome",
35
+ description: "The status and optional diagnostic data returned by a check"
36
+ });
37
+ var HealthCheckResult = Schema.Struct({
38
+ name: Schema.NonEmptyString,
39
+ status: HealthStatus,
40
+ data: Schema.optionalKey(HealthCheckData)
41
+ }).annotate({
42
+ identifier: "HealthCheckResult",
43
+ title: "Health Check Result",
44
+ description: "The outcome of a named health check"
45
+ });
46
+ var HealthUpResponse = Schema.Struct({
47
+ status: Schema.Literal("UP"),
48
+ checks: Schema.Array(HealthCheckResult)
49
+ }).annotate({
50
+ identifier: "HealthUpResponse",
51
+ title: "Healthy Response",
52
+ description: "A response where all health checks are up",
53
+ examples: [{ status: "UP", checks: [] }]
54
+ });
55
+ var HealthDownResponse = Schema.Struct({
56
+ status: Schema.Literal("DOWN"),
57
+ checks: Schema.Array(HealthCheckResult)
58
+ }).pipe(HttpApiSchema.status(503)).annotate({
59
+ identifier: "HealthDownResponse",
60
+ title: "Unhealthy Response",
61
+ description: "A response where one or more health checks are down",
62
+ examples: [
63
+ {
64
+ status: "DOWN",
65
+ checks: [{ name: "database", status: "DOWN" }]
66
+ }
67
+ ]
68
+ });
69
+ var HealthResponse = Schema.Union([
70
+ HealthUpResponse,
71
+ HealthDownResponse
72
+ ]).annotate({
73
+ identifier: "HealthResponse",
74
+ title: "Health Response",
75
+ description: "An aggregate health response"
76
+ });
77
+
78
+ // ../../src/services/health/api.group.ts
79
+ var errors = [HealthDownResponse, HttpApiError.InternalServerError];
80
+ var HealthApiGroup = HttpApiGroup.make("health").annotateMerge(OpenApi.annotations({
81
+ title: "Health",
82
+ description: "Application health checks"
83
+ })).add(HttpApiEndpoint.get("getHealth", "/health", {
84
+ success: HealthUpResponse,
85
+ error: errors
86
+ }).annotateMerge(OpenApi.annotations({
87
+ summary: "Get aggregate health",
88
+ description: "Runs all registered liveness, readiness, and startup checks."
89
+ }))).add(HttpApiEndpoint.get("getLiveness", "/health/live", {
90
+ success: HealthUpResponse,
91
+ error: errors
92
+ }).annotateMerge(OpenApi.annotations({
93
+ summary: "Get application liveness",
94
+ description: "Returns whether the application process is responsive."
95
+ }))).add(HttpApiEndpoint.get("getReadiness", "/health/ready", {
96
+ success: HealthUpResponse,
97
+ error: errors
98
+ }).annotateMerge(OpenApi.annotations({
99
+ summary: "Get application readiness",
100
+ description: "Returns whether the application is ready to serve traffic."
101
+ }))).add(HttpApiEndpoint.get("getStartup", "/health/started", {
102
+ success: HealthUpResponse,
103
+ error: errors
104
+ }).annotateMerge(OpenApi.annotations({
105
+ summary: "Get application startup status",
106
+ description: "Returns whether the application has completed startup."
107
+ })));
108
+
109
+ // ../../src/services/health/index.ts
110
+ class HealthServiceConfig extends Context.Service()("@krak-stack/registry/HealthServiceConfig") {
111
+ static layerWith = ({
112
+ checks = {}
113
+ } = {}) => Layer.effect(this, Effect2.gen(function* () {
114
+ const services = yield* Effect2.context();
115
+ const resolve = (registered) => (registered ?? []).map(({ name, check }) => ({
116
+ name,
117
+ check: Effect2.provide(check, services)
118
+ }));
119
+ return {
120
+ live: resolve(checks.live),
121
+ ready: resolve(checks.ready),
122
+ started: resolve(checks.started)
123
+ };
124
+ }));
125
+ }
126
+
127
+ class HealthService extends Context.Service()("@krak-stack/registry/HealthService", {
128
+ make: Effect2.gen(function* () {
129
+ const checks = yield* HealthServiceConfig;
130
+ const allChecks = Array.from(new Set([...checks.live, ...checks.ready, ...checks.started]));
131
+ const execute = Effect2.fn("HealthService.execute")(function* (healthCheck) {
132
+ const exit = yield* Effect2.exit(healthCheck.check);
133
+ if (!Exit.isSuccess(exit)) {
134
+ return {
135
+ name: healthCheck.name,
136
+ status: "DOWN"
137
+ };
138
+ }
139
+ return exit.value.data === undefined ? {
140
+ name: healthCheck.name,
141
+ status: exit.value.status
142
+ } : {
143
+ name: healthCheck.name,
144
+ status: exit.value.status,
145
+ data: exit.value.data
146
+ };
147
+ });
148
+ const run = Effect2.fn("HealthService.run")(function* (registered) {
149
+ const results = yield* Effect2.forEach(registered, execute, {
150
+ concurrency: "unbounded"
151
+ });
152
+ if (results.every(({ status }) => status === "UP")) {
153
+ return {
154
+ status: "UP",
155
+ checks: results
156
+ };
157
+ }
158
+ return {
159
+ status: "DOWN",
160
+ checks: results
161
+ };
162
+ });
163
+ const aggregate = Effect2.fn("HealthService.aggregate")(() => run(allChecks));
164
+ const live = Effect2.fn("HealthService.live")(() => run(checks.live));
165
+ const ready = Effect2.fn("HealthService.ready")(() => run(checks.ready));
166
+ const started = Effect2.fn("HealthService.started")(() => run(checks.started));
167
+ return { aggregate, live, ready, started };
168
+ })
169
+ }) {
170
+ static up = (data) => data === undefined ? { status: "UP" } : { status: "UP", data };
171
+ static down = (data) => data === undefined ? { status: "DOWN" } : { status: "DOWN", data };
172
+ static layer = Layer.effect(this, this.make).pipe(Layer.provide(HealthServiceConfig.layerWith()));
173
+ static layerWith = (options) => Layer.effect(this, this.make).pipe(Layer.provide(HealthServiceConfig.layerWith(options)));
174
+ }
175
+ export {
176
+ healthHandler,
177
+ HealthUpResponse,
178
+ HealthStatus,
179
+ HealthService,
180
+ HealthResponse,
181
+ HealthDownResponse,
182
+ HealthCheckResult,
183
+ HealthCheckOutcome,
184
+ HealthCheckData,
185
+ HealthApiGroup
186
+ };
@@ -0,0 +1,50 @@
1
+ import { Schema } from "effect";
2
+ export declare const HealthStatus: Schema.Literals<readonly ["UP", "DOWN"]>;
3
+ export type HealthStatus = typeof HealthStatus.Type;
4
+ export declare const HealthCheckData: Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.Number]>>;
5
+ export type HealthCheckData = typeof HealthCheckData.Type;
6
+ export declare const HealthCheckOutcome: Schema.Struct<{
7
+ readonly status: Schema.Literals<readonly ["UP", "DOWN"]>;
8
+ readonly data: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.Number]>>>;
9
+ }>;
10
+ export type HealthCheckOutcome = typeof HealthCheckOutcome.Type;
11
+ export declare const HealthCheckResult: Schema.Struct<{
12
+ readonly name: Schema.NonEmptyString;
13
+ readonly status: Schema.Literals<readonly ["UP", "DOWN"]>;
14
+ readonly data: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.Number]>>>;
15
+ }>;
16
+ export type HealthCheckResult = typeof HealthCheckResult.Type;
17
+ export declare const HealthUpResponse: Schema.Struct<{
18
+ readonly status: Schema.Literal<"UP">;
19
+ readonly checks: Schema.$Array<Schema.Struct<{
20
+ readonly name: Schema.NonEmptyString;
21
+ readonly status: Schema.Literals<readonly ["UP", "DOWN"]>;
22
+ readonly data: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.Number]>>>;
23
+ }>>;
24
+ }>;
25
+ export type HealthUpResponse = typeof HealthUpResponse.Type;
26
+ export declare const HealthDownResponse: Schema.Struct<{
27
+ readonly status: Schema.Literal<"DOWN">;
28
+ readonly checks: Schema.$Array<Schema.Struct<{
29
+ readonly name: Schema.NonEmptyString;
30
+ readonly status: Schema.Literals<readonly ["UP", "DOWN"]>;
31
+ readonly data: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.Number]>>>;
32
+ }>>;
33
+ }>;
34
+ export type HealthDownResponse = typeof HealthDownResponse.Type;
35
+ export declare const HealthResponse: Schema.Union<readonly [Schema.Struct<{
36
+ readonly status: Schema.Literal<"UP">;
37
+ readonly checks: Schema.$Array<Schema.Struct<{
38
+ readonly name: Schema.NonEmptyString;
39
+ readonly status: Schema.Literals<readonly ["UP", "DOWN"]>;
40
+ readonly data: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.Number]>>>;
41
+ }>>;
42
+ }>, Schema.Struct<{
43
+ readonly status: Schema.Literal<"DOWN">;
44
+ readonly checks: Schema.$Array<Schema.Struct<{
45
+ readonly name: Schema.NonEmptyString;
46
+ readonly status: Schema.Literals<readonly ["UP", "DOWN"]>;
47
+ readonly data: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.Number]>>>;
48
+ }>>;
49
+ }>]>;
50
+ export type HealthResponse = typeof HealthResponse.Type;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krak-stack/registry",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "Tree-shakable KrakStack components and Effect services.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -199,6 +199,10 @@
199
199
  "types": "./dist/services/file-extraction/schema.d.ts",
200
200
  "import": "./dist/services/file-extraction/schema.js"
201
201
  },
202
+ "./service-health": {
203
+ "types": "./dist/services/health/index.d.ts",
204
+ "import": "./dist/services/health/index.js"
205
+ },
202
206
  "./tailwind.css": "./tailwind.css",
203
207
  "./package.json": "./package.json"
204
208
  },