ff-serv 0.1.10 → 0.1.11
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/dist/adapter-DLhjFlOu.d.cts +31 -0
- package/dist/adapter-DLhjFlOu.d.ts +31 -0
- package/dist/cli.js +47 -47
- package/dist/exports/cache-bun-redis.cjs +50 -0
- package/dist/exports/cache-bun-redis.cjs.map +1 -0
- package/dist/exports/cache-bun-redis.d.cts +11 -0
- package/dist/exports/cache-bun-redis.d.ts +11 -0
- package/dist/exports/cache-bun-redis.js +23 -0
- package/dist/exports/cache-bun-redis.js.map +1 -0
- package/dist/exports/cache-ioredis.cjs +51 -0
- package/dist/exports/cache-ioredis.cjs.map +1 -0
- package/dist/exports/cache-ioredis.d.cts +11 -0
- package/dist/exports/cache-ioredis.d.ts +11 -0
- package/dist/exports/cache-ioredis.js +24 -0
- package/dist/exports/cache-ioredis.js.map +1 -0
- package/dist/exports/cache.cjs +220 -0
- package/dist/exports/cache.cjs.map +1 -0
- package/dist/exports/cache.d.cts +30 -0
- package/dist/exports/cache.d.ts +30 -0
- package/dist/exports/cache.js +199 -0
- package/dist/exports/cache.js.map +1 -0
- package/dist/exports/orpc.cjs +15 -10
- package/dist/exports/orpc.cjs.map +1 -1
- package/dist/exports/orpc.js +16 -11
- package/dist/exports/orpc.js.map +1 -1
- package/dist/index.cjs +15 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -7
- package/dist/index.d.ts +10 -7
- package/dist/index.js +17 -12
- package/dist/index.js.map +1 -1
- package/package.json +26 -2
- package/src/cache/AGENTS.md +8 -0
- package/src/cache/adapter.test.ts +181 -0
- package/src/cache/adapter.ts +120 -0
- package/src/cache/adapters/bun-redis.ts +29 -0
- package/src/cache/adapters/ioredis.ts +30 -0
- package/src/cache/cache.test.ts +461 -0
- package/src/cache/cache.ts +184 -0
- package/src/cli/commands/db/pull.ts +5 -15
- package/src/cli/commands/db/shared.ts +7 -7
- package/src/cli/config/index.ts +1 -3
- package/src/cli/index.ts +1 -1
- package/src/cli/utils/database-source.ts +1 -4
- package/src/exports/cache-bun-redis.ts +1 -0
- package/src/exports/cache-ioredis.ts +1 -0
- package/src/exports/cache.ts +6 -0
- package/src/exports/orpc.ts +1 -1
- package/src/http/fetch-handler.test.ts +1 -1
- package/src/index.ts +1 -0
- package/src/logger.test.ts +168 -0
- package/src/logger.ts +41 -19
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// src/cache/adapter.ts
|
|
2
|
+
import { Duration, Effect, Option, Schema } from "effect";
|
|
3
|
+
var CacheAdapter;
|
|
4
|
+
((CacheAdapter2) => {
|
|
5
|
+
function memory(opts) {
|
|
6
|
+
return {
|
|
7
|
+
get: () => Effect.succeed(Option.none()),
|
|
8
|
+
set: () => Effect.void,
|
|
9
|
+
remove: () => Effect.void,
|
|
10
|
+
removeAll: Effect.void,
|
|
11
|
+
capacity: opts?.capacity
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
CacheAdapter2.memory = memory;
|
|
15
|
+
function redis(opts) {
|
|
16
|
+
const encodeKey = (key) => `${opts.keyPrefix}:${JSON.stringify(key)}`;
|
|
17
|
+
const encodeEntry = (entry) => {
|
|
18
|
+
if (opts.schema) {
|
|
19
|
+
return Schema.encode(opts.schema)(entry.value).pipe(
|
|
20
|
+
Effect.map(
|
|
21
|
+
(encoded) => JSON.stringify({ value: encoded, storedAt: entry.storedAt })
|
|
22
|
+
),
|
|
23
|
+
Effect.orDie
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return Effect.succeed(JSON.stringify(entry));
|
|
27
|
+
};
|
|
28
|
+
const decodeEntry = (raw) => {
|
|
29
|
+
const parsed = JSON.parse(raw);
|
|
30
|
+
if (opts.schema) {
|
|
31
|
+
return Schema.decode(opts.schema)(parsed.value).pipe(
|
|
32
|
+
Effect.map((value) => ({
|
|
33
|
+
value,
|
|
34
|
+
storedAt: parsed.storedAt
|
|
35
|
+
})),
|
|
36
|
+
Effect.orDie
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return Effect.succeed(parsed);
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
get: (key) => Effect.gen(function* () {
|
|
43
|
+
const raw = yield* opts.client.get(encodeKey(key));
|
|
44
|
+
if (Option.isNone(raw)) return Option.none();
|
|
45
|
+
const entry = yield* decodeEntry(raw.value);
|
|
46
|
+
return Option.some(entry);
|
|
47
|
+
}),
|
|
48
|
+
set: (key, entry, ttl) => Effect.gen(function* () {
|
|
49
|
+
const encoded = yield* encodeEntry(entry);
|
|
50
|
+
yield* opts.client.set(
|
|
51
|
+
encodeKey(key),
|
|
52
|
+
encoded,
|
|
53
|
+
Duration.toMillis(ttl)
|
|
54
|
+
);
|
|
55
|
+
}),
|
|
56
|
+
remove: (key) => opts.client.del(encodeKey(key)),
|
|
57
|
+
removeAll: Effect.void
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
CacheAdapter2.redis = redis;
|
|
61
|
+
function tiered(l1, l2) {
|
|
62
|
+
return {
|
|
63
|
+
get: (key) => Effect.gen(function* () {
|
|
64
|
+
const fromL1 = yield* l1.get(key);
|
|
65
|
+
if (Option.isSome(fromL1)) return fromL1;
|
|
66
|
+
return yield* l2.get(key);
|
|
67
|
+
}),
|
|
68
|
+
set: (key, entry, ttl) => Effect.all([l1.set(key, entry, ttl), l2.set(key, entry, ttl)], {
|
|
69
|
+
discard: true
|
|
70
|
+
}),
|
|
71
|
+
remove: (key) => Effect.all([l1.remove(key), l2.remove(key)], { discard: true }),
|
|
72
|
+
removeAll: Effect.all([l1.removeAll, l2.removeAll], { discard: true }),
|
|
73
|
+
capacity: l1.capacity
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
CacheAdapter2.tiered = tiered;
|
|
77
|
+
})(CacheAdapter || (CacheAdapter = {}));
|
|
78
|
+
|
|
79
|
+
// src/cache/cache.ts
|
|
80
|
+
import {
|
|
81
|
+
Clock,
|
|
82
|
+
Duration as Duration2,
|
|
83
|
+
Effect as Effect2,
|
|
84
|
+
Cache as EffectCache,
|
|
85
|
+
Exit,
|
|
86
|
+
Option as Option2
|
|
87
|
+
} from "effect";
|
|
88
|
+
var Cache;
|
|
89
|
+
((Cache2) => {
|
|
90
|
+
function entry(value, opts) {
|
|
91
|
+
return { _tag: "CacheEntry", value, ttl: opts.ttl, swr: opts.swr };
|
|
92
|
+
}
|
|
93
|
+
Cache2.entry = entry;
|
|
94
|
+
function make(opts) {
|
|
95
|
+
return Effect2.gen(function* () {
|
|
96
|
+
const adapter = opts.adapter;
|
|
97
|
+
const defaultTtlMs = Duration2.toMillis(Duration2.decode(opts.ttl));
|
|
98
|
+
const defaultSwrMs = opts.swr ? Duration2.toMillis(Duration2.decode(opts.swr)) : 0;
|
|
99
|
+
const capacity = adapter?.capacity ?? Number.MAX_SAFE_INTEGER;
|
|
100
|
+
const refreshingKeys = /* @__PURE__ */ new Set();
|
|
101
|
+
const inner = yield* EffectCache.makeWith({
|
|
102
|
+
capacity,
|
|
103
|
+
lookup: (key) => Effect2.gen(function* () {
|
|
104
|
+
const isRefreshing = refreshingKeys.has(JSON.stringify(key));
|
|
105
|
+
if (adapter && !isRefreshing) {
|
|
106
|
+
const cached = yield* adapter.get(key);
|
|
107
|
+
if (Option2.isSome(cached)) {
|
|
108
|
+
const now = yield* Clock.currentTimeMillis;
|
|
109
|
+
const age = now - cached.value.storedAt;
|
|
110
|
+
const totalWindow = defaultTtlMs + defaultSwrMs;
|
|
111
|
+
if (age < totalWindow) {
|
|
112
|
+
return {
|
|
113
|
+
value: cached.value.value,
|
|
114
|
+
ttlMs: Math.max(0, defaultTtlMs - age),
|
|
115
|
+
swrMs: Math.max(
|
|
116
|
+
0,
|
|
117
|
+
defaultSwrMs - Math.max(0, age - defaultTtlMs)
|
|
118
|
+
)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const result = yield* opts.lookup(key);
|
|
124
|
+
const cv = resolveLookupResult(result, defaultTtlMs, defaultSwrMs);
|
|
125
|
+
if (adapter) {
|
|
126
|
+
const now = yield* Clock.currentTimeMillis;
|
|
127
|
+
yield* adapter.set(
|
|
128
|
+
key,
|
|
129
|
+
{ value: cv.value, storedAt: now },
|
|
130
|
+
Duration2.millis(cv.ttlMs + cv.swrMs)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return cv;
|
|
134
|
+
}),
|
|
135
|
+
timeToLive: (exit) => {
|
|
136
|
+
if (Exit.isSuccess(exit)) {
|
|
137
|
+
return Duration2.millis(exit.value.ttlMs + exit.value.swrMs);
|
|
138
|
+
}
|
|
139
|
+
return Duration2.zero;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
const get = (key) => Effect2.gen(function* () {
|
|
143
|
+
const cv = yield* inner.get(key);
|
|
144
|
+
if (cv.swrMs > 0) {
|
|
145
|
+
const stats = yield* inner.entryStats(key);
|
|
146
|
+
if (Option2.isSome(stats)) {
|
|
147
|
+
const now = yield* Clock.currentTimeMillis;
|
|
148
|
+
const age = now - stats.value.loadedMillis;
|
|
149
|
+
if (age > cv.ttlMs) {
|
|
150
|
+
const keyStr = JSON.stringify(key);
|
|
151
|
+
if (!refreshingKeys.has(keyStr)) {
|
|
152
|
+
refreshingKeys.add(keyStr);
|
|
153
|
+
yield* Effect2.forkDaemon(
|
|
154
|
+
inner.refresh(key).pipe(
|
|
155
|
+
Effect2.ensuring(
|
|
156
|
+
Effect2.sync(() => {
|
|
157
|
+
refreshingKeys.delete(keyStr);
|
|
158
|
+
})
|
|
159
|
+
),
|
|
160
|
+
Effect2.ignore
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return cv.value;
|
|
168
|
+
});
|
|
169
|
+
const invalidate = (key) => Effect2.gen(function* () {
|
|
170
|
+
yield* inner.invalidate(key);
|
|
171
|
+
if (adapter) yield* adapter.remove(key);
|
|
172
|
+
});
|
|
173
|
+
const invalidateAll = Effect2.gen(function* () {
|
|
174
|
+
yield* inner.invalidateAll;
|
|
175
|
+
if (adapter) yield* adapter.removeAll;
|
|
176
|
+
});
|
|
177
|
+
return { get, invalidate, invalidateAll };
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
Cache2.make = make;
|
|
181
|
+
})(Cache || (Cache = {}));
|
|
182
|
+
function isCacheEntry(result) {
|
|
183
|
+
return typeof result === "object" && result !== null && "_tag" in result && result._tag === "CacheEntry";
|
|
184
|
+
}
|
|
185
|
+
function resolveLookupResult(result, defaultTtlMs, defaultSwrMs) {
|
|
186
|
+
if (isCacheEntry(result)) {
|
|
187
|
+
return {
|
|
188
|
+
value: result.value,
|
|
189
|
+
ttlMs: Duration2.toMillis(Duration2.decode(result.ttl)),
|
|
190
|
+
swrMs: result.swr ? Duration2.toMillis(Duration2.decode(result.swr)) : 0
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return { value: result, ttlMs: defaultTtlMs, swrMs: defaultSwrMs };
|
|
194
|
+
}
|
|
195
|
+
export {
|
|
196
|
+
Cache,
|
|
197
|
+
CacheAdapter
|
|
198
|
+
};
|
|
199
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cache/adapter.ts","../../src/cache/cache.ts"],"sourcesContent":["import { Duration, Effect, Option, Schema } from 'effect';\n\nexport type CacheEntry<Value> = {\n\treadonly value: Value;\n\treadonly storedAt: number;\n};\n\nexport type RedisClient = {\n\treadonly get: (key: string) => Effect.Effect<Option.Option<string>>;\n\treadonly set: (\n\t\tkey: string,\n\t\tvalue: string,\n\t\tttlMs: number,\n\t) => Effect.Effect<void>;\n\treadonly del: (key: string) => Effect.Effect<void>;\n};\n\nexport type CacheAdapter<Key, Value> = {\n\treadonly get: (key: Key) => Effect.Effect<Option.Option<CacheEntry<Value>>>;\n\treadonly set: (\n\t\tkey: Key,\n\t\tentry: CacheEntry<Value>,\n\t\tttl: Duration.Duration,\n\t) => Effect.Effect<void>;\n\treadonly remove: (key: Key) => Effect.Effect<void>;\n\treadonly removeAll: Effect.Effect<void>;\n\treadonly capacity?: number;\n};\n\nexport namespace CacheAdapter {\n\t// No-op adapter — Effect Cache IS the in-memory store. This only carries `capacity`.\n\texport function memory<Key, Value>(opts?: {\n\t\tcapacity?: number;\n\t}): CacheAdapter<Key, Value> {\n\t\treturn {\n\t\t\tget: () => Effect.succeed(Option.none()),\n\t\t\tset: () => Effect.void,\n\t\t\tremove: () => Effect.void,\n\t\t\tremoveAll: Effect.void,\n\t\t\tcapacity: opts?.capacity,\n\t\t};\n\t}\n\n\texport function redis<Key, Value>(opts: {\n\t\tclient: RedisClient;\n\t\tkeyPrefix: string;\n\t\tschema?: Schema.Schema<Value, string>;\n\t}): CacheAdapter<Key, Value> {\n\t\tconst encodeKey = (key: Key) => `${opts.keyPrefix}:${JSON.stringify(key)}`;\n\n\t\tconst encodeEntry = (entry: CacheEntry<Value>): Effect.Effect<string> => {\n\t\t\tif (opts.schema) {\n\t\t\t\treturn Schema.encode(opts.schema)(entry.value).pipe(\n\t\t\t\t\tEffect.map((encoded) =>\n\t\t\t\t\t\tJSON.stringify({ value: encoded, storedAt: entry.storedAt }),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.orDie,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn Effect.succeed(JSON.stringify(entry));\n\t\t};\n\n\t\tconst decodeEntry = (raw: string): Effect.Effect<CacheEntry<Value>> => {\n\t\t\tconst parsed = JSON.parse(raw);\n\t\t\tif (opts.schema) {\n\t\t\t\treturn Schema.decode(opts.schema)(parsed.value).pipe(\n\t\t\t\t\tEffect.map((value) => ({\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tstoredAt: parsed.storedAt as number,\n\t\t\t\t\t})),\n\t\t\t\t\tEffect.orDie,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn Effect.succeed(parsed as CacheEntry<Value>);\n\t\t};\n\n\t\treturn {\n\t\t\tget: (key) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst raw = yield* opts.client.get(encodeKey(key));\n\t\t\t\t\tif (Option.isNone(raw)) return Option.none<CacheEntry<Value>>();\n\t\t\t\t\tconst entry = yield* decodeEntry(raw.value);\n\t\t\t\t\treturn Option.some(entry);\n\t\t\t\t}),\n\t\t\tset: (key, entry, ttl) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst encoded = yield* encodeEntry(entry);\n\t\t\t\t\tyield* opts.client.set(\n\t\t\t\t\t\tencodeKey(key),\n\t\t\t\t\t\tencoded,\n\t\t\t\t\t\tDuration.toMillis(ttl),\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\tremove: (key) => opts.client.del(encodeKey(key)),\n\t\t\tremoveAll: Effect.void,\n\t\t};\n\t}\n\n\texport function tiered<Key, Value>(\n\t\tl1: CacheAdapter<Key, Value>,\n\t\tl2: CacheAdapter<Key, Value>,\n\t): CacheAdapter<Key, Value> {\n\t\treturn {\n\t\t\tget: (key) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst fromL1 = yield* l1.get(key);\n\t\t\t\t\tif (Option.isSome(fromL1)) return fromL1;\n\t\t\t\t\treturn yield* l2.get(key);\n\t\t\t\t}),\n\t\t\tset: (key, entry, ttl) =>\n\t\t\t\tEffect.all([l1.set(key, entry, ttl), l2.set(key, entry, ttl)], {\n\t\t\t\t\tdiscard: true,\n\t\t\t\t}),\n\t\t\tremove: (key) =>\n\t\t\t\tEffect.all([l1.remove(key), l2.remove(key)], { discard: true }),\n\t\t\tremoveAll: Effect.all([l1.removeAll, l2.removeAll], { discard: true }),\n\t\t\tcapacity: l1.capacity,\n\t\t};\n\t}\n}\n","import {\n\tClock,\n\tDuration,\n\tEffect,\n\tCache as EffectCache,\n\tExit,\n\tOption,\n} from 'effect';\nimport type { CacheAdapter, CacheEntry } from './adapter.js';\n\n// Bundles value with resolved TTL/SWR so the SWR check at read time uses per-entry durations\ntype CacheValue<Value> = {\n\treadonly value: Value;\n\treadonly ttlMs: number;\n\treadonly swrMs: number;\n};\n\nexport type CacheInstance<Key, Value, Error> = {\n\treadonly get: (key: Key) => Effect.Effect<Value, Error>;\n\treadonly invalidate: (key: Key) => Effect.Effect<void>;\n\treadonly invalidateAll: Effect.Effect<void>;\n};\n\nexport namespace Cache {\n\texport type Entry<Value> = {\n\t\treadonly _tag: 'CacheEntry';\n\t\treadonly value: Value;\n\t\treadonly ttl: Duration.DurationInput;\n\t\treadonly swr?: Duration.DurationInput;\n\t};\n\n\texport function entry<Value>(\n\t\tvalue: Value,\n\t\topts: { ttl: Duration.DurationInput; swr?: Duration.DurationInput },\n\t): Entry<Value> {\n\t\treturn { _tag: 'CacheEntry', value, ttl: opts.ttl, swr: opts.swr };\n\t}\n\n\texport type LookupResult<Value> = Value | Entry<Value>;\n\n\texport function make<Key, Value, Error = never, R = never>(opts: {\n\t\tttl: Duration.DurationInput;\n\t\tswr?: Duration.DurationInput;\n\t\tlookup: (key: Key) => Effect.Effect<LookupResult<Value>, Error, R>;\n\t\tadapter?: CacheAdapter<Key, Value>;\n\t}): Effect.Effect<CacheInstance<Key, Value, Error>, never, R> {\n\t\treturn Effect.gen(function* () {\n\t\t\tconst adapter = opts.adapter;\n\t\t\tconst defaultTtlMs = Duration.toMillis(Duration.decode(opts.ttl));\n\t\t\tconst defaultSwrMs = opts.swr\n\t\t\t\t? Duration.toMillis(Duration.decode(opts.swr))\n\t\t\t\t: 0;\n\t\t\tconst capacity = adapter?.capacity ?? Number.MAX_SAFE_INTEGER;\n\n\t\t\t// Safe without synchronization — no yield points between has() and add() (cooperative scheduling)\n\t\t\tconst refreshingKeys = new Set<string>();\n\n\t\t\t// makeWith uses `timeToLive: (exit) => Duration` — the lookup stores CacheValue\n\t\t\t// so timeToLive can extract the total window (ttl + swr) from the exit result\n\t\t\tconst inner = yield* EffectCache.makeWith({\n\t\t\t\tcapacity,\n\t\t\t\tlookup: (key: Key) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst isRefreshing = refreshingKeys.has(JSON.stringify(key));\n\n\t\t\t\t\t\tif (adapter && !isRefreshing) {\n\t\t\t\t\t\t\tconst cached = yield* adapter.get(key);\n\t\t\t\t\t\t\tif (Option.isSome(cached)) {\n\t\t\t\t\t\t\t\tconst now = yield* Clock.currentTimeMillis;\n\t\t\t\t\t\t\t\tconst age = now - cached.value.storedAt;\n\t\t\t\t\t\t\t\tconst totalWindow = defaultTtlMs + defaultSwrMs;\n\t\t\t\t\t\t\t\tif (age < totalWindow) {\n\t\t\t\t\t\t\t\t\t// Adjust remaining TTL/SWR for elapsed age so SWR triggers at correct real-world time\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tvalue: cached.value.value,\n\t\t\t\t\t\t\t\t\t\tttlMs: Math.max(0, defaultTtlMs - age),\n\t\t\t\t\t\t\t\t\t\tswrMs: Math.max(\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t\tdefaultSwrMs - Math.max(0, age - defaultTtlMs),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t} satisfies CacheValue<Value>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst result = yield* opts.lookup(key);\n\t\t\t\t\t\tconst cv = resolveLookupResult(result, defaultTtlMs, defaultSwrMs);\n\n\t\t\t\t\t\tif (adapter) {\n\t\t\t\t\t\t\tconst now = yield* Clock.currentTimeMillis;\n\t\t\t\t\t\t\tyield* adapter.set(\n\t\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t\t\t{ value: cv.value, storedAt: now } satisfies CacheEntry<Value>,\n\t\t\t\t\t\t\t\tDuration.millis(cv.ttlMs + cv.swrMs),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn cv;\n\t\t\t\t\t}),\n\t\t\t\ttimeToLive: (exit) => {\n\t\t\t\t\tif (Exit.isSuccess(exit)) {\n\t\t\t\t\t\treturn Duration.millis(exit.value.ttlMs + exit.value.swrMs);\n\t\t\t\t\t}\n\t\t\t\t\treturn Duration.zero;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst get = (key: Key) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst cv = yield* inner.get(key);\n\n\t\t\t\t\tif (cv.swrMs > 0) {\n\t\t\t\t\t\tconst stats = yield* inner.entryStats(key);\n\t\t\t\t\t\tif (Option.isSome(stats)) {\n\t\t\t\t\t\t\tconst now = yield* Clock.currentTimeMillis;\n\t\t\t\t\t\t\tconst age = now - stats.value.loadedMillis;\n\t\t\t\t\t\t\tif (age > cv.ttlMs) {\n\t\t\t\t\t\t\t\tconst keyStr = JSON.stringify(key);\n\t\t\t\t\t\t\t\tif (!refreshingKeys.has(keyStr)) {\n\t\t\t\t\t\t\t\t\trefreshingKeys.add(keyStr);\n\t\t\t\t\t\t\t\t\t// refresh() recomputes without invalidating, so stale value remains available during recomputation\n\t\t\t\t\t\t\t\t\tyield* Effect.forkDaemon(\n\t\t\t\t\t\t\t\t\t\tinner.refresh(key).pipe(\n\t\t\t\t\t\t\t\t\t\t\tEffect.ensuring(\n\t\t\t\t\t\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\trefreshingKeys.delete(keyStr);\n\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\tEffect.ignore,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn cv.value;\n\t\t\t\t});\n\n\t\t\tconst invalidate = (key: Key) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tyield* inner.invalidate(key);\n\t\t\t\t\tif (adapter) yield* adapter.remove(key);\n\t\t\t\t});\n\n\t\t\tconst invalidateAll = Effect.gen(function* () {\n\t\t\t\tyield* inner.invalidateAll;\n\t\t\t\tif (adapter) yield* adapter.removeAll;\n\t\t\t});\n\n\t\t\treturn { get, invalidate, invalidateAll } satisfies CacheInstance<\n\t\t\t\tKey,\n\t\t\t\tValue,\n\t\t\t\tError\n\t\t\t>;\n\t\t});\n\t}\n}\n\nfunction isCacheEntry<Value>(\n\tresult: Cache.LookupResult<Value>,\n): result is Cache.Entry<Value> {\n\treturn (\n\t\ttypeof result === 'object' &&\n\t\tresult !== null &&\n\t\t'_tag' in result &&\n\t\t(result as Cache.Entry<Value>)._tag === 'CacheEntry'\n\t);\n}\n\nfunction resolveLookupResult<Value>(\n\tresult: Cache.LookupResult<Value>,\n\tdefaultTtlMs: number,\n\tdefaultSwrMs: number,\n): CacheValue<Value> {\n\tif (isCacheEntry(result)) {\n\t\treturn {\n\t\t\tvalue: result.value,\n\t\t\tttlMs: Duration.toMillis(Duration.decode(result.ttl)),\n\t\t\tswrMs: result.swr ? Duration.toMillis(Duration.decode(result.swr)) : 0,\n\t\t};\n\t}\n\treturn { value: result, ttlMs: defaultTtlMs, swrMs: defaultSwrMs };\n}\n"],"mappings":"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","names":["CacheAdapter","Duration","Effect","Option","Cache"]}
|
package/dist/exports/orpc.cjs
CHANGED
|
@@ -39,19 +39,24 @@ function extractParams(...[obj, msg]) {
|
|
|
39
39
|
}
|
|
40
40
|
return { message: msg, attributes: obj };
|
|
41
41
|
}
|
|
42
|
+
function makeSyncLogger(runtime, annotations) {
|
|
43
|
+
const run = (e) => {
|
|
44
|
+
const annotated = Object.keys(annotations).length > 0 ? e.pipe(import_effect.Effect.annotateLogs(annotations)) : e;
|
|
45
|
+
void import_effect.Runtime.runPromise(runtime)(annotated);
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
info: (...params) => run(Logger.info(...params)),
|
|
49
|
+
debug: (...params) => run(Logger.debug(...params)),
|
|
50
|
+
warn: (...params) => run(Logger.warn(...params)),
|
|
51
|
+
error: (...params) => run(Logger.error(...params)),
|
|
52
|
+
child: (childAnnotations) => makeSyncLogger(runtime, { ...annotations, ...childAnnotations })
|
|
53
|
+
};
|
|
54
|
+
}
|
|
42
55
|
var Logger;
|
|
43
56
|
((Logger2) => {
|
|
44
|
-
Logger2.sync = () => import_effect.Effect.gen(function* () {
|
|
57
|
+
Logger2.sync = (annotations) => import_effect.Effect.gen(function* () {
|
|
45
58
|
const runtime = yield* import_effect.Effect.runtime();
|
|
46
|
-
|
|
47
|
-
void import_effect.Runtime.runPromise(runtime)(e);
|
|
48
|
-
};
|
|
49
|
-
return {
|
|
50
|
-
info: (...params) => run(Logger2.info(...params)),
|
|
51
|
-
debug: (...params) => run(Logger2.debug(...params)),
|
|
52
|
-
warn: (...params) => run(Logger2.warn(...params)),
|
|
53
|
-
error: (...params) => run(Logger2.error(...params))
|
|
54
|
-
};
|
|
59
|
+
return makeSyncLogger(runtime, annotations ?? {});
|
|
55
60
|
});
|
|
56
61
|
Logger2.info = (...params) => import_effect.Effect.gen(function* () {
|
|
57
62
|
const { message, attributes } = extractParams(...params);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/orpc.ts","../../src/http/orpc.ts","../../src/http/fetch-handler.ts","../../src/logger.ts"],"sourcesContent":["export { oRPCHandler } from '../http/orpc.js';","import type { Context } from '@orpc/server';\nimport type { FetchHandler } from '@orpc/server/fetch';\nimport type { FriendlyStandardHandleOptions } from '@orpc/server/standard';\nimport { Effect } from 'effect';\nimport { Handler } from './fetch-handler.js';\n\ntype MaybeOptionalOptions<TOptions> =\n\tRecord<never, never> extends TOptions\n\t\t? [options?: TOptions]\n\t\t: [options: TOptions];\n\ntype PossibleOpt<T extends Context, E, R> =\n\t| FriendlyStandardHandleOptions<T>\n\t| Effect.Effect<FriendlyStandardHandleOptions<T>, E, R>;\n\nfunction getValue<T extends Context, E, R>(opt: PossibleOpt<T, E, R>) {\n\treturn Effect.isEffect(opt) ? opt : Effect.succeed(opt);\n}\n\nexport function oRPCHandler<T extends Context, E, R>(\n\thandler: FetchHandler<T>,\n\topt?: PossibleOpt<T, E, R> | ((request: Request) => PossibleOpt<T, E, R>),\n) {\n\treturn new Handler('oRPCHandler', ({ request }) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst _opt = (\n\t\t\t\topt\n\t\t\t\t\t? [yield* getValue(typeof opt === 'function' ? opt(request) : opt)]\n\t\t\t\t\t: []\n\t\t\t) as MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>;\n\t\t\treturn yield* Effect.tryPromise(() => handler.handle(request, ..._opt));\n\t\t}),\n\t);\n}\n","import { Effect, FiberSet } from 'effect';\nimport type { Cause } from 'effect/Cause';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\n// #region Handler\n\nexport type AnyResponse = Response | Promise<Response>;\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: AnyResponse;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport class Handler<NAME extends string, R> {\n\tconstructor(\n\t\treadonly _tag: NAME,\n\t\treadonly handle: (opt: {\n\t\t\turl: URL;\n\t\t\trequest: Request;\n\t\t}) => Effect.Effect<HandlerResult, unknown, R>,\n\t) {}\n}\n\n// #endregion\n\ntype ExtractRequirements<T> = T extends Handler<string, infer R> ? R : never;\n\nexport const createFetchHandler = <\n\tconst HANDLERS extends [\n\t\tHandler<string, unknown>,\n\t\t...Array<Handler<string, unknown>>,\n\t],\n\tR = ExtractRequirements<HANDLERS[number]>,\n>(\n\thandlers: HANDLERS,\n\topts?: {\n\t\tdebug?: boolean;\n\t\tonError?: (ctx: {\n\t\t\terror: Cause<unknown>;\n\t\t}) => Effect.Effect<unknown, unknown>;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise<R>();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of handlers) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst result = yield* handler.handle({ url: urlObj, request }).pipe(\n\t\t\t\t\t\tEffect.flatMap(({ matched, response }) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\t\tresponse:\n\t\t\t\t\t\t\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => response)\n\t\t\t\t\t\t\t\t\t\t\t\t: response,\n\t\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn { matched: false, response: undefined } as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchAllCause((error) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t\t\t`Unhandled exception in HTTP handler '${handler._tag}'`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (opts?.onError) yield* opts.onError({ error });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\tresponse: new Response('Internal Server Error', {\n\t\t\t\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t) as Effect.Effect<Response, never, R>;\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});\n","import { Effect, FiberSet, Runtime } from 'effect';\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\nexport namespace Logger {\n\texport const sync = () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst runtime = yield* Effect.runtime();\n\n\t\t\tconst run = (e: Effect.Effect<void, never, never>) => {\n\t\t\t\t// Intentionally ignoring the await here\n\t\t\t\t// void runPromise(e);\n\t\t\t\tvoid Runtime.runPromise(runtime)(e);\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\t\t\trun(Logger.info(...params)),\n\t\t\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\t\t\trun(Logger.debug(...params)),\n\t\t\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\t\t\trun(Logger.warn(...params)),\n\t\t\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\t\t\trun(Logger.error(...params)),\n\t\t\t};\n\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGA,IAAAA,iBAAuB;;;ACHvB,IAAAC,iBAAiC;AAEjC,oBAAuB;;;ACFvB,oBAA0C;AAG1C,SAAS,iBAAiB,CAAC,KAAK,GAAG,GAAc;AAChD,MAAI,OAAO,QAAQ,UAAU;AAC5B,WAAO,EAAE,SAAS,IAAI;AAAA,EACvB;AACA,SAAO,EAAE,SAAS,KAAK,YAAY,IAA2B;AAC/D;AAEO,IAAU;AAAA,CAAV,CAAUC,YAAV;AACC,EAAMA,QAAA,OAAO,MACnB,qBAAO,IAAI,aAAa;AACvB,UAAM,UAAU,OAAO,qBAAO,QAAQ;AAEtC,UAAM,MAAM,CAAC,MAAyC;AAGrD,WAAK,sBAAQ,WAAW,OAAO,EAAE,CAAC;AAAA,IACnC;AAEA,WAAO;AAAA,MACN,MAAM,IAAI,WACT,IAAIA,QAAO,KAAK,GAAG,MAAM,CAAC;AAAA,MAC3B,OAAO,IAAI,WACV,IAAIA,QAAO,MAAM,GAAG,MAAM,CAAC;AAAA,MAC5B,MAAM,IAAI,WACT,IAAIA,QAAO,KAAK,GAAG,MAAM,CAAC;AAAA,MAC3B,OAAO,IAAI,WACV,IAAIA,QAAO,MAAM,GAAG,MAAM,CAAC;AAAA,IAC7B;AAAA,EACD,CAAC;AAIK,EAAMA,QAAA,OAAO,IAAI,WACvB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,QAAQ,OAAO,EAAE;AAAA,MAC9B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,OAAO,IAAI,WACvB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,WAAW,OAAO,EAAE;AAAA,MACjC,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAAA,GAvDc;;;ADSV,IAAM,UAAN,MAAsC;AAAA,EAC5C,YACU,MACA,QAIR;AALQ;AACA;AAAA,EAIP;AACJ;;;ADZA,SAAS,SAAkC,KAA2B;AACrE,SAAO,sBAAO,SAAS,GAAG,IAAI,MAAM,sBAAO,QAAQ,GAAG;AACvD;AAEO,SAAS,YACf,SACA,KACC;AACD,SAAO,IAAI;AAAA,IAAQ;AAAA,IAAe,CAAC,EAAE,QAAQ,MAC5C,sBAAO,IAAI,aAAa;AACvB,YAAM,OACL,MACG,CAAC,OAAO,SAAS,OAAO,QAAQ,aAAa,IAAI,OAAO,IAAI,GAAG,CAAC,IAChE,CAAC;AAEL,aAAO,OAAO,sBAAO,WAAW,MAAM,QAAQ,OAAO,SAAS,GAAG,IAAI,CAAC;AAAA,IACvE,CAAC;AAAA,EACF;AACD;","names":["import_effect","import_effect","Logger"]}
|
|
1
|
+
{"version":3,"sources":["../../src/exports/orpc.ts","../../src/http/orpc.ts","../../src/http/fetch-handler.ts","../../src/logger.ts"],"sourcesContent":["export { oRPCHandler } from '../http/orpc.js';\n","import type { Context } from '@orpc/server';\nimport type { FetchHandler } from '@orpc/server/fetch';\nimport type { FriendlyStandardHandleOptions } from '@orpc/server/standard';\nimport { Effect } from 'effect';\nimport { Handler } from './fetch-handler.js';\n\ntype MaybeOptionalOptions<TOptions> =\n\tRecord<never, never> extends TOptions\n\t\t? [options?: TOptions]\n\t\t: [options: TOptions];\n\ntype PossibleOpt<T extends Context, E, R> =\n\t| FriendlyStandardHandleOptions<T>\n\t| Effect.Effect<FriendlyStandardHandleOptions<T>, E, R>;\n\nfunction getValue<T extends Context, E, R>(opt: PossibleOpt<T, E, R>) {\n\treturn Effect.isEffect(opt) ? opt : Effect.succeed(opt);\n}\n\nexport function oRPCHandler<T extends Context, E, R>(\n\thandler: FetchHandler<T>,\n\topt?: PossibleOpt<T, E, R> | ((request: Request) => PossibleOpt<T, E, R>),\n) {\n\treturn new Handler('oRPCHandler', ({ request }) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst _opt = (\n\t\t\t\topt\n\t\t\t\t\t? [yield* getValue(typeof opt === 'function' ? opt(request) : opt)]\n\t\t\t\t\t: []\n\t\t\t) as MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>;\n\t\t\treturn yield* Effect.tryPromise(() => handler.handle(request, ..._opt));\n\t\t}),\n\t);\n}\n","import { Effect, FiberSet } from 'effect';\nimport type { Cause } from 'effect/Cause';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\n// #region Handler\n\nexport type AnyResponse = Response | Promise<Response>;\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: AnyResponse;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport class Handler<NAME extends string, R> {\n\tconstructor(\n\t\treadonly _tag: NAME,\n\t\treadonly handle: (opt: {\n\t\t\turl: URL;\n\t\t\trequest: Request;\n\t\t}) => Effect.Effect<HandlerResult, unknown, R>,\n\t) {}\n}\n\n// #endregion\n\ntype ExtractRequirements<T> = T extends Handler<string, infer R> ? R : never;\n\nexport const createFetchHandler = <\n\tconst HANDLERS extends [\n\t\tHandler<string, unknown>,\n\t\t...Array<Handler<string, unknown>>,\n\t],\n\tR = ExtractRequirements<HANDLERS[number]>,\n>(\n\thandlers: HANDLERS,\n\topts?: {\n\t\tdebug?: boolean;\n\t\tonError?: (ctx: {\n\t\t\terror: Cause<unknown>;\n\t\t}) => Effect.Effect<unknown, unknown>;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise<R>();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of handlers) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst result = yield* handler.handle({ url: urlObj, request }).pipe(\n\t\t\t\t\t\tEffect.flatMap(({ matched, response }) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\t\tresponse:\n\t\t\t\t\t\t\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => response)\n\t\t\t\t\t\t\t\t\t\t\t\t: response,\n\t\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn { matched: false, response: undefined } as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchAllCause((error) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t\t\t`Unhandled exception in HTTP handler '${handler._tag}'`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (opts?.onError) yield* opts.onError({ error });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\tresponse: new Response('Internal Server Error', {\n\t\t\t\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t) as Effect.Effect<Response, never, R>;\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});\n","import { Effect, Runtime } from 'effect';\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\t// biome-ignore lint/suspicious/noExplicitAny: log attributes are unstructured\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: log annotations are unstructured\ntype LogAnnotations = Record<string, any>;\n\nexport type SyncLogger = {\n\tinfo: (...params: Parameters<typeof Logger.info>) => void;\n\tdebug: (...params: Parameters<typeof Logger.debug>) => void;\n\twarn: (...params: Parameters<typeof Logger.warn>) => void;\n\terror: (...params: Parameters<typeof Logger.error>) => void;\n\tchild: (annotations: LogAnnotations) => SyncLogger;\n};\n\nfunction makeSyncLogger(\n\truntime: Runtime.Runtime<never>,\n\tannotations: LogAnnotations,\n): SyncLogger {\n\tconst run = (e: Effect.Effect<void, never, never>) => {\n\t\tconst annotated =\n\t\t\tObject.keys(annotations).length > 0\n\t\t\t\t? e.pipe(Effect.annotateLogs(annotations))\n\t\t\t\t: e;\n\t\tvoid Runtime.runPromise(runtime)(annotated);\n\t};\n\n\treturn {\n\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\trun(Logger.info(...params)),\n\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\trun(Logger.debug(...params)),\n\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\trun(Logger.warn(...params)),\n\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\trun(Logger.error(...params)),\n\t\tchild: (childAnnotations: LogAnnotations) =>\n\t\t\tmakeSyncLogger(runtime, { ...annotations, ...childAnnotations }),\n\t};\n}\n\nexport namespace Logger {\n\texport const sync = (annotations?: LogAnnotations) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst runtime = yield* Effect.runtime();\n\t\t\treturn makeSyncLogger(runtime, annotations ?? {});\n\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGA,IAAAA,iBAAuB;;;ACHvB,IAAAC,iBAAiC;AAEjC,oBAAuB;;;ACFvB,oBAAgC;AAGhC,SAAS,iBAAiB,CAAC,KAAK,GAAG,GAAc;AAChD,MAAI,OAAO,QAAQ,UAAU;AAC5B,WAAO,EAAE,SAAS,IAAI;AAAA,EACvB;AAEA,SAAO,EAAE,SAAS,KAAK,YAAY,IAA2B;AAC/D;AAaA,SAAS,eACR,SACA,aACa;AACb,QAAM,MAAM,CAAC,MAAyC;AACrD,UAAM,YACL,OAAO,KAAK,WAAW,EAAE,SAAS,IAC/B,EAAE,KAAK,qBAAO,aAAa,WAAW,CAAC,IACvC;AACJ,SAAK,sBAAQ,WAAW,OAAO,EAAE,SAAS;AAAA,EAC3C;AAEA,SAAO;AAAA,IACN,MAAM,IAAI,WACT,IAAI,OAAO,KAAK,GAAG,MAAM,CAAC;AAAA,IAC3B,OAAO,IAAI,WACV,IAAI,OAAO,MAAM,GAAG,MAAM,CAAC;AAAA,IAC5B,MAAM,IAAI,WACT,IAAI,OAAO,KAAK,GAAG,MAAM,CAAC;AAAA,IAC3B,OAAO,IAAI,WACV,IAAI,OAAO,MAAM,GAAG,MAAM,CAAC;AAAA,IAC5B,OAAO,CAAC,qBACP,eAAe,SAAS,EAAE,GAAG,aAAa,GAAG,iBAAiB,CAAC;AAAA,EACjE;AACD;AAEO,IAAU;AAAA,CAAV,CAAUC,YAAV;AACC,EAAMA,QAAA,OAAO,CAAC,gBACpB,qBAAO,IAAI,aAAa;AACvB,UAAM,UAAU,OAAO,qBAAO,QAAQ;AACtC,WAAO,eAAe,SAAS,eAAe,CAAC,CAAC;AAAA,EACjD,CAAC;AAIK,EAAMA,QAAA,OAAO,IAAI,WACvB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,QAAQ,OAAO,EAAE;AAAA,MAC9B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,OAAO,IAAI,WACvB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,WAAW,OAAO,EAAE;AAAA,MACjC,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAAA,GAvCc;;;AD7BV,IAAM,UAAN,MAAsC;AAAA,EAC5C,YACU,MACA,QAIR;AALQ;AACA;AAAA,EAIP;AACJ;;;ADZA,SAAS,SAAkC,KAA2B;AACrE,SAAO,sBAAO,SAAS,GAAG,IAAI,MAAM,sBAAO,QAAQ,GAAG;AACvD;AAEO,SAAS,YACf,SACA,KACC;AACD,SAAO,IAAI;AAAA,IAAQ;AAAA,IAAe,CAAC,EAAE,QAAQ,MAC5C,sBAAO,IAAI,aAAa;AACvB,YAAM,OACL,MACG,CAAC,OAAO,SAAS,OAAO,QAAQ,aAAa,IAAI,OAAO,IAAI,GAAG,CAAC,IAChE,CAAC;AAEL,aAAO,OAAO,sBAAO,WAAW,MAAM,QAAQ,OAAO,SAAS,GAAG,IAAI,CAAC;AAAA,IACvE,CAAC;AAAA,EACF;AACD;","names":["import_effect","import_effect","Logger"]}
|
package/dist/exports/orpc.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Effect as Effect3 } from "effect";
|
|
3
3
|
|
|
4
4
|
// src/http/fetch-handler.ts
|
|
5
|
-
import { Effect as Effect2, FiberSet
|
|
5
|
+
import { Effect as Effect2, FiberSet } from "effect";
|
|
6
6
|
import { nanoid } from "nanoid";
|
|
7
7
|
|
|
8
8
|
// src/logger.ts
|
|
@@ -13,19 +13,24 @@ function extractParams(...[obj, msg]) {
|
|
|
13
13
|
}
|
|
14
14
|
return { message: msg, attributes: obj };
|
|
15
15
|
}
|
|
16
|
+
function makeSyncLogger(runtime, annotations) {
|
|
17
|
+
const run = (e) => {
|
|
18
|
+
const annotated = Object.keys(annotations).length > 0 ? e.pipe(Effect.annotateLogs(annotations)) : e;
|
|
19
|
+
void Runtime.runPromise(runtime)(annotated);
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
info: (...params) => run(Logger.info(...params)),
|
|
23
|
+
debug: (...params) => run(Logger.debug(...params)),
|
|
24
|
+
warn: (...params) => run(Logger.warn(...params)),
|
|
25
|
+
error: (...params) => run(Logger.error(...params)),
|
|
26
|
+
child: (childAnnotations) => makeSyncLogger(runtime, { ...annotations, ...childAnnotations })
|
|
27
|
+
};
|
|
28
|
+
}
|
|
16
29
|
var Logger;
|
|
17
30
|
((Logger2) => {
|
|
18
|
-
Logger2.sync = () => Effect.gen(function* () {
|
|
31
|
+
Logger2.sync = (annotations) => Effect.gen(function* () {
|
|
19
32
|
const runtime = yield* Effect.runtime();
|
|
20
|
-
|
|
21
|
-
void Runtime.runPromise(runtime)(e);
|
|
22
|
-
};
|
|
23
|
-
return {
|
|
24
|
-
info: (...params) => run(Logger2.info(...params)),
|
|
25
|
-
debug: (...params) => run(Logger2.debug(...params)),
|
|
26
|
-
warn: (...params) => run(Logger2.warn(...params)),
|
|
27
|
-
error: (...params) => run(Logger2.error(...params))
|
|
28
|
-
};
|
|
33
|
+
return makeSyncLogger(runtime, annotations ?? {});
|
|
29
34
|
});
|
|
30
35
|
Logger2.info = (...params) => Effect.gen(function* () {
|
|
31
36
|
const { message, attributes } = extractParams(...params);
|
package/dist/exports/orpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/http/orpc.ts","../../src/http/fetch-handler.ts","../../src/logger.ts"],"sourcesContent":["import type { Context } from '@orpc/server';\nimport type { FetchHandler } from '@orpc/server/fetch';\nimport type { FriendlyStandardHandleOptions } from '@orpc/server/standard';\nimport { Effect } from 'effect';\nimport { Handler } from './fetch-handler.js';\n\ntype MaybeOptionalOptions<TOptions> =\n\tRecord<never, never> extends TOptions\n\t\t? [options?: TOptions]\n\t\t: [options: TOptions];\n\ntype PossibleOpt<T extends Context, E, R> =\n\t| FriendlyStandardHandleOptions<T>\n\t| Effect.Effect<FriendlyStandardHandleOptions<T>, E, R>;\n\nfunction getValue<T extends Context, E, R>(opt: PossibleOpt<T, E, R>) {\n\treturn Effect.isEffect(opt) ? opt : Effect.succeed(opt);\n}\n\nexport function oRPCHandler<T extends Context, E, R>(\n\thandler: FetchHandler<T>,\n\topt?: PossibleOpt<T, E, R> | ((request: Request) => PossibleOpt<T, E, R>),\n) {\n\treturn new Handler('oRPCHandler', ({ request }) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst _opt = (\n\t\t\t\topt\n\t\t\t\t\t? [yield* getValue(typeof opt === 'function' ? opt(request) : opt)]\n\t\t\t\t\t: []\n\t\t\t) as MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>;\n\t\t\treturn yield* Effect.tryPromise(() => handler.handle(request, ..._opt));\n\t\t}),\n\t);\n}\n","import { Effect, FiberSet } from 'effect';\nimport type { Cause } from 'effect/Cause';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\n// #region Handler\n\nexport type AnyResponse = Response | Promise<Response>;\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: AnyResponse;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport class Handler<NAME extends string, R> {\n\tconstructor(\n\t\treadonly _tag: NAME,\n\t\treadonly handle: (opt: {\n\t\t\turl: URL;\n\t\t\trequest: Request;\n\t\t}) => Effect.Effect<HandlerResult, unknown, R>,\n\t) {}\n}\n\n// #endregion\n\ntype ExtractRequirements<T> = T extends Handler<string, infer R> ? R : never;\n\nexport const createFetchHandler = <\n\tconst HANDLERS extends [\n\t\tHandler<string, unknown>,\n\t\t...Array<Handler<string, unknown>>,\n\t],\n\tR = ExtractRequirements<HANDLERS[number]>,\n>(\n\thandlers: HANDLERS,\n\topts?: {\n\t\tdebug?: boolean;\n\t\tonError?: (ctx: {\n\t\t\terror: Cause<unknown>;\n\t\t}) => Effect.Effect<unknown, unknown>;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise<R>();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of handlers) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst result = yield* handler.handle({ url: urlObj, request }).pipe(\n\t\t\t\t\t\tEffect.flatMap(({ matched, response }) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\t\tresponse:\n\t\t\t\t\t\t\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => response)\n\t\t\t\t\t\t\t\t\t\t\t\t: response,\n\t\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn { matched: false, response: undefined } as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchAllCause((error) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t\t\t`Unhandled exception in HTTP handler '${handler._tag}'`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (opts?.onError) yield* opts.onError({ error });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\tresponse: new Response('Internal Server Error', {\n\t\t\t\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t) as Effect.Effect<Response, never, R>;\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});\n","import { Effect, FiberSet, Runtime } from 'effect';\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\nexport namespace Logger {\n\texport const sync = () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst runtime = yield* Effect.runtime();\n\n\t\t\tconst run = (e: Effect.Effect<void, never, never>) => {\n\t\t\t\t// Intentionally ignoring the await here\n\t\t\t\t// void runPromise(e);\n\t\t\t\tvoid Runtime.runPromise(runtime)(e);\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\t\t\trun(Logger.info(...params)),\n\t\t\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\t\t\trun(Logger.debug(...params)),\n\t\t\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\t\t\trun(Logger.warn(...params)),\n\t\t\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\t\t\trun(Logger.error(...params)),\n\t\t\t};\n\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n}\n"],"mappings":";AAGA,SAAS,UAAAA,eAAc;;;ACHvB,SAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AAEjC,SAAS,cAAc;;;ACFvB,SAAS,QAAkB,eAAe;AAG1C,SAAS,iBAAiB,CAAC,KAAK,GAAG,GAAc;AAChD,MAAI,OAAO,QAAQ,UAAU;AAC5B,WAAO,EAAE,SAAS,IAAI;AAAA,EACvB;AACA,SAAO,EAAE,SAAS,KAAK,YAAY,IAA2B;AAC/D;AAEO,IAAU;AAAA,CAAV,CAAUC,YAAV;AACC,EAAMA,QAAA,OAAO,MACnB,OAAO,IAAI,aAAa;AACvB,UAAM,UAAU,OAAO,OAAO,QAAQ;AAEtC,UAAM,MAAM,CAAC,MAAyC;AAGrD,WAAK,QAAQ,WAAW,OAAO,EAAE,CAAC;AAAA,IACnC;AAEA,WAAO;AAAA,MACN,MAAM,IAAI,WACT,IAAIA,QAAO,KAAK,GAAG,MAAM,CAAC;AAAA,MAC3B,OAAO,IAAI,WACV,IAAIA,QAAO,MAAM,GAAG,MAAM,CAAC;AAAA,MAC5B,MAAM,IAAI,WACT,IAAIA,QAAO,KAAK,GAAG,MAAM,CAAC;AAAA,MAC3B,OAAO,IAAI,WACV,IAAIA,QAAO,MAAM,GAAG,MAAM,CAAC;AAAA,IAC7B;AAAA,EACD,CAAC;AAIK,EAAMA,QAAA,OAAO,IAAI,WACvB,OAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,OAAO,QAAQ,OAAO,EAAE;AAAA,MAC9B,aAAa,OAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,OAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,OAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,OAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,OAAO,IAAI,WACvB,OAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,OAAO,WAAW,OAAO,EAAE;AAAA,MACjC,aAAa,OAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,OAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,OAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,OAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAAA,GAvDc;;;ADSV,IAAM,UAAN,MAAsC;AAAA,EAC5C,YACU,MACA,QAIR;AALQ;AACA;AAAA,EAIP;AACJ;;;ADZA,SAAS,SAAkC,KAA2B;AACrE,SAAOC,QAAO,SAAS,GAAG,IAAI,MAAMA,QAAO,QAAQ,GAAG;AACvD;AAEO,SAAS,YACf,SACA,KACC;AACD,SAAO,IAAI;AAAA,IAAQ;AAAA,IAAe,CAAC,EAAE,QAAQ,MAC5CA,QAAO,IAAI,aAAa;AACvB,YAAM,OACL,MACG,CAAC,OAAO,SAAS,OAAO,QAAQ,aAAa,IAAI,OAAO,IAAI,GAAG,CAAC,IAChE,CAAC;AAEL,aAAO,OAAOA,QAAO,WAAW,MAAM,QAAQ,OAAO,SAAS,GAAG,IAAI,CAAC;AAAA,IACvE,CAAC;AAAA,EACF;AACD;","names":["Effect","Effect","FiberSet","Logger","Effect"]}
|
|
1
|
+
{"version":3,"sources":["../../src/http/orpc.ts","../../src/http/fetch-handler.ts","../../src/logger.ts"],"sourcesContent":["import type { Context } from '@orpc/server';\nimport type { FetchHandler } from '@orpc/server/fetch';\nimport type { FriendlyStandardHandleOptions } from '@orpc/server/standard';\nimport { Effect } from 'effect';\nimport { Handler } from './fetch-handler.js';\n\ntype MaybeOptionalOptions<TOptions> =\n\tRecord<never, never> extends TOptions\n\t\t? [options?: TOptions]\n\t\t: [options: TOptions];\n\ntype PossibleOpt<T extends Context, E, R> =\n\t| FriendlyStandardHandleOptions<T>\n\t| Effect.Effect<FriendlyStandardHandleOptions<T>, E, R>;\n\nfunction getValue<T extends Context, E, R>(opt: PossibleOpt<T, E, R>) {\n\treturn Effect.isEffect(opt) ? opt : Effect.succeed(opt);\n}\n\nexport function oRPCHandler<T extends Context, E, R>(\n\thandler: FetchHandler<T>,\n\topt?: PossibleOpt<T, E, R> | ((request: Request) => PossibleOpt<T, E, R>),\n) {\n\treturn new Handler('oRPCHandler', ({ request }) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst _opt = (\n\t\t\t\topt\n\t\t\t\t\t? [yield* getValue(typeof opt === 'function' ? opt(request) : opt)]\n\t\t\t\t\t: []\n\t\t\t) as MaybeOptionalOptions<FriendlyStandardHandleOptions<T>>;\n\t\t\treturn yield* Effect.tryPromise(() => handler.handle(request, ..._opt));\n\t\t}),\n\t);\n}\n","import { Effect, FiberSet } from 'effect';\nimport type { Cause } from 'effect/Cause';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\n// #region Handler\n\nexport type AnyResponse = Response | Promise<Response>;\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: AnyResponse;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport class Handler<NAME extends string, R> {\n\tconstructor(\n\t\treadonly _tag: NAME,\n\t\treadonly handle: (opt: {\n\t\t\turl: URL;\n\t\t\trequest: Request;\n\t\t}) => Effect.Effect<HandlerResult, unknown, R>,\n\t) {}\n}\n\n// #endregion\n\ntype ExtractRequirements<T> = T extends Handler<string, infer R> ? R : never;\n\nexport const createFetchHandler = <\n\tconst HANDLERS extends [\n\t\tHandler<string, unknown>,\n\t\t...Array<Handler<string, unknown>>,\n\t],\n\tR = ExtractRequirements<HANDLERS[number]>,\n>(\n\thandlers: HANDLERS,\n\topts?: {\n\t\tdebug?: boolean;\n\t\tonError?: (ctx: {\n\t\t\terror: Cause<unknown>;\n\t\t}) => Effect.Effect<unknown, unknown>;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise<R>();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of handlers) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst result = yield* handler.handle({ url: urlObj, request }).pipe(\n\t\t\t\t\t\tEffect.flatMap(({ matched, response }) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\t\tresponse:\n\t\t\t\t\t\t\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => response)\n\t\t\t\t\t\t\t\t\t\t\t\t: response,\n\t\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn { matched: false, response: undefined } as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchAllCause((error) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t\t\t`Unhandled exception in HTTP handler '${handler._tag}'`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (opts?.onError) yield* opts.onError({ error });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\tresponse: new Response('Internal Server Error', {\n\t\t\t\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t) as Effect.Effect<Response, never, R>;\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});\n","import { Effect, Runtime } from 'effect';\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\t// biome-ignore lint/suspicious/noExplicitAny: log attributes are unstructured\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: log annotations are unstructured\ntype LogAnnotations = Record<string, any>;\n\nexport type SyncLogger = {\n\tinfo: (...params: Parameters<typeof Logger.info>) => void;\n\tdebug: (...params: Parameters<typeof Logger.debug>) => void;\n\twarn: (...params: Parameters<typeof Logger.warn>) => void;\n\terror: (...params: Parameters<typeof Logger.error>) => void;\n\tchild: (annotations: LogAnnotations) => SyncLogger;\n};\n\nfunction makeSyncLogger(\n\truntime: Runtime.Runtime<never>,\n\tannotations: LogAnnotations,\n): SyncLogger {\n\tconst run = (e: Effect.Effect<void, never, never>) => {\n\t\tconst annotated =\n\t\t\tObject.keys(annotations).length > 0\n\t\t\t\t? e.pipe(Effect.annotateLogs(annotations))\n\t\t\t\t: e;\n\t\tvoid Runtime.runPromise(runtime)(annotated);\n\t};\n\n\treturn {\n\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\trun(Logger.info(...params)),\n\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\trun(Logger.debug(...params)),\n\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\trun(Logger.warn(...params)),\n\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\trun(Logger.error(...params)),\n\t\tchild: (childAnnotations: LogAnnotations) =>\n\t\t\tmakeSyncLogger(runtime, { ...annotations, ...childAnnotations }),\n\t};\n}\n\nexport namespace Logger {\n\texport const sync = (annotations?: LogAnnotations) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst runtime = yield* Effect.runtime();\n\t\t\treturn makeSyncLogger(runtime, annotations ?? {});\n\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n}\n"],"mappings":"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","names":["Effect","Effect","Logger","Effect"]}
|
package/dist/index.cjs
CHANGED
|
@@ -52,19 +52,24 @@ function extractParams(...[obj, msg]) {
|
|
|
52
52
|
}
|
|
53
53
|
return { message: msg, attributes: obj };
|
|
54
54
|
}
|
|
55
|
+
function makeSyncLogger(runtime, annotations) {
|
|
56
|
+
const run = (e) => {
|
|
57
|
+
const annotated = Object.keys(annotations).length > 0 ? e.pipe(import_effect.Effect.annotateLogs(annotations)) : e;
|
|
58
|
+
void import_effect.Runtime.runPromise(runtime)(annotated);
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
info: (...params) => run(Logger.info(...params)),
|
|
62
|
+
debug: (...params) => run(Logger.debug(...params)),
|
|
63
|
+
warn: (...params) => run(Logger.warn(...params)),
|
|
64
|
+
error: (...params) => run(Logger.error(...params)),
|
|
65
|
+
child: (childAnnotations) => makeSyncLogger(runtime, { ...annotations, ...childAnnotations })
|
|
66
|
+
};
|
|
67
|
+
}
|
|
55
68
|
var Logger;
|
|
56
69
|
((Logger2) => {
|
|
57
|
-
Logger2.sync = () => import_effect.Effect.gen(function* () {
|
|
70
|
+
Logger2.sync = (annotations) => import_effect.Effect.gen(function* () {
|
|
58
71
|
const runtime = yield* import_effect.Effect.runtime();
|
|
59
|
-
|
|
60
|
-
void import_effect.Runtime.runPromise(runtime)(e);
|
|
61
|
-
};
|
|
62
|
-
return {
|
|
63
|
-
info: (...params) => run(Logger2.info(...params)),
|
|
64
|
-
debug: (...params) => run(Logger2.debug(...params)),
|
|
65
|
-
warn: (...params) => run(Logger2.warn(...params)),
|
|
66
|
-
error: (...params) => run(Logger2.error(...params))
|
|
67
|
-
};
|
|
72
|
+
return makeSyncLogger(runtime, annotations ?? {});
|
|
68
73
|
});
|
|
69
74
|
Logger2.info = (...params) => import_effect.Effect.gen(function* () {
|
|
70
75
|
const { message, attributes } = extractParams(...params);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/http/basic.ts","../src/http/fetch-handler.ts","../src/logger.ts","../src/port.ts"],"sourcesContent":["export * from './http/index.js';\nexport { Logger } from './logger.js';\nexport { getPort } from './port.js';\n","import { Effect } from 'effect';\nimport { type AnyResponse, Handler } from './fetch-handler.js';\n\nexport namespace Path {\n\texport type Type = `/${string}` | ((url: URL) => boolean);\n\texport function matched(path: Type, url: URL) {\n\t\treturn typeof path === 'function' ? path(url) : path === url.pathname;\n\t}\n}\n\nexport namespace Fn {\n\ttype Input = [request: Request];\n\n\ttype OutputSync = AnyResponse;\n\ttype OutputEffect<R> = Effect.Effect<AnyResponse, unknown, R>;\n\n\texport type FnSync = (...input: Input) => OutputSync;\n\texport type FnEffect<R> = (...input: Input) => OutputEffect<R>;\n\texport type FnAny<R> = (...input: Input) => OutputSync | OutputEffect<R>;\n\n\texport function exec<R>(fn: FnAny<R>, ...[request]: Input) {\n\t\tconst response = fn(request);\n\t\tif (!Effect.isEffect(response)) return Effect.succeed(response);\n\t\treturn response;\n\t}\n}\n\nexport function basicHandler(\n\tpath: Path.Type,\n\tfn: Fn.FnSync,\n): Handler<'basicHandler', never>;\nexport function basicHandler<R>(\n\tpath: Path.Type,\n\tfn: Fn.FnEffect<R>,\n): Handler<'basicHandler', R>;\nexport function basicHandler<R>(path: Path.Type, fn: Fn.FnAny<R>) {\n\treturn new Handler('basicHandler', ({ url, request }) => {\n\t\tif (!Path.matched(path, url))\n\t\t\treturn Effect.succeed({ matched: false, response: undefined });\n\n\t\treturn Effect.gen(function* () {\n\t\t\treturn {\n\t\t\t\tmatched: true,\n\t\t\t\tresponse: yield* Fn.exec(fn, request),\n\t\t\t};\n\t\t});\n\t});\n}\n","import { Effect, FiberSet } from 'effect';\nimport type { Cause } from 'effect/Cause';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\n// #region Handler\n\nexport type AnyResponse = Response | Promise<Response>;\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: AnyResponse;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport class Handler<NAME extends string, R> {\n\tconstructor(\n\t\treadonly _tag: NAME,\n\t\treadonly handle: (opt: {\n\t\t\turl: URL;\n\t\t\trequest: Request;\n\t\t}) => Effect.Effect<HandlerResult, unknown, R>,\n\t) {}\n}\n\n// #endregion\n\ntype ExtractRequirements<T> = T extends Handler<string, infer R> ? R : never;\n\nexport const createFetchHandler = <\n\tconst HANDLERS extends [\n\t\tHandler<string, unknown>,\n\t\t...Array<Handler<string, unknown>>,\n\t],\n\tR = ExtractRequirements<HANDLERS[number]>,\n>(\n\thandlers: HANDLERS,\n\topts?: {\n\t\tdebug?: boolean;\n\t\tonError?: (ctx: {\n\t\t\terror: Cause<unknown>;\n\t\t}) => Effect.Effect<unknown, unknown>;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise<R>();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of handlers) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst result = yield* handler.handle({ url: urlObj, request }).pipe(\n\t\t\t\t\t\tEffect.flatMap(({ matched, response }) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\t\tresponse:\n\t\t\t\t\t\t\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => response)\n\t\t\t\t\t\t\t\t\t\t\t\t: response,\n\t\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn { matched: false, response: undefined } as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchAllCause((error) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t\t\t`Unhandled exception in HTTP handler '${handler._tag}'`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (opts?.onError) yield* opts.onError({ error });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\tresponse: new Response('Internal Server Error', {\n\t\t\t\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t) as Effect.Effect<Response, never, R>;\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});\n","import { Effect, FiberSet, Runtime } from 'effect';\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\nexport namespace Logger {\n\texport const sync = () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst runtime = yield* Effect.runtime();\n\n\t\t\tconst run = (e: Effect.Effect<void, never, never>) => {\n\t\t\t\t// Intentionally ignoring the await here\n\t\t\t\t// void runPromise(e);\n\t\t\t\tvoid Runtime.runPromise(runtime)(e);\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\t\t\trun(Logger.info(...params)),\n\t\t\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\t\t\trun(Logger.debug(...params)),\n\t\t\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\t\t\trun(Logger.warn(...params)),\n\t\t\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\t\t\trun(Logger.error(...params)),\n\t\t\t};\n\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n}\n","import { Effect } from 'effect';\nimport * as GetPort from 'get-port';\n\nexport const getPort = (options?: GetPort.Options) =>\n\tEffect.tryPromise(() => GetPort.default(options));\n"],"mappings":"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","names":["import_effect","import_effect","Logger","Path","Fn","import_effect"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/http/basic.ts","../src/http/fetch-handler.ts","../src/logger.ts","../src/port.ts"],"sourcesContent":["export * from './http/index.js';\nexport type { SyncLogger } from './logger.js';\nexport { Logger } from './logger.js';\nexport { getPort } from './port.js';\n","import { Effect } from 'effect';\nimport { type AnyResponse, Handler } from './fetch-handler.js';\n\nexport namespace Path {\n\texport type Type = `/${string}` | ((url: URL) => boolean);\n\texport function matched(path: Type, url: URL) {\n\t\treturn typeof path === 'function' ? path(url) : path === url.pathname;\n\t}\n}\n\nexport namespace Fn {\n\ttype Input = [request: Request];\n\n\ttype OutputSync = AnyResponse;\n\ttype OutputEffect<R> = Effect.Effect<AnyResponse, unknown, R>;\n\n\texport type FnSync = (...input: Input) => OutputSync;\n\texport type FnEffect<R> = (...input: Input) => OutputEffect<R>;\n\texport type FnAny<R> = (...input: Input) => OutputSync | OutputEffect<R>;\n\n\texport function exec<R>(fn: FnAny<R>, ...[request]: Input) {\n\t\tconst response = fn(request);\n\t\tif (!Effect.isEffect(response)) return Effect.succeed(response);\n\t\treturn response;\n\t}\n}\n\nexport function basicHandler(\n\tpath: Path.Type,\n\tfn: Fn.FnSync,\n): Handler<'basicHandler', never>;\nexport function basicHandler<R>(\n\tpath: Path.Type,\n\tfn: Fn.FnEffect<R>,\n): Handler<'basicHandler', R>;\nexport function basicHandler<R>(path: Path.Type, fn: Fn.FnAny<R>) {\n\treturn new Handler('basicHandler', ({ url, request }) => {\n\t\tif (!Path.matched(path, url))\n\t\t\treturn Effect.succeed({ matched: false, response: undefined });\n\n\t\treturn Effect.gen(function* () {\n\t\t\treturn {\n\t\t\t\tmatched: true,\n\t\t\t\tresponse: yield* Fn.exec(fn, request),\n\t\t\t};\n\t\t});\n\t});\n}\n","import { Effect, FiberSet } from 'effect';\nimport type { Cause } from 'effect/Cause';\nimport { nanoid } from 'nanoid';\nimport { Logger } from '../logger.js';\n\n// #region Handler\n\nexport type AnyResponse = Response | Promise<Response>;\n\nexport type HandlerResult =\n\t| {\n\t\t\tmatched: true;\n\t\t\tresponse: AnyResponse;\n\t }\n\t| {\n\t\t\tmatched: false;\n\t\t\tresponse: undefined;\n\t };\n\nexport class Handler<NAME extends string, R> {\n\tconstructor(\n\t\treadonly _tag: NAME,\n\t\treadonly handle: (opt: {\n\t\t\turl: URL;\n\t\t\trequest: Request;\n\t\t}) => Effect.Effect<HandlerResult, unknown, R>,\n\t) {}\n}\n\n// #endregion\n\ntype ExtractRequirements<T> = T extends Handler<string, infer R> ? R : never;\n\nexport const createFetchHandler = <\n\tconst HANDLERS extends [\n\t\tHandler<string, unknown>,\n\t\t...Array<Handler<string, unknown>>,\n\t],\n\tR = ExtractRequirements<HANDLERS[number]>,\n>(\n\thandlers: HANDLERS,\n\topts?: {\n\t\tdebug?: boolean;\n\t\tonError?: (ctx: {\n\t\t\terror: Cause<unknown>;\n\t\t}) => Effect.Effect<unknown, unknown>;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst runFork = yield* FiberSet.makeRuntimePromise<R>();\n\t\treturn async (request: Request) => {\n\t\t\tconst urlObj = new URL(request.url);\n\t\t\tconst requestId = nanoid(6);\n\n\t\t\tconst effect = Effect.gen(function* () {\n\t\t\t\tyield* Logger.info(\n\t\t\t\t\t{ request: { pathname: urlObj.pathname } },\n\t\t\t\t\t'Request started',\n\t\t\t\t);\n\n\t\t\t\tfor (const handler of handlers) {\n\t\t\t\t\tif (!handler) continue;\n\n\t\t\t\t\tconst result = yield* handler.handle({ url: urlObj, request }).pipe(\n\t\t\t\t\t\tEffect.flatMap(({ matched, response }) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tif (matched) {\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\t\tresponse:\n\t\t\t\t\t\t\t\t\t\t\tresponse instanceof Promise\n\t\t\t\t\t\t\t\t\t\t\t\t? yield* Effect.tryPromise(() => response)\n\t\t\t\t\t\t\t\t\t\t\t\t: response,\n\t\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn { matched: false, response: undefined } as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.catchAllCause((error) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* Logger.error(\n\t\t\t\t\t\t\t\t\t{ error },\n\t\t\t\t\t\t\t\t\t`Unhandled exception in HTTP handler '${handler._tag}'`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (opts?.onError) yield* opts.onError({ error });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tmatched: true,\n\t\t\t\t\t\t\t\t\tresponse: new Response('Internal Server Error', {\n\t\t\t\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as const;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (opts?.debug)\n\t\t\t\t\t\tyield* Logger.debug(\n\t\t\t\t\t\t\t{ handler: handler._tag, request, result },\n\t\t\t\t\t\t\t'Processed handler',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.matched) continue;\n\t\t\t\t\treturn result.response;\n\t\t\t\t}\n\n\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}).pipe(\n\t\t\t\tEffect.tap((response) =>\n\t\t\t\t\tresponse.ok\n\t\t\t\t\t\t? Logger.info(`Request completed with status ${response.status}`)\n\t\t\t\t\t\t: Logger.warn(`Request completed with status ${response.status}`),\n\t\t\t\t),\n\t\t\t\tEffect.withSpan('http'),\n\t\t\t\tEffect.annotateLogs({ requestId }),\n\t\t\t\tEffect.scoped,\n\t\t\t) as Effect.Effect<Response, never, R>;\n\n\t\t\treturn runFork(effect);\n\t\t};\n\t});\n","import { Effect, Runtime } from 'effect';\n\ntype LogParams = [obj: unknown, msg?: string];\nfunction extractParams(...[obj, msg]: LogParams) {\n\tif (typeof obj === 'string') {\n\t\treturn { message: obj };\n\t}\n\t// biome-ignore lint/suspicious/noExplicitAny: log attributes are unstructured\n\treturn { message: msg, attributes: obj as Record<string, any> };\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: log annotations are unstructured\ntype LogAnnotations = Record<string, any>;\n\nexport type SyncLogger = {\n\tinfo: (...params: Parameters<typeof Logger.info>) => void;\n\tdebug: (...params: Parameters<typeof Logger.debug>) => void;\n\twarn: (...params: Parameters<typeof Logger.warn>) => void;\n\terror: (...params: Parameters<typeof Logger.error>) => void;\n\tchild: (annotations: LogAnnotations) => SyncLogger;\n};\n\nfunction makeSyncLogger(\n\truntime: Runtime.Runtime<never>,\n\tannotations: LogAnnotations,\n): SyncLogger {\n\tconst run = (e: Effect.Effect<void, never, never>) => {\n\t\tconst annotated =\n\t\t\tObject.keys(annotations).length > 0\n\t\t\t\t? e.pipe(Effect.annotateLogs(annotations))\n\t\t\t\t: e;\n\t\tvoid Runtime.runPromise(runtime)(annotated);\n\t};\n\n\treturn {\n\t\tinfo: (...params: Parameters<typeof Logger.info>) =>\n\t\t\trun(Logger.info(...params)),\n\t\tdebug: (...params: Parameters<typeof Logger.debug>) =>\n\t\t\trun(Logger.debug(...params)),\n\t\twarn: (...params: Parameters<typeof Logger.warn>) =>\n\t\t\trun(Logger.warn(...params)),\n\t\terror: (...params: Parameters<typeof Logger.error>) =>\n\t\t\trun(Logger.error(...params)),\n\t\tchild: (childAnnotations: LogAnnotations) =>\n\t\t\tmakeSyncLogger(runtime, { ...annotations, ...childAnnotations }),\n\t};\n}\n\nexport namespace Logger {\n\texport const sync = (annotations?: LogAnnotations) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst runtime = yield* Effect.runtime();\n\t\t\treturn makeSyncLogger(runtime, annotations ?? {});\n\t\t});\n\n\t// --\n\n\texport const info = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logInfo(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const debug = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logDebug(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const warn = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logWarning(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n\n\texport const error = (...params: LogParams) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst { message, attributes } = extractParams(...params);\n\t\t\tyield* Effect.logError(message).pipe(\n\t\t\t\tattributes ? Effect.annotateLogs(attributes) : (e) => e,\n\t\t\t);\n\t\t});\n}\n","import { Effect } from 'effect';\nimport * as GetPort from 'get-port';\n\nexport const getPort = (options?: GetPort.Options) =>\n\tEffect.tryPromise(() => GetPort.default(options));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,iBAAuB;;;ACAvB,IAAAC,iBAAiC;AAEjC,oBAAuB;;;ACFvB,oBAAgC;AAGhC,SAAS,iBAAiB,CAAC,KAAK,GAAG,GAAc;AAChD,MAAI,OAAO,QAAQ,UAAU;AAC5B,WAAO,EAAE,SAAS,IAAI;AAAA,EACvB;AAEA,SAAO,EAAE,SAAS,KAAK,YAAY,IAA2B;AAC/D;AAaA,SAAS,eACR,SACA,aACa;AACb,QAAM,MAAM,CAAC,MAAyC;AACrD,UAAM,YACL,OAAO,KAAK,WAAW,EAAE,SAAS,IAC/B,EAAE,KAAK,qBAAO,aAAa,WAAW,CAAC,IACvC;AACJ,SAAK,sBAAQ,WAAW,OAAO,EAAE,SAAS;AAAA,EAC3C;AAEA,SAAO;AAAA,IACN,MAAM,IAAI,WACT,IAAI,OAAO,KAAK,GAAG,MAAM,CAAC;AAAA,IAC3B,OAAO,IAAI,WACV,IAAI,OAAO,MAAM,GAAG,MAAM,CAAC;AAAA,IAC5B,MAAM,IAAI,WACT,IAAI,OAAO,KAAK,GAAG,MAAM,CAAC;AAAA,IAC3B,OAAO,IAAI,WACV,IAAI,OAAO,MAAM,GAAG,MAAM,CAAC;AAAA,IAC5B,OAAO,CAAC,qBACP,eAAe,SAAS,EAAE,GAAG,aAAa,GAAG,iBAAiB,CAAC;AAAA,EACjE;AACD;AAEO,IAAU;AAAA,CAAV,CAAUC,YAAV;AACC,EAAMA,QAAA,OAAO,CAAC,gBACpB,qBAAO,IAAI,aAAa;AACvB,UAAM,UAAU,OAAO,qBAAO,QAAQ;AACtC,WAAO,eAAe,SAAS,eAAe,CAAC,CAAC;AAAA,EACjD,CAAC;AAIK,EAAMA,QAAA,OAAO,IAAI,WACvB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,QAAQ,OAAO,EAAE;AAAA,MAC9B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,OAAO,IAAI,WACvB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,WAAW,OAAO,EAAE;AAAA,MACjC,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAEK,EAAMA,QAAA,QAAQ,IAAI,WACxB,qBAAO,IAAI,aAAa;AACvB,UAAM,EAAE,SAAS,WAAW,IAAI,cAAc,GAAG,MAAM;AACvD,WAAO,qBAAO,SAAS,OAAO,EAAE;AAAA,MAC/B,aAAa,qBAAO,aAAa,UAAU,IAAI,CAAC,MAAM;AAAA,IACvD;AAAA,EACD,CAAC;AAAA,GAvCc;;;AD7BV,IAAM,UAAN,MAAsC;AAAA,EAC5C,YACU,MACA,QAIR;AALQ;AACA;AAAA,EAIP;AACJ;AAMO,IAAM,qBAAqB,CAOjC,UACA,SAOA,sBAAO,IAAI,aAAa;AACvB,QAAM,UAAU,OAAO,wBAAS,mBAAsB;AACtD,SAAO,OAAO,YAAqB;AAClC,UAAM,SAAS,IAAI,IAAI,QAAQ,GAAG;AAClC,UAAM,gBAAY,sBAAO,CAAC;AAE1B,UAAM,SAAS,sBAAO,IAAI,aAAa;AACtC,aAAO,OAAO;AAAA,QACb,EAAE,SAAS,EAAE,UAAU,OAAO,SAAS,EAAE;AAAA,QACzC;AAAA,MACD;AAEA,iBAAW,WAAW,UAAU;AAC/B,YAAI,CAAC,QAAS;AAEd,cAAM,SAAS,OAAO,QAAQ,OAAO,EAAE,KAAK,QAAQ,QAAQ,CAAC,EAAE;AAAA,UAC9D,sBAAO;AAAA,YAAQ,CAAC,EAAE,SAAS,SAAS,MACnC,sBAAO,IAAI,aAAa;AACvB,kBAAI,SAAS;AACZ,uBAAO;AAAA,kBACN,SAAS;AAAA,kBACT,UACC,oBAAoB,UACjB,OAAO,sBAAO,WAAW,MAAM,QAAQ,IACvC;AAAA,gBACL;AAAA,cACD;AACA,qBAAO,EAAE,SAAS,OAAO,UAAU,OAAU;AAAA,YAC9C,CAAC;AAAA,UACF;AAAA,UACA,sBAAO;AAAA,YAAc,CAAC,UACrB,sBAAO,IAAI,aAAa;AACvB,qBAAO,OAAO;AAAA,gBACb,EAAE,MAAM;AAAA,gBACR,wCAAwC,QAAQ,IAAI;AAAA,cACrD;AACA,kBAAI,MAAM,QAAS,QAAO,KAAK,QAAQ,EAAE,MAAM,CAAC;AAChD,qBAAO;AAAA,gBACN,SAAS;AAAA,gBACT,UAAU,IAAI,SAAS,yBAAyB;AAAA,kBAC/C,QAAQ;AAAA,gBACT,CAAC;AAAA,cACF;AAAA,YACD,CAAC;AAAA,UACF;AAAA,QACD;AAEA,YAAI,MAAM;AACT,iBAAO,OAAO;AAAA,YACb,EAAE,SAAS,QAAQ,MAAM,SAAS,OAAO;AAAA,YACzC;AAAA,UACD;AAED,YAAI,CAAC,OAAO,QAAS;AACrB,eAAO,OAAO;AAAA,MACf;AAEA,aAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,IAAI,CAAC;AAAA,IACjD,CAAC,EAAE;AAAA,MACF,sBAAO;AAAA,QAAI,CAAC,aACX,SAAS,KACN,OAAO,KAAK,iCAAiC,SAAS,MAAM,EAAE,IAC9D,OAAO,KAAK,iCAAiC,SAAS,MAAM,EAAE;AAAA,MAClE;AAAA,MACA,sBAAO,SAAS,MAAM;AAAA,MACtB,sBAAO,aAAa,EAAE,UAAU,CAAC;AAAA,MACjC,sBAAO;AAAA,IACR;AAEA,WAAO,QAAQ,MAAM;AAAA,EACtB;AACD,CAAC;;;ADpHK,IAAU;AAAA,CAAV,CAAUC,UAAV;AAEC,WAAS,QAAQ,MAAY,KAAU;AAC7C,WAAO,OAAO,SAAS,aAAa,KAAK,GAAG,IAAI,SAAS,IAAI;AAAA,EAC9D;AAFO,EAAAA,MAAS;AAAA,GAFA;AAOV,IAAU;AAAA,CAAV,CAAUC,QAAV;AAUC,WAAS,KAAQ,OAAiB,CAAC,OAAO,GAAU;AAC1D,UAAM,WAAW,GAAG,OAAO;AAC3B,QAAI,CAAC,sBAAO,SAAS,QAAQ,EAAG,QAAO,sBAAO,QAAQ,QAAQ;AAC9D,WAAO;AAAA,EACR;AAJO,EAAAA,IAAS;AAAA,GAVA;AAyBV,SAAS,aAAgB,MAAiB,IAAiB;AACjE,SAAO,IAAI,QAAQ,gBAAgB,CAAC,EAAE,KAAK,QAAQ,MAAM;AACxD,QAAI,CAAC,KAAK,QAAQ,MAAM,GAAG;AAC1B,aAAO,sBAAO,QAAQ,EAAE,SAAS,OAAO,UAAU,OAAU,CAAC;AAE9D,WAAO,sBAAO,IAAI,aAAa;AAC9B,aAAO;AAAA,QACN,SAAS;AAAA,QACT,UAAU,OAAO,GAAG,KAAK,IAAI,OAAO;AAAA,MACrC;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AACF;;;AG/CA,IAAAC,iBAAuB;AACvB,cAAyB;AAElB,IAAM,UAAU,CAAC,YACvB,sBAAO,WAAW,MAAc,gBAAQ,OAAO,CAAC;","names":["import_effect","import_effect","Logger","Path","Fn","import_effect"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -23,13 +23,16 @@ declare function basicHandler(path: Path.Type, fn: Fn.FnSync): Handler<'basicHan
|
|
|
23
23
|
declare function basicHandler<R>(path: Path.Type, fn: Fn.FnEffect<R>): Handler<'basicHandler', R>;
|
|
24
24
|
|
|
25
25
|
type LogParams = [obj: unknown, msg?: string];
|
|
26
|
+
type LogAnnotations = Record<string, any>;
|
|
27
|
+
type SyncLogger = {
|
|
28
|
+
info: (...params: Parameters<typeof Logger.info>) => void;
|
|
29
|
+
debug: (...params: Parameters<typeof Logger.debug>) => void;
|
|
30
|
+
warn: (...params: Parameters<typeof Logger.warn>) => void;
|
|
31
|
+
error: (...params: Parameters<typeof Logger.error>) => void;
|
|
32
|
+
child: (annotations: LogAnnotations) => SyncLogger;
|
|
33
|
+
};
|
|
26
34
|
declare namespace Logger {
|
|
27
|
-
const sync: () => Effect.Effect<
|
|
28
|
-
info: (obj: unknown, msg?: string | undefined) => void;
|
|
29
|
-
debug: (obj: unknown, msg?: string | undefined) => void;
|
|
30
|
-
warn: (obj: unknown, msg?: string | undefined) => void;
|
|
31
|
-
error: (obj: unknown, msg?: string | undefined) => void;
|
|
32
|
-
}, never, never>;
|
|
35
|
+
const sync: (annotations?: LogAnnotations) => Effect.Effect<SyncLogger, never, never>;
|
|
33
36
|
const info: (...params: LogParams) => Effect.Effect<void, never, never>;
|
|
34
37
|
const debug: (...params: LogParams) => Effect.Effect<void, never, never>;
|
|
35
38
|
const warn: (...params: LogParams) => Effect.Effect<void, never, never>;
|
|
@@ -38,4 +41,4 @@ declare namespace Logger {
|
|
|
38
41
|
|
|
39
42
|
declare const getPort: (options?: GetPort.Options) => Effect.Effect<number, effect_Cause.UnknownException, never>;
|
|
40
43
|
|
|
41
|
-
export { Logger, basicHandler, getPort };
|
|
44
|
+
export { Logger, type SyncLogger, basicHandler, getPort };
|
package/dist/index.d.ts
CHANGED
|
@@ -23,13 +23,16 @@ declare function basicHandler(path: Path.Type, fn: Fn.FnSync): Handler<'basicHan
|
|
|
23
23
|
declare function basicHandler<R>(path: Path.Type, fn: Fn.FnEffect<R>): Handler<'basicHandler', R>;
|
|
24
24
|
|
|
25
25
|
type LogParams = [obj: unknown, msg?: string];
|
|
26
|
+
type LogAnnotations = Record<string, any>;
|
|
27
|
+
type SyncLogger = {
|
|
28
|
+
info: (...params: Parameters<typeof Logger.info>) => void;
|
|
29
|
+
debug: (...params: Parameters<typeof Logger.debug>) => void;
|
|
30
|
+
warn: (...params: Parameters<typeof Logger.warn>) => void;
|
|
31
|
+
error: (...params: Parameters<typeof Logger.error>) => void;
|
|
32
|
+
child: (annotations: LogAnnotations) => SyncLogger;
|
|
33
|
+
};
|
|
26
34
|
declare namespace Logger {
|
|
27
|
-
const sync: () => Effect.Effect<
|
|
28
|
-
info: (obj: unknown, msg?: string | undefined) => void;
|
|
29
|
-
debug: (obj: unknown, msg?: string | undefined) => void;
|
|
30
|
-
warn: (obj: unknown, msg?: string | undefined) => void;
|
|
31
|
-
error: (obj: unknown, msg?: string | undefined) => void;
|
|
32
|
-
}, never, never>;
|
|
35
|
+
const sync: (annotations?: LogAnnotations) => Effect.Effect<SyncLogger, never, never>;
|
|
33
36
|
const info: (...params: LogParams) => Effect.Effect<void, never, never>;
|
|
34
37
|
const debug: (...params: LogParams) => Effect.Effect<void, never, never>;
|
|
35
38
|
const warn: (...params: LogParams) => Effect.Effect<void, never, never>;
|
|
@@ -38,4 +41,4 @@ declare namespace Logger {
|
|
|
38
41
|
|
|
39
42
|
declare const getPort: (options?: GetPort.Options) => Effect.Effect<number, effect_Cause.UnknownException, never>;
|
|
40
43
|
|
|
41
|
-
export { Logger, basicHandler, getPort };
|
|
44
|
+
export { Logger, type SyncLogger, basicHandler, getPort };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Effect as Effect3 } from "effect";
|
|
3
3
|
|
|
4
4
|
// src/http/fetch-handler.ts
|
|
5
|
-
import { Effect as Effect2, FiberSet
|
|
5
|
+
import { Effect as Effect2, FiberSet } from "effect";
|
|
6
6
|
import { nanoid } from "nanoid";
|
|
7
7
|
|
|
8
8
|
// src/logger.ts
|
|
@@ -13,19 +13,24 @@ function extractParams(...[obj, msg]) {
|
|
|
13
13
|
}
|
|
14
14
|
return { message: msg, attributes: obj };
|
|
15
15
|
}
|
|
16
|
+
function makeSyncLogger(runtime, annotations) {
|
|
17
|
+
const run = (e) => {
|
|
18
|
+
const annotated = Object.keys(annotations).length > 0 ? e.pipe(Effect.annotateLogs(annotations)) : e;
|
|
19
|
+
void Runtime.runPromise(runtime)(annotated);
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
info: (...params) => run(Logger.info(...params)),
|
|
23
|
+
debug: (...params) => run(Logger.debug(...params)),
|
|
24
|
+
warn: (...params) => run(Logger.warn(...params)),
|
|
25
|
+
error: (...params) => run(Logger.error(...params)),
|
|
26
|
+
child: (childAnnotations) => makeSyncLogger(runtime, { ...annotations, ...childAnnotations })
|
|
27
|
+
};
|
|
28
|
+
}
|
|
16
29
|
var Logger;
|
|
17
30
|
((Logger2) => {
|
|
18
|
-
Logger2.sync = () => Effect.gen(function* () {
|
|
31
|
+
Logger2.sync = (annotations) => Effect.gen(function* () {
|
|
19
32
|
const runtime = yield* Effect.runtime();
|
|
20
|
-
|
|
21
|
-
void Runtime.runPromise(runtime)(e);
|
|
22
|
-
};
|
|
23
|
-
return {
|
|
24
|
-
info: (...params) => run(Logger2.info(...params)),
|
|
25
|
-
debug: (...params) => run(Logger2.debug(...params)),
|
|
26
|
-
warn: (...params) => run(Logger2.warn(...params)),
|
|
27
|
-
error: (...params) => run(Logger2.error(...params))
|
|
28
|
-
};
|
|
33
|
+
return makeSyncLogger(runtime, annotations ?? {});
|
|
29
34
|
});
|
|
30
35
|
Logger2.info = (...params) => Effect.gen(function* () {
|
|
31
36
|
const { message, attributes } = extractParams(...params);
|
|
@@ -61,7 +66,7 @@ var Handler = class {
|
|
|
61
66
|
}
|
|
62
67
|
};
|
|
63
68
|
var createFetchHandler = (handlers, opts) => Effect2.gen(function* () {
|
|
64
|
-
const runFork = yield*
|
|
69
|
+
const runFork = yield* FiberSet.makeRuntimePromise();
|
|
65
70
|
return async (request) => {
|
|
66
71
|
const urlObj = new URL(request.url);
|
|
67
72
|
const requestId = nanoid(6);
|