@ontemper/sdk 0.0.0 → 0.2.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 (98) hide show
  1. package/README.md +221 -2
  2. package/dist/AxiosError.d.ts +46 -0
  3. package/dist/AxiosError.d.ts.map +1 -0
  4. package/dist/AxiosError.js +118 -0
  5. package/dist/AxiosError.js.map +1 -0
  6. package/dist/Contract/Invocation.d.ts +21 -0
  7. package/dist/Contract/Invocation.d.ts.map +1 -0
  8. package/dist/Contract/Invocation.js +2 -0
  9. package/dist/Contract/Invocation.js.map +1 -0
  10. package/dist/Contract/Manifest.d.ts +125 -0
  11. package/dist/Contract/Manifest.d.ts.map +1 -0
  12. package/dist/Contract/Manifest.js +59 -0
  13. package/dist/Contract/Manifest.js.map +1 -0
  14. package/dist/Contract/RuntimeApi.d.ts +143 -0
  15. package/dist/Contract/RuntimeApi.d.ts.map +1 -0
  16. package/dist/Contract/RuntimeApi.js +148 -0
  17. package/dist/Contract/RuntimeApi.js.map +1 -0
  18. package/dist/Contract/index.d.ts +4 -0
  19. package/dist/Contract/index.d.ts.map +1 -0
  20. package/dist/Contract/index.js +3 -0
  21. package/dist/Contract/index.js.map +1 -0
  22. package/dist/Correlation.d.ts +33 -0
  23. package/dist/Correlation.d.ts.map +1 -0
  24. package/dist/Correlation.js +57 -0
  25. package/dist/Correlation.js.map +1 -0
  26. package/dist/HttpApiResource.d.ts +32 -0
  27. package/dist/HttpApiResource.d.ts.map +1 -0
  28. package/dist/HttpApiResource.js +35 -0
  29. package/dist/HttpApiResource.js.map +1 -0
  30. package/dist/HttpClient.d.ts +10 -0
  31. package/dist/HttpClient.d.ts.map +1 -0
  32. package/dist/HttpClient.js +167 -0
  33. package/dist/HttpClient.js.map +1 -0
  34. package/dist/HttpPayload.d.ts +9 -0
  35. package/dist/HttpPayload.d.ts.map +1 -0
  36. package/dist/HttpPayload.js +32 -0
  37. package/dist/HttpPayload.js.map +1 -0
  38. package/dist/Invocation.d.ts +7 -0
  39. package/dist/Invocation.d.ts.map +1 -0
  40. package/dist/Invocation.js +4 -0
  41. package/dist/Invocation.js.map +1 -0
  42. package/dist/LogContext.d.ts +59 -0
  43. package/dist/LogContext.d.ts.map +1 -0
  44. package/dist/LogContext.js +47 -0
  45. package/dist/LogContext.js.map +1 -0
  46. package/dist/Logger.d.ts +5 -0
  47. package/dist/Logger.d.ts.map +1 -0
  48. package/dist/Logger.js +314 -0
  49. package/dist/Logger.js.map +1 -0
  50. package/dist/Manifest.d.ts +8 -0
  51. package/dist/Manifest.d.ts.map +1 -0
  52. package/dist/Manifest.js +101 -0
  53. package/dist/Manifest.js.map +1 -0
  54. package/dist/Middleware.d.ts +13 -0
  55. package/dist/Middleware.d.ts.map +1 -0
  56. package/dist/Middleware.js +287 -0
  57. package/dist/Middleware.js.map +1 -0
  58. package/dist/Redaction.d.ts +27 -0
  59. package/dist/Redaction.d.ts.map +1 -0
  60. package/dist/Redaction.js +149 -0
  61. package/dist/Redaction.js.map +1 -0
  62. package/dist/Resource.d.ts +66 -0
  63. package/dist/Resource.d.ts.map +1 -0
  64. package/dist/Resource.js +57 -0
  65. package/dist/Resource.js.map +1 -0
  66. package/dist/ResourcesErrors.d.ts +36 -0
  67. package/dist/ResourcesErrors.d.ts.map +1 -0
  68. package/dist/ResourcesErrors.js +27 -0
  69. package/dist/ResourcesErrors.js.map +1 -0
  70. package/dist/ResourcesToken.d.ts +10 -0
  71. package/dist/ResourcesToken.d.ts.map +1 -0
  72. package/dist/ResourcesToken.js +63 -0
  73. package/dist/ResourcesToken.js.map +1 -0
  74. package/dist/RuntimeResources.d.ts +26 -0
  75. package/dist/RuntimeResources.d.ts.map +1 -0
  76. package/dist/RuntimeResources.js +115 -0
  77. package/dist/RuntimeResources.js.map +1 -0
  78. package/dist/Trigger.d.ts +17 -0
  79. package/dist/Trigger.d.ts.map +1 -0
  80. package/dist/Trigger.js +4 -0
  81. package/dist/Trigger.js.map +1 -0
  82. package/dist/Workflow.d.ts +36 -0
  83. package/dist/Workflow.d.ts.map +1 -0
  84. package/dist/Workflow.js +80 -0
  85. package/dist/Workflow.js.map +1 -0
  86. package/dist/cli.d.ts +3 -0
  87. package/dist/cli.d.ts.map +1 -0
  88. package/dist/cli.js +447 -0
  89. package/dist/cli.js.map +1 -0
  90. package/dist/index.d.ts +17 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +16 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/testing.d.ts +42 -0
  95. package/dist/testing.d.ts.map +1 -0
  96. package/dist/testing.js +49 -0
  97. package/dist/testing.js.map +1 -0
  98. package/package.json +57 -5
@@ -0,0 +1,287 @@
1
+ import { Cause, Clock, Context, Duration, Effect, Exit, Option, Predicate, Schema } from 'effect';
2
+ import { Headers, HttpRouter, HttpServerError, HttpServerRequest, HttpServerResponse } from 'effect/unstable/http';
3
+ import { bodyOf, formDataFields, safeJsonParse } from './HttpPayload.js';
4
+ import { Invocation } from './Invocation.js';
5
+ import { CurrentLogContext, logSpan, TRACE_HEADER } from './LogContext.js';
6
+ class InvocationDeadlineExceeded extends Schema.TaggedError()('InvocationDeadlineExceeded', { runId: Schema.String, executionId: Schema.String, deadline: Schema.String, message: Schema.String }) {
7
+ }
8
+ /**
9
+ * Legacy unnbound-events `ServerError` (sdk/events/src/lib/error.ts). It stays a plain `Error` so it
10
+ * logs as the legacy pino `err`: `{ type, message, stack, status, name }`.
11
+ */
12
+ class ServerError extends Error {
13
+ status;
14
+ constructor(status, message, options) {
15
+ super(message, options);
16
+ // `status` before `name`: the order pino serialized the legacy own fields in.
17
+ this.status = status;
18
+ this.name = 'ServerError';
19
+ }
20
+ }
21
+ const MESSAGE_HEADER = 'x-message-id';
22
+ /** Legacy `readBody` ceiling (sdk/events/src/lib/utils.ts:63-106), matched to the ingress limit. */
23
+ const MAX_REQUEST_BODY_BYTES = 100 * 1024 * 1024;
24
+ /** The Run trace id of a W3C `traceparent`, as the gateway records it in `run_events.trace_id`. */
25
+ const traceIdOf = (traceparent) => {
26
+ const traceId = traceparent === undefined ? undefined : /^00-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/.exec(traceparent)?.[1];
27
+ return traceId === undefined || /^0+$/.test(traceId) ? undefined : traceId;
28
+ };
29
+ const headerOf = (headers, name) => {
30
+ const value = headers[name];
31
+ return value === undefined || value === '' ? undefined : value;
32
+ };
33
+ /**
34
+ * Legacy `readBody`: the whole body, rejected with 413 when its declared or streamed length passes
35
+ * the ceiling and with 400 when the stream fails. It reads a clone, so the handler still reads the body.
36
+ */
37
+ const readBody = (source, declaredLength) => {
38
+ const declared = Number(declaredLength ?? Number.NaN);
39
+ if (Number.isFinite(declared) && declared > MAX_REQUEST_BODY_BYTES) {
40
+ return Effect.fail(new ServerError(413, 'Request body too large.'));
41
+ }
42
+ const stream = source.clone().body;
43
+ if (stream === null)
44
+ return Effect.succeed(new Uint8Array());
45
+ return Effect.acquireUseRelease(Effect.sync(() => stream.getReader()), (reader) => Effect.gen(function* () {
46
+ const chunks = [];
47
+ let total = 0;
48
+ while (true) {
49
+ const next = yield* Effect.tryPromise({
50
+ try: () => reader.read(),
51
+ catch: (cause) => new ServerError(400, 'Failed to read request body.', { cause }),
52
+ });
53
+ if (next.done)
54
+ break;
55
+ total += next.value.byteLength;
56
+ if (total > MAX_REQUEST_BODY_BYTES)
57
+ return yield* Effect.fail(new ServerError(413, 'Request body too large.'));
58
+ chunks.push(next.value);
59
+ }
60
+ const bytes = new Uint8Array(total);
61
+ let offset = 0;
62
+ for (const chunk of chunks) {
63
+ bytes.set(chunk, offset);
64
+ offset += chunk.byteLength;
65
+ }
66
+ return bytes;
67
+ }), (reader, exit) => Effect.sync(() => {
68
+ if (Exit.isSuccess(exit))
69
+ return reader.releaseLock();
70
+ // A tee branch's cancel settles only when the handler's branch is cancelled too, so it is not awaited.
71
+ reader.cancel().catch(() => undefined);
72
+ }));
73
+ };
74
+ const decoder = new TextDecoder();
75
+ /** unnbound-events 2.0 `parseBody` by content type; anything else was logged as its `ArrayBuffer`, `{}`. */
76
+ const loggedBodyOf = (bytes, contentType) => {
77
+ if (contentType.includes('application/json')) {
78
+ const text = decoder.decode(bytes);
79
+ // Hono's `req.json()` rejected invalid JSON, and legacy then logged no body.
80
+ return Effect.try(() => JSON.parse(text)).pipe(Effect.orElseSucceed(() => undefined));
81
+ }
82
+ if (contentType.includes('application/x-www-form-urlencoded') || contentType.includes('multipart/form-data')) {
83
+ return Effect.tryPromise(() => new Response(bytes, { headers: { 'content-type': contentType } }).formData()).pipe(Effect.map(formDataFields), Effect.orElseSucceed(() => undefined));
84
+ }
85
+ if (contentType.includes('text/plain'))
86
+ return Effect.succeed(safeJsonParse(decoder.decode(bytes)));
87
+ return Effect.succeed({});
88
+ };
89
+ /** unnbound-events 2.0 `buildIncomingPayload` before a response exists (sdk/events/src/lib/utils.ts:278-306). */
90
+ const incomingOf = (request, params) => {
91
+ const source = request.source;
92
+ const body = source instanceof Request
93
+ ? Effect.flatMap(readBody(source, request.headers['content-length']), (bytes) => loggedBodyOf(bytes, headerOf(request.headers, 'content-type') ?? ''))
94
+ : Effect.succeed(undefined);
95
+ return Effect.map(body, (body) => {
96
+ const url = new URL(request.originalUrl, 'https://unnbound.ai');
97
+ // Hono `query()` keeps the first value of a repeated key.
98
+ const query = {};
99
+ for (const [key, value] of url.searchParams)
100
+ query[key] ??= value;
101
+ const ip = headerOf(request.headers, 'cf-connecting-ip') ??
102
+ headerOf(request.headers, 'x-forwarded-for') ??
103
+ headerOf(request.headers, 'x-real-ip');
104
+ return {
105
+ type: 'http',
106
+ source: 'http',
107
+ http: {
108
+ url: url.toString(),
109
+ method: request.method.toLowerCase(),
110
+ query,
111
+ params,
112
+ // Legacy `normalizeIp`: an IPv4-mapped IPv6 address logs as IPv4.
113
+ ip: ip?.startsWith('::ffff:') ? ip.slice(7) : ip,
114
+ incoming: true,
115
+ request: { headers: { ...request.headers }, body },
116
+ },
117
+ };
118
+ });
119
+ };
120
+ /**
121
+ * Legacy logged the declared response headers, with a JSON content type only over a body
122
+ * (sdk/events/src/lib/utils.ts:238-260); 204, 205, and 304 log no body. Effect derives
123
+ * `content-type` and `content-length` from the body, so those are not declared.
124
+ */
125
+ const responseOf = ({ body, headers, status }) => {
126
+ const logged = status === 204 || status === 205 || status === 304 ? undefined : bodyOf(body);
127
+ const declared = { ...Headers.removeMany(headers, ['content-type', 'content-length']) };
128
+ if (!Predicate.isTruthy(logged))
129
+ return { status, headers: declared, body: undefined };
130
+ const contentType = headerOf(headers, 'content-type');
131
+ return {
132
+ status,
133
+ headers: {
134
+ 'content-type': contentType === undefined || contentType.startsWith('application/json')
135
+ ? 'application/json; charset=utf-8'
136
+ : contentType,
137
+ ...declared,
138
+ },
139
+ body: logged,
140
+ };
141
+ };
142
+ const isRouteNotFound = (cause) => {
143
+ const error = Cause.squash(cause);
144
+ return HttpServerError.isHttpServerError(error) && error.reason._tag === 'RouteNotFound';
145
+ };
146
+ const deadlineOutcome = (error) => {
147
+ const body = {
148
+ _tag: error._tag,
149
+ runId: error.runId,
150
+ executionId: error.executionId,
151
+ deadline: error.deadline,
152
+ };
153
+ return {
154
+ response: HttpServerResponse.jsonUnsafe(body, { status: 504 }),
155
+ failure: { error, message: 'workflow.invocation_deadline_exceeded' },
156
+ };
157
+ };
158
+ /** Legacy `onError` for a `ServerError`: its status and `{ message }`, logged as its cause when it has one. */
159
+ const serverErrorOutcome = (error) => ({
160
+ response: HttpServerResponse.jsonUnsafe({ message: error.message }, { status: error.status }),
161
+ failure: { error: error.cause instanceof Error ? error.cause : error, message: error.message, untraced: true },
162
+ });
163
+ /**
164
+ * Legacy unnbound-events `onError`: a response Effect derives from the cause (declared HTTP errors)
165
+ * is kept, anything else answers `500 {"message":"Internal server error"}`.
166
+ */
167
+ const failureOutcome = (cause) => {
168
+ // Nobody awaits an interrupted request; the interruption propagates.
169
+ if (Cause.hasInterruptsOnly(cause))
170
+ return Effect.failCause(Cause.fromReasons(cause.reasons.filter(Cause.isInterruptReason)));
171
+ const error = Cause.squash(cause);
172
+ if (error instanceof InvocationDeadlineExceeded)
173
+ return Effect.succeed(deadlineOutcome(error));
174
+ if (isRouteNotFound(cause))
175
+ return Effect.succeed(serverErrorOutcome(new ServerError(404, 'Endpoint not found.')));
176
+ return Effect.map(HttpServerError.causeResponse(cause), ([response]) => response.status === 500 && response.body._tag === 'Empty'
177
+ ? {
178
+ response: HttpServerResponse.jsonUnsafe({ message: 'Internal server error' }, { status: 500 }),
179
+ failure: { error, message: 'Internal server error' },
180
+ }
181
+ : {
182
+ response,
183
+ failure: {
184
+ error,
185
+ message: Predicate.hasProperty(error, 'message') && Predicate.isString(error.message)
186
+ ? error.message
187
+ : String(error),
188
+ },
189
+ });
190
+ };
191
+ /**
192
+ * The SDK ends a request this long before `InvocationContext.deadline`, so its finalizers run and its
193
+ * 504 is written before the host's own timer, which stays only the backstop.
194
+ */
195
+ const DEADLINE_MARGIN_MS = 2_000;
196
+ /** The fiber is interrupted, finalizers included, at the deadline less the margin; at once when less remains. */
197
+ const withDeadline = (invocation) => (effect) => {
198
+ if (!Number.isFinite(invocation.deadline))
199
+ return effect;
200
+ const exceeded = () => Effect.fail(new InvocationDeadlineExceeded({
201
+ runId: invocation.runId,
202
+ executionId: invocation.executionId,
203
+ deadline: new Date(invocation.deadline).toISOString(),
204
+ message: 'Invocation deadline exceeded.',
205
+ }));
206
+ return Effect.flatMap(Clock.currentTimeMillis, (now) => {
207
+ const remaining = invocation.deadline - DEADLINE_MARGIN_MS - now;
208
+ return remaining > 0
209
+ ? Effect.timeoutOrElse(effect, { duration: Duration.millis(remaining), orElse: exceeded })
210
+ : exceeded();
211
+ });
212
+ };
213
+ /**
214
+ * One request as legacy unnbound-events served it (sdk/events/src/lib/routing/endpoint.ts): the
215
+ * body read under the invocation deadline and the 100 MiB ceiling, an `Event request` span under the
216
+ * caller's trace, the `onError` line for a failed handler, and the trace and message ids echoed on the
217
+ * response (routing/response.ts:31-41) unless the message id is empty or the request never reached a route.
218
+ */
219
+ const serveEventRequest = (handler) => Effect.withFiber((fiber) => {
220
+ // The SDK installs both services on every request context before routing.
221
+ const request = Context.getUnsafe(fiber.context, HttpServerRequest.HttpServerRequest);
222
+ const invocation = Context.getUnsafe(fiber.context, Invocation);
223
+ const routeParams = Context.getOrUndefined(fiber.context, HttpRouter.RouteContext)?.params ?? {};
224
+ // Hono's `:param` never matched an empty segment, so such a request met legacy `notFound`.
225
+ const unmatched = Object.values(routeParams).includes('');
226
+ const run = unmatched
227
+ ? Effect.fail(new HttpServerError.HttpServerError({ reason: new HttpServerError.RouteNotFound({ request }) }))
228
+ : handler;
229
+ // An empty trace header counts as absent (`||`), an empty message id as present (`??`), as in legacy.
230
+ const traceId = headerOf(request.headers, TRACE_HEADER) ??
231
+ traceIdOf(headerOf(request.headers, 'traceparent')) ??
232
+ traceIdOf(headerOf(request.headers, 'x-traceparent')) ??
233
+ crypto.randomUUID();
234
+ const inboundMessageId = request.headers[MESSAGE_HEADER];
235
+ const messageId = inboundMessageId ?? crypto.randomUUID();
236
+ // Legacy echoed both ids only when both were non-empty.
237
+ const echo = (response) => messageId === ''
238
+ ? response
239
+ : HttpServerResponse.setHeaders(response, {
240
+ [TRACE_HEADER]: response.headers[TRACE_HEADER] ?? traceId,
241
+ [MESSAGE_HEADER]: response.headers[MESSAGE_HEADER] ?? messageId,
242
+ });
243
+ // Hono's compose ran `notFound`, and the body read, outside its try, so `onError` caught them past the trace middleware.
244
+ const untracedFailure = (outcome) => outcome.failure === undefined
245
+ ? Effect.succeed(outcome.response)
246
+ : Effect.logError(outcome.failure.message, { err: outcome.failure.error }).pipe(Effect.provideService(CurrentLogContext, undefined), Effect.as(outcome.response));
247
+ return Effect.gen(function* () {
248
+ const incoming = yield* incomingOf(request, unmatched ? {} : routeParams).pipe(withDeadline(invocation));
249
+ const outcome = yield* run.pipe(withDeadline(invocation), Effect.matchCauseEffect({
250
+ onFailure: failureOutcome,
251
+ onSuccess: (response) => Effect.succeed({ response }),
252
+ }), logSpan('Event request', {
253
+ fields: (exit) => exit === undefined || Exit.isFailure(exit)
254
+ ? incoming
255
+ : { ...incoming, http: { ...incoming.http, response: responseOf(exit.value.response) } },
256
+ failure: (exit) => {
257
+ if (Exit.isFailure(exit))
258
+ return Option.some(Cause.squash(exit.cause));
259
+ return exit.value.failure === undefined ? Option.none() : Option.some(exit.value.failure.error);
260
+ },
261
+ }));
262
+ const failure = outcome.failure;
263
+ if (failure?.untraced === true)
264
+ return yield* untracedFailure(outcome);
265
+ if (failure !== undefined)
266
+ yield* Effect.logError(failure.message, { err: failure.error });
267
+ return echo(outcome.response);
268
+ }).pipe(Effect.catch((error) => error instanceof InvocationDeadlineExceeded
269
+ ? Effect.logError('workflow.invocation_deadline_exceeded', { err: error }).pipe(Effect.as(echo(deadlineOutcome(error).response)))
270
+ : untracedFailure(serverErrorOutcome(error))), Effect.provideService(CurrentLogContext, {
271
+ traceId,
272
+ messageId,
273
+ messageIdMinted: inboundMessageId === undefined,
274
+ source: 'http',
275
+ }), Effect.annotateLogs({
276
+ runId: invocation.runId,
277
+ executionId: invocation.executionId,
278
+ attempt: invocation.attempt,
279
+ triggerKind: invocation.triggerKind,
280
+ traceparent: headerOf(request.headers, 'traceparent'),
281
+ }));
282
+ });
283
+ /** Serves every API route as an `Event request`; provide it to the routes it wraps. */
284
+ export const EventRequestMiddleware = HttpRouter.middleware((effect) => serveEventRequest(effect)).layer;
285
+ /** An unmatched route answers like legacy `notFound`: `404 {"message":"Endpoint not found."}` in its own span, with no id headers. */
286
+ export const UnmatchedRequestMiddleware = HttpRouter.middleware((effect) => Effect.catchCause(effect, (cause) => isRouteNotFound(cause) ? serveEventRequest(Effect.failCause(cause)) : Effect.failCause(cause)), { global: true });
287
+ //# sourceMappingURL=Middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Middleware.js","sourceRoot":"","sources":["../src/Middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Context, type Effect } from 'effect';
2
+ import type { LogJson } from './LogContext.js';
3
+ /** Replaces a secret wherever it appears in a logged string (legacy `applyRedactionMasks`). */
4
+ export declare const REDACTED = "[Redacted]";
5
+ /**
6
+ * Legacy pino `redact` paths, widened: credential headers are removed, `err` loses every `config`, and
7
+ * a secret body key's value becomes `[Redacted]` at any depth and in form-encoded bodies, because a
8
+ * credential a partner returns (an OAuth token response) is logged before the caller can register it.
9
+ * `line` is the logger's own JSON copy.
10
+ */
11
+ export declare const redactLine: (line: {
12
+ [key: string]: LogJson;
13
+ }) => void;
14
+ /** Secret values masked out of every string a workflow logs. */
15
+ export interface SecretMasks {
16
+ readonly register: (values: Iterable<string>) => void;
17
+ readonly mask: (text: string) => string;
18
+ }
19
+ export declare const makeSecretMasks: () => SecretMasks;
20
+ /** `workflow()` installs one registry per module, so a secret seen by one request stays masked in every later one. */
21
+ export declare const SecretMasks: Context.Reference<SecretMasks>;
22
+ /**
23
+ * Masks each non-empty value, and its `encodeURIComponent` and form-urlencoded forms, as `[Redacted]`
24
+ * in every later log line of this workflow.
25
+ */
26
+ export declare const registerSecrets: (values: Iterable<string>) => Effect.Effect<void>;
27
+ //# sourceMappingURL=Redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Redaction.d.ts","sourceRoot":"","sources":["../src/Redaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,QAAQ,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,eAAe,CAAC;AAmErC;;;;;GAKG;AACH,eAAO,MAAM,UAAU,SAAU;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,KAAG,IAsB7D,CAAC;AAEF,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACtD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC;AAaD,eAAO,MAAM,eAAe,QAAO,WAoClC,CAAC;AAEF,sHAAsH;AACtH,eAAO,MAAM,WAAW,gCAEtB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAY,QAAQ,CAAC,MAAM,CAAC,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CACrB,CAAC"}
@@ -0,0 +1,149 @@
1
+ import { Context, Predicate } from 'effect';
2
+ /** Replaces a secret wherever it appears in a logged string (legacy `applyRedactionMasks`). */
3
+ export const REDACTED = '[Redacted]';
4
+ /**
5
+ * Credential headers removed from every logged `http` request and response: the legacy logger redact
6
+ * paths and the unnbound-events trace list (sdk/events/src/lib/utils.ts:190-198).
7
+ */
8
+ const secretHeaderNames = {
9
+ authorization: true,
10
+ 'proxy-authorization': true,
11
+ cookie: true,
12
+ 'set-cookie': true,
13
+ 'x-service-token': true,
14
+ 'x-api-key': true,
15
+ 'x-auth-token': true,
16
+ 'ocp-apim-subscription-key': true,
17
+ };
18
+ /** Body keys whose values are credentials, compared lowercase without `_` and `-`, so `accessToken` matches too. */
19
+ const secretBodyKeys = {
20
+ accesstoken: true,
21
+ refreshtoken: true,
22
+ idtoken: true,
23
+ clientsecret: true,
24
+ password: true,
25
+ apikey: true,
26
+ secret: true,
27
+ token: true,
28
+ };
29
+ const isSecretBodyKey = (name) => Object.hasOwn(secretBodyKeys, name.toLowerCase().replace(/[-_]/g, ''));
30
+ const maskSecretFields = (value) => {
31
+ if (Array.isArray(value))
32
+ return value.map(maskSecretFields);
33
+ if (!Predicate.isObject(value))
34
+ return value;
35
+ const masked = {};
36
+ for (const [key, item] of Object.entries(value))
37
+ masked[key] = isSecretBodyKey(key) ? REDACTED : maskSecretFields(item);
38
+ return masked;
39
+ };
40
+ const maskSecretFormFields = (body) => body
41
+ .split('&')
42
+ .map((field) => {
43
+ const separator = field.indexOf('=');
44
+ if (separator === -1)
45
+ return field;
46
+ const name = field.slice(0, separator);
47
+ let decoded = name;
48
+ try {
49
+ decoded = decodeURIComponent(name.replaceAll('+', ' '));
50
+ }
51
+ catch {
52
+ // An undecodable name is compared as sent.
53
+ }
54
+ return isSecretBodyKey(decoded) ? `${name}=${REDACTED}` : field;
55
+ })
56
+ .join('&');
57
+ /** Legacy pino removed `err.config`; an HTTP error's request config (headers, body, URL) goes at any depth. */
58
+ const withoutConfig = (value) => {
59
+ if (Array.isArray(value))
60
+ return value.map(withoutConfig);
61
+ if (!Predicate.isObject(value))
62
+ return value;
63
+ const kept = {};
64
+ for (const [key, item] of Object.entries(value))
65
+ if (key !== 'config')
66
+ kept[key] = withoutConfig(item);
67
+ return kept;
68
+ };
69
+ /**
70
+ * Legacy pino `redact` paths, widened: credential headers are removed, `err` loses every `config`, and
71
+ * a secret body key's value becomes `[Redacted]` at any depth and in form-encoded bodies, because a
72
+ * credential a partner returns (an OAuth token response) is logged before the caller can register it.
73
+ * `line` is the logger's own JSON copy.
74
+ */
75
+ export const redactLine = (line) => {
76
+ if (line.err !== undefined)
77
+ line.err = withoutConfig(line.err);
78
+ const http = line.http;
79
+ if (!Predicate.isObject(http))
80
+ return;
81
+ for (const part of [http.request, http.response]) {
82
+ if (!Predicate.isObject(part))
83
+ continue;
84
+ const headers = Predicate.isObject(part.headers) ? part.headers : undefined;
85
+ if (headers !== undefined) {
86
+ part.headers = Object.fromEntries(Object.entries(headers).filter(([name]) => !Object.hasOwn(secretHeaderNames, name.toLowerCase())));
87
+ }
88
+ // Header names are case-insensitive, and a caller may log its own `http` payload.
89
+ const contentType = Object.entries(headers ?? {}).find(([name]) => name.toLowerCase() === 'content-type')?.[1];
90
+ if (!Predicate.isString(part.body))
91
+ part.body = maskSecretFields(part.body);
92
+ else if (Predicate.isString(contentType) &&
93
+ contentType.toLowerCase().startsWith('application/x-www-form-urlencoded')) {
94
+ part.body = maskSecretFormFields(part.body);
95
+ }
96
+ }
97
+ };
98
+ /** A secret also reaches logs percent-encoded: in URLs, form bodies, and the errors that quote them. */
99
+ const encodingsOf = (value) => {
100
+ const form = new URLSearchParams([['', value]]).toString().slice(1);
101
+ try {
102
+ return [value, encodeURIComponent(value), form];
103
+ }
104
+ catch {
105
+ // A lone surrogate has no percent-encoding; the form serializer sends U+FFFD instead.
106
+ return [value, form];
107
+ }
108
+ };
109
+ export const makeSecretMasks = () => {
110
+ const values = new Set();
111
+ // Alternation tries the longest secret first at each position, as the legacy scanner did.
112
+ let pattern;
113
+ return {
114
+ register: (candidates) => {
115
+ for (const candidate of candidates) {
116
+ if (candidate.length === 0)
117
+ continue;
118
+ for (const value of encodingsOf(candidate)) {
119
+ if (values.has(value))
120
+ continue;
121
+ values.add(value);
122
+ pattern = undefined;
123
+ }
124
+ }
125
+ },
126
+ mask: (text) => {
127
+ if (values.size === 0)
128
+ return text;
129
+ pattern ??= new RegExp([...values]
130
+ .sort((left, right) => right.length - left.length)
131
+ .map((value) => value
132
+ .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
133
+ // Percent-escapes are case-insensitive on their hex digits: `%2F` and `%2f` are one byte.
134
+ .replace(/%([0-9A-Fa-f])([0-9A-Fa-f])/g, (_escape, high, low) => `%${[high, low].map((digit) => (/[0-9]/.test(digit) ? digit : `[${digit.toUpperCase()}${digit.toLowerCase()}]`)).join('')}`))
135
+ .join('|'), 'g');
136
+ return text.replace(pattern, REDACTED);
137
+ },
138
+ };
139
+ };
140
+ /** `workflow()` installs one registry per module, so a secret seen by one request stays masked in every later one. */
141
+ export const SecretMasks = Context.Reference('@temper/workflow/SecretMasks', {
142
+ defaultValue: makeSecretMasks,
143
+ });
144
+ /**
145
+ * Masks each non-empty value, and its `encodeURIComponent` and form-urlencoded forms, as `[Redacted]`
146
+ * in every later log line of this workflow.
147
+ */
148
+ export const registerSecrets = (values) => SecretMasks.useSync((masks) => masks.register(values));
149
+ //# sourceMappingURL=Redaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Redaction.js","sourceRoot":"","sources":["../src/Redaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGzD,+FAA+F;AAC/F,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAC;AAErC;;;GAGG;AACH,MAAM,iBAAiB,GAAG;IACxB,aAAa,EAAE,IAAI;IACnB,qBAAqB,EAAE,IAAI;IAC3B,MAAM,EAAE,IAAI;IACZ,YAAY,EAAE,IAAI;IAClB,iBAAiB,EAAE,IAAI;IACvB,WAAW,EAAE,IAAI;IACjB,cAAc,EAAE,IAAI;IACpB,2BAA2B,EAAE,IAAI;CACM,CAAC;AAE1C,oHAAoH;AACpH,MAAM,cAAc,GAAG;IACrB,WAAW,EAAE,IAAI;IACjB,YAAY,EAAE,IAAI;IAClB,OAAO,EAAE,IAAI;IACb,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,IAAI;IACd,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;CAC4B,CAAC;AAE1C,MAAM,eAAe,GAAG,CAAC,IAAY,EAAW,EAAE,CAChD,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEzE,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAW,EAAE;IACnD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,MAAM,MAAM,GAA+B,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzE,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,IAAY,EAAU,EAAE,CACpD,IAAI;KACD,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;IACb,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,SAAS,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACvC,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,CAAC;QACH,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;IAC7C,CAAC;IACD,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAClE,CAAC,CAAC;KACD,IAAI,CAAC,GAAG,CAAC,CAAC;AAEf,+GAA+G;AAC/G,MAAM,aAAa,GAAG,CAAC,KAAc,EAAW,EAAE;IAChD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC1D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,MAAM,IAAI,GAA+B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,GAAG,KAAK,QAAQ;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACvG,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAgC,EAAQ,EAAE;IACnE,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;QAAE,IAAI,CAAC,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO;IACtC,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QACxC,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,WAAW,CAC/B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAClG,CAAC;QACJ,CAAC;QACD,kFAAkF;QAClF,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/G,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACvE,IACH,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC/B,WAAW,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,mCAAmC,CAAC,EACzE,CAAC;YACD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAQF,wGAAwG;AACxG,MAAM,WAAW,GAAG,CAAC,KAAa,EAAyB,EAAE;IAC3D,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,OAAO,CAAC,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,sFAAsF;QACtF,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACvB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAgB,EAAE;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,0FAA0F;IAC1F,IAAI,OAA2B,CAAC;IAChC,OAAO;QACL,QAAQ,EAAE,CAAC,UAAU,EAAE,EAAE;YACvB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;gBACnC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;oBAAE,SAAS;gBACrC,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC3C,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;wBAAE,SAAS;oBAChC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAClB,OAAO,GAAG,SAAS,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;YACb,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YACnC,OAAO,KAAK,IAAI,MAAM,CACpB,CAAC,GAAG,MAAM,CAAC;iBACR,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;iBACjD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACb,KAAK;iBACF,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC;gBACvC,0FAA0F;iBACzF,OAAO,CACN,8BAA8B,EAC9B,CAAC,OAAO,EAAE,IAAY,EAAE,GAAW,EAAE,EAAE,CACrC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAC9H,CACJ;iBACA,IAAI,CAAC,GAAG,CAAC,EACZ,GAAG,CACJ,CAAC;YACF,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACzC,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,sHAAsH;AACtH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAc,8BAA8B,EAAE;IACxF,YAAY,EAAE,eAAe;CAC9B,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAwB,EAAuB,EAAE,CAC/E,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC"}
@@ -0,0 +1,66 @@
1
+ import { Context, Effect, Layer, type Redacted, Schema } from 'effect';
2
+ import { HttpApiMiddleware } from 'effect/unstable/httpapi';
3
+ import { type ManifestResource } from './Contract/Manifest.js';
4
+ import { InvalidResourceError, type ResourceNotSelectableError } from './ResourcesErrors.js';
5
+ import { type ReadError, RuntimeResources, type ResourceReader } from './RuntimeResources.js';
6
+ type Kind = ManifestResource['kind'];
7
+ type DeclarationId<K extends Kind, Name extends string> = `@temper/workflow/Declaration/${K}/${Name}`;
8
+ /** The middleware identity every declaration carries; `workflow()` supplies each one an endpoint names. */
9
+ export interface AnyDeclaration {
10
+ readonly key: DeclarationId<Kind, string>;
11
+ }
12
+ /**
13
+ * One resource, variable, or resource type a workflow reads, declared once. The class is both the
14
+ * endpoint middleware (`.middleware(ErpCredentials)`) and the handler's value (`yield* ErpCredentials`);
15
+ * a handler that yields it on an endpoint without it fails to compile.
16
+ */
17
+ export type Declaration<Self, K extends Kind, Name extends string, A> = HttpApiMiddleware.ServiceClass<Self, DeclarationId<K, Name>, {
18
+ requires: never;
19
+ provides: Self;
20
+ error: never;
21
+ clientError: never;
22
+ requiredForClient: false;
23
+ security: never;
24
+ }, A>;
25
+ /** Decodable without services, so a value decodes where the handler yields it. */
26
+ type ValueSchema = Schema.Top & {
27
+ readonly DecodingServices: never;
28
+ };
29
+ /** Finds, at run time, the one record of a declared resource type that a request names. */
30
+ export interface ResourceSelection<A> {
31
+ /** The one record of this type whose `x-selectable` field equals the match; `ResourceNotFoundError` when none does. */
32
+ readonly select: (match: Readonly<Record<string, string>>) => Effect.Effect<{
33
+ readonly key: string;
34
+ readonly value: A;
35
+ }, ReadError | ResourceNotSelectableError | InvalidResourceError>;
36
+ }
37
+ /** What `makeManifest` writes and `workflow()` runs for one declaration. */
38
+ export interface DeclarationRuntime {
39
+ readonly manifest: ManifestResource;
40
+ /** The per-request value: read on first use, then kept for the rest of the request. */
41
+ readonly read: (resources: ResourceReader) => Effect.Effect<unknown>;
42
+ readonly value: Context.Key<never, Effect.Effect<unknown>>;
43
+ }
44
+ /** The declaration an endpoint middleware carries, if it is one. */
45
+ export declare const declarationOf: (middleware: HttpApiMiddleware.AnyService) => DeclarationRuntime | undefined;
46
+ /**
47
+ * A resource read by key. Declare secret fields `Redacted` (see `HttpApiResource`); name `type` to have
48
+ * deploy check the bound record's resource type too. A read the platform cannot answer is a defect.
49
+ */
50
+ export declare const Resource: <Self>() => <const Name extends string, S extends ValueSchema>(key: Name, options: {
51
+ readonly schema: S;
52
+ readonly type?: string;
53
+ }) => Declaration<Self, 'resource', Name, S['Type']>;
54
+ /** A Variable read by key; it arrives `Redacted` because the platform decides what is secret. */
55
+ export declare const Variable: <Self>() => <const Name extends string>(key: Name) => Declaration<Self, 'variable', Name, Redacted.Redacted<string>>;
56
+ /**
57
+ * A resource type whose record the handler selects at run time, for example the tenant a request
58
+ * names. Deploy checks that the type exists; `select` finds the record and decodes it with `schema`.
59
+ */
60
+ export declare const ResourceType: <Self>() => <const Name extends string, S extends ValueSchema>(type: Name, options: {
61
+ readonly schema: S;
62
+ }) => Declaration<Self, 'resourceType', Name, ResourceSelection<S['Type']>>;
63
+ /** The middleware one declaration needs: its value, read through `RuntimeResources` on first use in a request. */
64
+ export declare const declarationLayer: (middleware: HttpApiMiddleware.AnyService, runtime: DeclarationRuntime) => Layer.Layer<any, never, RuntimeResources>;
65
+ export {};
66
+ //# sourceMappingURL=Resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Resource.d.ts","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { Context, Effect, Effectable, Layer, Schema } from 'effect';
2
+ import { HttpApiMiddleware } from 'effect/unstable/httpapi';
3
+ import { JsonSchemaObject } from './Contract/Manifest.js';
4
+ import { InvalidResourceError } from './ResourcesErrors.js';
5
+ import { RuntimeResources } from './RuntimeResources.js';
6
+ // Keyed by the class `declare` builds; an author's `class X extends Resource<X>()(…)` inherits from it.
7
+ const runtimes = new WeakMap();
8
+ /** The declaration an endpoint middleware carries, if it is one. */
9
+ export const declarationOf = (middleware) => runtimes.get(middleware) ?? runtimes.get(Object.getPrototypeOf(middleware));
10
+ /** The encoded form's JSON Schema: what deploy validates the bound value against. */
11
+ const jsonSchemaOf = (schema) => {
12
+ const document = Schema.toJsonSchemaDocument(schema);
13
+ const json = Object.keys(document.definitions).length === 0
14
+ ? document.schema
15
+ : { ...document.schema, $defs: document.definitions };
16
+ return Schema.decodeUnknownSync(JsonSchemaObject)(json);
17
+ };
18
+ const decodeAs = (key, schema) => (value) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((error) => new InvalidResourceError({
19
+ target: `key ${key}`,
20
+ message: `Resource ${key} does not match the expected schema: ${error.message}`,
21
+ })));
22
+ const declare = (kind, name, manifest, read) => {
23
+ const id = `@temper/workflow/Declaration/${kind}/${name}`;
24
+ const middleware = HttpApiMiddleware.Service()(id);
25
+ // The middleware reads the value into this key on first use; yielding the declaration yields that read.
26
+ const value = Context.Service(`${id}/value`);
27
+ Object.assign(middleware, Effectable.Prototype({ label: 'Declaration', evaluate: () => Effect.flatten(value) }));
28
+ runtimes.set(middleware, { manifest, read, value });
29
+ const declared = middleware;
30
+ // SAFETY: yielding the class now evaluates to the declared value, which is the `A` this type names.
31
+ return declared;
32
+ };
33
+ /**
34
+ * A resource read by key. Declare secret fields `Redacted` (see `HttpApiResource`); name `type` to have
35
+ * deploy check the bound record's resource type too. A read the platform cannot answer is a defect.
36
+ */
37
+ export const Resource = () => (key, options) => declare('resource', key, options.type === undefined
38
+ ? { kind: 'resource', key, schema: jsonSchemaOf(options.schema) }
39
+ : { kind: 'resource', key, type: options.type, schema: jsonSchemaOf(options.schema) }, (resources) => resources.resolve(key).pipe(Effect.flatMap(decodeAs(key, options.schema)), Effect.orDie));
40
+ /** A Variable read by key; it arrives `Redacted` because the platform decides what is secret. */
41
+ export const Variable = () => (key) => declare('variable', key, { kind: 'variable', key }, (resources) => Effect.orDie(resources.variable(key)));
42
+ /**
43
+ * A resource type whose record the handler selects at run time, for example the tenant a request
44
+ * names. Deploy checks that the type exists; `select` finds the record and decodes it with `schema`.
45
+ */
46
+ export const ResourceType = () => (type, options) => declare('resourceType', type, { kind: 'resourceType', type, schema: jsonSchemaOf(options.schema) }, (resources) => Effect.succeed({
47
+ select: (match) => Effect.gen(function* () {
48
+ const key = yield* resources.select({ resourceTypeKey: type, match });
49
+ const value = yield* resources.resolve(key).pipe(Effect.flatMap(decodeAs(key, options.schema)));
50
+ return { key, value };
51
+ }),
52
+ }));
53
+ /** The middleware one declaration needs: its value, read through `RuntimeResources` on first use in a request. */
54
+ export const declarationLayer = (middleware, runtime) => Layer.effect(
55
+ // The key's declared service is the handler's value; its context slot holds this middleware function.
56
+ middleware, Effect.map(RuntimeResources, (resources) => (httpEffect) => Effect.flatMap(Effect.cached(runtime.read(resources)), (read) => Effect.provideService(httpEffect, runtime.value, read))));
57
+ //# sourceMappingURL=Resource.js.map