@geekmidas/services 10.0.0-alpha.11 → 10.0.0-alpha.110
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/{ServiceDiscovery-WHikQSQv.mjs → ServiceDiscovery-5LlW7BgD.mjs} +5 -5
- package/dist/ServiceDiscovery-5LlW7BgD.mjs.map +1 -0
- package/dist/{ServiceDiscovery-BrCUabG_.cjs → ServiceDiscovery-C1bAv6vY.cjs} +9 -9
- package/dist/ServiceDiscovery-C1bAv6vY.cjs.map +1 -0
- package/dist/{ServiceDiscovery-BO8W-RY8.d.cts → ServiceDiscovery-D8OKCBzy.d.mts} +5 -8
- package/dist/ServiceDiscovery-D8OKCBzy.d.mts.map +1 -0
- package/dist/{ServiceDiscovery-CRq_bGbi.d.mts → ServiceDiscovery-zMTNKupf.d.cts} +5 -8
- package/dist/ServiceDiscovery-zMTNKupf.d.cts.map +1 -0
- package/dist/context.cjs +196 -5
- package/dist/context.cjs.map +1 -0
- package/dist/context.d.cts +99 -3
- package/dist/context.d.cts.map +1 -0
- package/dist/context.d.mts +99 -3
- package/dist/context.d.mts.map +1 -0
- package/dist/context.mjs +191 -2
- package/dist/context.mjs.map +1 -0
- package/dist/index.cjs +6 -4
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +3 -4
- package/dist/middy.cjs +4 -4
- package/dist/middy.cjs.map +1 -1
- package/dist/middy.d.cts +9 -13
- package/dist/middy.d.cts.map +1 -1
- package/dist/middy.d.mts +9 -13
- package/dist/middy.d.mts.map +1 -1
- package/dist/middy.mjs +3 -4
- package/dist/middy.mjs.map +1 -1
- package/dist/trpc.cjs +7 -7
- package/dist/trpc.cjs.map +1 -1
- package/dist/trpc.d.cts +8 -11
- package/dist/trpc.d.cts.map +1 -1
- package/dist/trpc.d.mts +8 -11
- package/dist/trpc.d.mts.map +1 -1
- package/dist/trpc.mjs +5 -6
- package/dist/trpc.mjs.map +1 -1
- package/dist/{types-Bgk-0NOO.d.cts → types-BJldyZ-B.d.cts} +20 -5
- package/dist/types-BJldyZ-B.d.cts.map +1 -0
- package/dist/{types-BoyOCa57.d.mts → types-BJldyZ-B.d.mts} +20 -5
- package/dist/types-BJldyZ-B.d.mts.map +1 -0
- package/package.json +7 -6
- package/dist/ServiceDiscovery-BO8W-RY8.d.cts.map +0 -1
- package/dist/ServiceDiscovery-BrCUabG_.cjs.map +0 -1
- package/dist/ServiceDiscovery-CRq_bGbi.d.mts.map +0 -1
- package/dist/ServiceDiscovery-WHikQSQv.mjs.map +0 -1
- package/dist/context-1ROj3zvL.cjs +0 -197
- package/dist/context-1ROj3zvL.cjs.map +0 -1
- package/dist/context-CH2c0ftq.mjs +0 -145
- package/dist/context-CH2c0ftq.mjs.map +0 -1
- package/dist/context-CU-87vsM.d.mts +0 -64
- package/dist/context-CU-87vsM.d.mts.map +0 -1
- package/dist/context-D2owD3ac.d.cts +0 -64
- package/dist/context-D2owD3ac.d.cts.map +0 -1
- package/dist/types-Bgk-0NOO.d.cts.map +0 -1
- package/dist/types-BoyOCa57.d.mts.map +0 -1
package/dist/trpc.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trpc.cjs","names":["
|
|
1
|
+
{"version":3,"file":"trpc.cjs","names":["ServiceDiscovery","randomUUID","runWithRequestContext"],"sources":["../src/trpc.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tTRPCMiddlewareBuilder,\n\tTRPCMiddlewareFunction,\n} from '@trpc/server';\nimport { runWithRequestContext } from './context';\nimport { ServiceDiscovery, type ServiceRecord } from './ServiceDiscovery';\nimport type { Service } from './types';\n\n/**\n * Shape of `t.middleware` from `@trpc/server`. We accept this rather than the\n * initialized `t` object so callers retain ownership of their tRPC instance\n * (no double-initialization, no opinion on context/meta shape).\n */\ntype CreateMiddleware<TContext, TMeta> = <$ContextOverrides>(\n\tfn: TRPCMiddlewareFunction<\n\t\tTContext,\n\t\tTMeta,\n\t\tobject,\n\t\t$ContextOverrides,\n\t\tunknown\n\t>,\n) => TRPCMiddlewareBuilder<TContext, TMeta, $ContextOverrides, unknown>;\n\n/**\n * Result of `createServicesMiddleware`: a function that accepts a service\n * tuple and returns a tRPC middleware that merges resolved services onto the\n * context.\n */\nexport type ServicesMiddleware<\n\tTContext extends object,\n\tTMeta extends object,\n> = <const T extends Service[]>(\n\tservices: [...T],\n) => TRPCMiddlewareBuilder<TContext, TMeta, ServiceRecord<T>, unknown>;\n\n/**\n * Context shape required by `createServicesMiddleware` overload 2.\n * Procedures that pull services via context-stored discovery must expose it\n * under `serviceDiscovery`.\n */\nexport interface ContextWithServiceDiscovery {\n\tserviceDiscovery: ServiceDiscovery;\n}\n\n/**\n * Minimum context required for request-context propagation. `logger` must be\n * present so services can call `serviceContext.getLogger()`. `requestId` and\n * `startTime` are auto-generated if missing.\n */\nexport interface ContextWithLogger {\n\tlogger: Logger;\n\trequestId?: string;\n\tstartTime?: number;\n}\n\n/**\n * Create a tRPC middleware that:\n *\n * 1. Resolves the requested services via `ServiceDiscovery`.\n * 2. Wraps the downstream call in `runWithRequestContext` so any code reached\n * by the procedure (including service method implementations) can read the\n * current logger/request id via `serviceContext`.\n * 3. Merges the resolved services onto the tRPC context so handlers can access\n * them by service name (`ctx.database`, `ctx.cache`, ...).\n *\n * Two overloads:\n * - Pass an `envParser` to create a per-request `ServiceDiscovery` instance.\n * - Omit `envParser` to read `ctx.serviceDiscovery` from the tRPC context.\n *\n * @example\n * ```ts\n * import { initTRPC } from '@trpc/server';\n * import { createServicesMiddleware } from '@geekmidas/services/trpc';\n *\n * const t = initTRPC.context<Context>().create();\n * const withServices = createServicesMiddleware(t.middleware, envParser);\n *\n * export const authedProcedure = t.procedure.use(\n * withServices([databaseService, cacheService]),\n * );\n * ```\n */\nexport function createServicesMiddleware<\n\tTContext extends ContextWithLogger & object,\n\tTMeta extends object,\n>(\n\tmw: CreateMiddleware<TContext, TMeta>,\n\tenvParser: EnvironmentParser<{}>,\n): ServicesMiddleware<TContext, TMeta>;\nexport function createServicesMiddleware<\n\tTContext extends ContextWithLogger & ContextWithServiceDiscovery & object,\n\tTMeta extends object,\n>(mw: CreateMiddleware<TContext, TMeta>): ServicesMiddleware<TContext, TMeta>;\nexport function createServicesMiddleware<\n\tTContext extends ContextWithLogger & object,\n\tTMeta extends object,\n>(\n\tmw: CreateMiddleware<TContext, TMeta>,\n\tenvParser?: EnvironmentParser<{}>,\n): ServicesMiddleware<TContext, TMeta> {\n\treturn (<const T extends Service[]>(services: [...T]) => {\n\t\tconst builder = mw(async (opts) => {\n\t\t\tconst ctx = opts.ctx as TContext & Partial<ContextWithServiceDiscovery>;\n\n\t\t\tconst discovery =\n\t\t\t\tctx.serviceDiscovery ??\n\t\t\t\tServiceDiscovery.getInstance(\n\t\t\t\t\tenvParser ??\n\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\t// Hit only if overload 2 was selected but ctx.serviceDiscovery is\n\t\t\t\t\t\t\t// missing at runtime — surface the mistake immediately rather\n\t\t\t\t\t\t\t// than letting an undefined env parser fail deep inside register.\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'createServicesMiddleware: no `envParser` provided and ' +\n\t\t\t\t\t\t\t\t\t'`ctx.serviceDiscovery` is missing. Pass an EnvironmentParser ' +\n\t\t\t\t\t\t\t\t\t'to createServicesMiddleware(), or attach a ServiceDiscovery ' +\n\t\t\t\t\t\t\t\t\t'instance to the tRPC context.',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})(),\n\t\t\t\t);\n\n\t\t\tconst requestId = ctx.requestId ?? randomUUID();\n\t\t\tconst startTime = ctx.startTime ?? Date.now();\n\n\t\t\treturn runWithRequestContext(\n\t\t\t\t{ logger: ctx.logger, requestId, startTime },\n\t\t\t\tasync () => {\n\t\t\t\t\tconst resolved = await discovery.register(services);\n\t\t\t\t\treturn opts.next({\n\t\t\t\t\t\tctx: { ...opts.ctx, ...resolved } as typeof opts.ctx &\n\t\t\t\t\t\t\tServiceRecord<T>,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\n\t\t// Tag the inner middleware function with the requested services so external\n\t\t// tooling (e.g. detect-procedures route generators) can introspect a\n\t\t// procedure's service dependencies without re-executing middleware.\n\t\tconst middlewares = (\n\t\t\tbuilder as unknown as { _middlewares?: Array<{ _services?: Service[] }> }\n\t\t)._middlewares;\n\t\tif (middlewares?.length) {\n\t\t\tconst last = middlewares[middlewares.length - 1];\n\t\t\tif (last) last._services = services as unknown as Service[];\n\t\t}\n\n\t\treturn builder as TRPCMiddlewareBuilder<\n\t\t\tTContext,\n\t\t\tTMeta,\n\t\t\tServiceRecord<T>,\n\t\t\tunknown\n\t\t>;\n\t}) as ServicesMiddleware<TContext, TMeta>;\n}\n\n/**\n * Create a tRPC middleware that establishes a request context for downstream\n * code without resolving any services. Useful when services aren't needed on\n * a procedure but the handler (or libraries it calls) still wants to read\n * `serviceContext.getLogger()` / `getRequestId()` / `getRequestStartTime()`.\n *\n * `requestId` and `startTime` are pulled from the tRPC context when present,\n * otherwise generated (`randomUUID()` and `Date.now()`).\n *\n * @example\n * ```ts\n * const withRequestContext = createRequestContextMiddleware(t.middleware);\n * export const baseProcedure = t.procedure.use(withRequestContext);\n * ```\n */\nexport function createRequestContextMiddleware<\n\tTContext extends ContextWithLogger & object,\n\tTMeta extends object,\n>(\n\tmw: CreateMiddleware<TContext, TMeta>,\n): TRPCMiddlewareBuilder<TContext, TMeta, object, unknown> {\n\treturn mw(async (opts) => {\n\t\tconst ctx = opts.ctx as TContext;\n\t\tconst requestId = ctx.requestId ?? randomUUID();\n\t\tconst startTime = ctx.startTime ?? Date.now();\n\t\treturn runWithRequestContext(\n\t\t\t{ logger: ctx.logger, requestId, startTime },\n\t\t\t() => opts.next(),\n\t\t);\n\t});\n}\n"],"mappings":";;;;;AAgGA,SAAgB,yBAIf,IACA,WACsC;CACtC,SAAoC,aAAqB;EACxD,MAAM,UAAU,GAAG,OAAO,SAAS;GAClC,MAAM,MAAM,KAAK;GAEjB,MAAM,YACL,IAAI,oBACJA,yBAAAA,iBAAiB,YAChB,oBACQ;IAIN,MAAM,IAAI,MACT,8MAID;GACD,EAAA,CAAG,CACL;GAED,MAAM,YAAY,IAAI,cAAA,GAAaC,YAAAA,WAAAA,CAAW;GAC9C,MAAM,YAAY,IAAI,aAAa,KAAK,IAAI;GAE5C,OAAOC,gBAAAA,sBACN;IAAE,QAAQ,IAAI;IAAQ;IAAW;GAAU,GAC3C,YAAY;IACX,MAAM,WAAW,MAAM,UAAU,SAAS,QAAQ;IAClD,OAAO,KAAK,KAAK,EAChB,KAAK;KAAE,GAAG,KAAK;KAAK,GAAG;IAAS,EAEjC,CAAC;GACF,CACD;EACD,CAAC;EAKD,MAAM,cACL,QACC;EACF,IAAI,aAAa,QAAQ;GACxB,MAAM,OAAO,YAAY,YAAY,SAAS;GAC9C,IAAI,MAAM,KAAK,YAAY;EAC5B;EAEA,OAAO;CAMR;AACD;;;;;;;;;;;;;;;;AAiBA,SAAgB,+BAIf,IAC0D;CAC1D,OAAO,GAAG,OAAO,SAAS;EACzB,MAAM,MAAM,KAAK;EACjB,MAAM,YAAY,IAAI,cAAA,GAAaD,YAAAA,WAAAA,CAAW;EAC9C,MAAM,YAAY,IAAI,aAAa,KAAK,IAAI;EAC5C,OAAOC,gBAAAA,sBACN;GAAE,QAAQ,IAAI;GAAQ;GAAW;EAAU,SACrC,KAAK,KAAK,CACjB;CACD,CAAC;AACF"}
|
package/dist/trpc.d.cts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { Service } from "./types-
|
|
2
|
-
import { ServiceDiscovery, ServiceRecord } from "./ServiceDiscovery-
|
|
1
|
+
import { n as Service } from "./types-BJldyZ-B.cjs";
|
|
2
|
+
import { n as ServiceDiscovery, r as ServiceRecord } from "./ServiceDiscovery-zMTNKupf.cjs";
|
|
3
3
|
import { Logger } from "@geekmidas/logger";
|
|
4
4
|
import { EnvironmentParser } from "@geekmidas/envkit";
|
|
5
5
|
import { TRPCMiddlewareBuilder, TRPCMiddlewareFunction } from "@trpc/server";
|
|
6
|
-
|
|
7
6
|
//#region src/trpc.d.ts
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* Shape of `t.middleware` from `@trpc/server`. We accept this rather than the
|
|
11
9
|
* initialized `t` object so callers retain ownership of their tRPC instance
|
|
@@ -17,13 +15,13 @@ type CreateMiddleware<TContext, TMeta> = <$ContextOverrides>(fn: TRPCMiddlewareF
|
|
|
17
15
|
* tuple and returns a tRPC middleware that merges resolved services onto the
|
|
18
16
|
* context.
|
|
19
17
|
*/
|
|
20
|
-
type ServicesMiddleware<TContext extends object, TMeta extends object> = <const T extends Service[]>(services: [...T]) => TRPCMiddlewareBuilder<TContext, TMeta, ServiceRecord<T>, unknown>;
|
|
18
|
+
export type ServicesMiddleware<TContext extends object, TMeta extends object> = <const T extends Service[]>(services: [...T]) => TRPCMiddlewareBuilder<TContext, TMeta, ServiceRecord<T>, unknown>;
|
|
21
19
|
/**
|
|
22
20
|
* Context shape required by `createServicesMiddleware` overload 2.
|
|
23
21
|
* Procedures that pull services via context-stored discovery must expose it
|
|
24
22
|
* under `serviceDiscovery`.
|
|
25
23
|
*/
|
|
26
|
-
interface ContextWithServiceDiscovery {
|
|
24
|
+
export interface ContextWithServiceDiscovery {
|
|
27
25
|
serviceDiscovery: ServiceDiscovery;
|
|
28
26
|
}
|
|
29
27
|
/**
|
|
@@ -31,7 +29,7 @@ interface ContextWithServiceDiscovery {
|
|
|
31
29
|
* present so services can call `serviceContext.getLogger()`. `requestId` and
|
|
32
30
|
* `startTime` are auto-generated if missing.
|
|
33
31
|
*/
|
|
34
|
-
interface ContextWithLogger {
|
|
32
|
+
export interface ContextWithLogger {
|
|
35
33
|
logger: Logger;
|
|
36
34
|
requestId?: string;
|
|
37
35
|
startTime?: number;
|
|
@@ -63,8 +61,8 @@ interface ContextWithLogger {
|
|
|
63
61
|
* );
|
|
64
62
|
* ```
|
|
65
63
|
*/
|
|
66
|
-
declare function createServicesMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>, envParser: EnvironmentParser<{}>): ServicesMiddleware<TContext, TMeta>;
|
|
67
|
-
declare function createServicesMiddleware<TContext extends ContextWithLogger & ContextWithServiceDiscovery & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): ServicesMiddleware<TContext, TMeta>;
|
|
64
|
+
export declare function createServicesMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>, envParser: EnvironmentParser<{}>): ServicesMiddleware<TContext, TMeta>;
|
|
65
|
+
export declare function createServicesMiddleware<TContext extends ContextWithLogger & ContextWithServiceDiscovery & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): ServicesMiddleware<TContext, TMeta>;
|
|
68
66
|
/**
|
|
69
67
|
* Create a tRPC middleware that establishes a request context for downstream
|
|
70
68
|
* code without resolving any services. Useful when services aren't needed on
|
|
@@ -80,7 +78,6 @@ declare function createServicesMiddleware<TContext extends ContextWithLogger & C
|
|
|
80
78
|
* export const baseProcedure = t.procedure.use(withRequestContext);
|
|
81
79
|
* ```
|
|
82
80
|
*/
|
|
83
|
-
declare function createRequestContextMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): TRPCMiddlewareBuilder<TContext, TMeta, object, unknown>;
|
|
81
|
+
export declare function createRequestContextMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): TRPCMiddlewareBuilder<TContext, TMeta, object, unknown>;
|
|
84
82
|
//#endregion
|
|
85
|
-
export { ContextWithLogger, ContextWithServiceDiscovery, ServicesMiddleware, createRequestContextMiddleware, createServicesMiddleware };
|
|
86
83
|
//# sourceMappingURL=trpc.d.cts.map
|
package/dist/trpc.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trpc.d.cts","names":[],"sources":["../src/trpc.ts"],"
|
|
1
|
+
{"version":3,"file":"trpc.d.cts","names":[],"sources":["../src/trpc.ts"],"mappings":";;;;;;;;;;;KAgBK,iBAAiB,UAAU,UAAU,mBACzC,IAAI,uBACH,UACA,eAEA,gCAGG,sBAAsB,UAAU,OAAO;;;;;;YAOhC,mBACX,yBACA,+BACU,UAAU,WACpB,cAAc,OACV,sBAAsB,UAAU,OAAO,cAAc;;;;;;iBAOzC;EAChB,kBAAkB;;;;;;;iBAQF;EAChB,QAAQ;EACR;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8Be,yBACf,iBAAiB,4BACjB,sBAEA,IAAI,iBAAiB,UAAU,QAC/B,WAAW,wBACT,mBAAmB,UAAU;wBAChB,yBACf,iBAAiB,oBAAoB,sCACrC,sBACC,IAAI,iBAAiB,UAAU,SAAS,mBAAmB,UAAU;;;;;;;;;;;;;;;;wBA+EvD,+BACf,iBAAiB,4BACjB,sBAEA,IAAI,iBAAiB,UAAU,SAC7B,sBAAsB,UAAU"}
|
package/dist/trpc.d.mts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { Service } from "./types-
|
|
2
|
-
import { ServiceDiscovery, ServiceRecord } from "./ServiceDiscovery-
|
|
1
|
+
import { n as Service } from "./types-BJldyZ-B.mjs";
|
|
2
|
+
import { n as ServiceDiscovery, r as ServiceRecord } from "./ServiceDiscovery-D8OKCBzy.mjs";
|
|
3
3
|
import { Logger } from "@geekmidas/logger";
|
|
4
4
|
import { EnvironmentParser } from "@geekmidas/envkit";
|
|
5
5
|
import { TRPCMiddlewareBuilder, TRPCMiddlewareFunction } from "@trpc/server";
|
|
6
|
-
|
|
7
6
|
//#region src/trpc.d.ts
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* Shape of `t.middleware` from `@trpc/server`. We accept this rather than the
|
|
11
9
|
* initialized `t` object so callers retain ownership of their tRPC instance
|
|
@@ -17,13 +15,13 @@ type CreateMiddleware<TContext, TMeta> = <$ContextOverrides>(fn: TRPCMiddlewareF
|
|
|
17
15
|
* tuple and returns a tRPC middleware that merges resolved services onto the
|
|
18
16
|
* context.
|
|
19
17
|
*/
|
|
20
|
-
type ServicesMiddleware<TContext extends object, TMeta extends object> = <const T extends Service[]>(services: [...T]) => TRPCMiddlewareBuilder<TContext, TMeta, ServiceRecord<T>, unknown>;
|
|
18
|
+
export type ServicesMiddleware<TContext extends object, TMeta extends object> = <const T extends Service[]>(services: [...T]) => TRPCMiddlewareBuilder<TContext, TMeta, ServiceRecord<T>, unknown>;
|
|
21
19
|
/**
|
|
22
20
|
* Context shape required by `createServicesMiddleware` overload 2.
|
|
23
21
|
* Procedures that pull services via context-stored discovery must expose it
|
|
24
22
|
* under `serviceDiscovery`.
|
|
25
23
|
*/
|
|
26
|
-
interface ContextWithServiceDiscovery {
|
|
24
|
+
export interface ContextWithServiceDiscovery {
|
|
27
25
|
serviceDiscovery: ServiceDiscovery;
|
|
28
26
|
}
|
|
29
27
|
/**
|
|
@@ -31,7 +29,7 @@ interface ContextWithServiceDiscovery {
|
|
|
31
29
|
* present so services can call `serviceContext.getLogger()`. `requestId` and
|
|
32
30
|
* `startTime` are auto-generated if missing.
|
|
33
31
|
*/
|
|
34
|
-
interface ContextWithLogger {
|
|
32
|
+
export interface ContextWithLogger {
|
|
35
33
|
logger: Logger;
|
|
36
34
|
requestId?: string;
|
|
37
35
|
startTime?: number;
|
|
@@ -63,8 +61,8 @@ interface ContextWithLogger {
|
|
|
63
61
|
* );
|
|
64
62
|
* ```
|
|
65
63
|
*/
|
|
66
|
-
declare function createServicesMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>, envParser: EnvironmentParser<{}>): ServicesMiddleware<TContext, TMeta>;
|
|
67
|
-
declare function createServicesMiddleware<TContext extends ContextWithLogger & ContextWithServiceDiscovery & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): ServicesMiddleware<TContext, TMeta>;
|
|
64
|
+
export declare function createServicesMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>, envParser: EnvironmentParser<{}>): ServicesMiddleware<TContext, TMeta>;
|
|
65
|
+
export declare function createServicesMiddleware<TContext extends ContextWithLogger & ContextWithServiceDiscovery & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): ServicesMiddleware<TContext, TMeta>;
|
|
68
66
|
/**
|
|
69
67
|
* Create a tRPC middleware that establishes a request context for downstream
|
|
70
68
|
* code without resolving any services. Useful when services aren't needed on
|
|
@@ -80,7 +78,6 @@ declare function createServicesMiddleware<TContext extends ContextWithLogger & C
|
|
|
80
78
|
* export const baseProcedure = t.procedure.use(withRequestContext);
|
|
81
79
|
* ```
|
|
82
80
|
*/
|
|
83
|
-
declare function createRequestContextMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): TRPCMiddlewareBuilder<TContext, TMeta, object, unknown>;
|
|
81
|
+
export declare function createRequestContextMiddleware<TContext extends ContextWithLogger & object, TMeta extends object>(mw: CreateMiddleware<TContext, TMeta>): TRPCMiddlewareBuilder<TContext, TMeta, object, unknown>;
|
|
84
82
|
//#endregion
|
|
85
|
-
export { ContextWithLogger, ContextWithServiceDiscovery, ServicesMiddleware, createRequestContextMiddleware, createServicesMiddleware };
|
|
86
83
|
//# sourceMappingURL=trpc.d.mts.map
|
package/dist/trpc.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trpc.d.mts","names":[],"sources":["../src/trpc.ts"],"
|
|
1
|
+
{"version":3,"file":"trpc.d.mts","names":[],"sources":["../src/trpc.ts"],"mappings":";;;;;;;;;;;KAgBK,iBAAiB,UAAU,UAAU,mBACzC,IAAI,uBACH,UACA,eAEA,gCAGG,sBAAsB,UAAU,OAAO;;;;;;YAOhC,mBACX,yBACA,+BACU,UAAU,WACpB,cAAc,OACV,sBAAsB,UAAU,OAAO,cAAc;;;;;;iBAOzC;EAChB,kBAAkB;;;;;;;iBAQF;EAChB,QAAQ;EACR;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8Be,yBACf,iBAAiB,4BACjB,sBAEA,IAAI,iBAAiB,UAAU,QAC/B,WAAW,wBACT,mBAAmB,UAAU;wBAChB,yBACf,iBAAiB,oBAAoB,sCACrC,sBACC,IAAI,iBAAiB,UAAU,SAAS,mBAAmB,UAAU;;;;;;;;;;;;;;;;wBA+EvD,+BACf,iBAAiB,4BACjB,sBAEA,IAAI,iBAAiB,UAAU,SAC7B,sBAAsB,UAAU"}
|
package/dist/trpc.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { runWithRequestContext } from "./context
|
|
2
|
-
import { ServiceDiscovery } from "./ServiceDiscovery-
|
|
1
|
+
import { runWithRequestContext } from "./context.mjs";
|
|
2
|
+
import { t as ServiceDiscovery } from "./ServiceDiscovery-5LlW7BgD.mjs";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
-
|
|
5
4
|
//#region src/trpc.ts
|
|
6
5
|
function createServicesMiddleware(mw, envParser) {
|
|
7
|
-
return (services) => {
|
|
6
|
+
return ((services) => {
|
|
8
7
|
const builder = mw(async (opts) => {
|
|
9
8
|
const ctx = opts.ctx;
|
|
10
9
|
const discovery = ctx.serviceDiscovery ?? ServiceDiscovery.getInstance(envParser ?? (() => {
|
|
@@ -30,7 +29,7 @@ function createServicesMiddleware(mw, envParser) {
|
|
|
30
29
|
if (last) last._services = services;
|
|
31
30
|
}
|
|
32
31
|
return builder;
|
|
33
|
-
};
|
|
32
|
+
});
|
|
34
33
|
}
|
|
35
34
|
/**
|
|
36
35
|
* Create a tRPC middleware that establishes a request context for downstream
|
|
@@ -59,7 +58,7 @@ function createRequestContextMiddleware(mw) {
|
|
|
59
58
|
}, () => opts.next());
|
|
60
59
|
});
|
|
61
60
|
}
|
|
62
|
-
|
|
63
61
|
//#endregion
|
|
64
62
|
export { createRequestContextMiddleware, createServicesMiddleware };
|
|
63
|
+
|
|
65
64
|
//# sourceMappingURL=trpc.mjs.map
|
package/dist/trpc.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trpc.mjs","names":[
|
|
1
|
+
{"version":3,"file":"trpc.mjs","names":[],"sources":["../src/trpc.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport type {\n\tTRPCMiddlewareBuilder,\n\tTRPCMiddlewareFunction,\n} from '@trpc/server';\nimport { runWithRequestContext } from './context';\nimport { ServiceDiscovery, type ServiceRecord } from './ServiceDiscovery';\nimport type { Service } from './types';\n\n/**\n * Shape of `t.middleware` from `@trpc/server`. We accept this rather than the\n * initialized `t` object so callers retain ownership of their tRPC instance\n * (no double-initialization, no opinion on context/meta shape).\n */\ntype CreateMiddleware<TContext, TMeta> = <$ContextOverrides>(\n\tfn: TRPCMiddlewareFunction<\n\t\tTContext,\n\t\tTMeta,\n\t\tobject,\n\t\t$ContextOverrides,\n\t\tunknown\n\t>,\n) => TRPCMiddlewareBuilder<TContext, TMeta, $ContextOverrides, unknown>;\n\n/**\n * Result of `createServicesMiddleware`: a function that accepts a service\n * tuple and returns a tRPC middleware that merges resolved services onto the\n * context.\n */\nexport type ServicesMiddleware<\n\tTContext extends object,\n\tTMeta extends object,\n> = <const T extends Service[]>(\n\tservices: [...T],\n) => TRPCMiddlewareBuilder<TContext, TMeta, ServiceRecord<T>, unknown>;\n\n/**\n * Context shape required by `createServicesMiddleware` overload 2.\n * Procedures that pull services via context-stored discovery must expose it\n * under `serviceDiscovery`.\n */\nexport interface ContextWithServiceDiscovery {\n\tserviceDiscovery: ServiceDiscovery;\n}\n\n/**\n * Minimum context required for request-context propagation. `logger` must be\n * present so services can call `serviceContext.getLogger()`. `requestId` and\n * `startTime` are auto-generated if missing.\n */\nexport interface ContextWithLogger {\n\tlogger: Logger;\n\trequestId?: string;\n\tstartTime?: number;\n}\n\n/**\n * Create a tRPC middleware that:\n *\n * 1. Resolves the requested services via `ServiceDiscovery`.\n * 2. Wraps the downstream call in `runWithRequestContext` so any code reached\n * by the procedure (including service method implementations) can read the\n * current logger/request id via `serviceContext`.\n * 3. Merges the resolved services onto the tRPC context so handlers can access\n * them by service name (`ctx.database`, `ctx.cache`, ...).\n *\n * Two overloads:\n * - Pass an `envParser` to create a per-request `ServiceDiscovery` instance.\n * - Omit `envParser` to read `ctx.serviceDiscovery` from the tRPC context.\n *\n * @example\n * ```ts\n * import { initTRPC } from '@trpc/server';\n * import { createServicesMiddleware } from '@geekmidas/services/trpc';\n *\n * const t = initTRPC.context<Context>().create();\n * const withServices = createServicesMiddleware(t.middleware, envParser);\n *\n * export const authedProcedure = t.procedure.use(\n * withServices([databaseService, cacheService]),\n * );\n * ```\n */\nexport function createServicesMiddleware<\n\tTContext extends ContextWithLogger & object,\n\tTMeta extends object,\n>(\n\tmw: CreateMiddleware<TContext, TMeta>,\n\tenvParser: EnvironmentParser<{}>,\n): ServicesMiddleware<TContext, TMeta>;\nexport function createServicesMiddleware<\n\tTContext extends ContextWithLogger & ContextWithServiceDiscovery & object,\n\tTMeta extends object,\n>(mw: CreateMiddleware<TContext, TMeta>): ServicesMiddleware<TContext, TMeta>;\nexport function createServicesMiddleware<\n\tTContext extends ContextWithLogger & object,\n\tTMeta extends object,\n>(\n\tmw: CreateMiddleware<TContext, TMeta>,\n\tenvParser?: EnvironmentParser<{}>,\n): ServicesMiddleware<TContext, TMeta> {\n\treturn (<const T extends Service[]>(services: [...T]) => {\n\t\tconst builder = mw(async (opts) => {\n\t\t\tconst ctx = opts.ctx as TContext & Partial<ContextWithServiceDiscovery>;\n\n\t\t\tconst discovery =\n\t\t\t\tctx.serviceDiscovery ??\n\t\t\t\tServiceDiscovery.getInstance(\n\t\t\t\t\tenvParser ??\n\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\t// Hit only if overload 2 was selected but ctx.serviceDiscovery is\n\t\t\t\t\t\t\t// missing at runtime — surface the mistake immediately rather\n\t\t\t\t\t\t\t// than letting an undefined env parser fail deep inside register.\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'createServicesMiddleware: no `envParser` provided and ' +\n\t\t\t\t\t\t\t\t\t'`ctx.serviceDiscovery` is missing. Pass an EnvironmentParser ' +\n\t\t\t\t\t\t\t\t\t'to createServicesMiddleware(), or attach a ServiceDiscovery ' +\n\t\t\t\t\t\t\t\t\t'instance to the tRPC context.',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})(),\n\t\t\t\t);\n\n\t\t\tconst requestId = ctx.requestId ?? randomUUID();\n\t\t\tconst startTime = ctx.startTime ?? Date.now();\n\n\t\t\treturn runWithRequestContext(\n\t\t\t\t{ logger: ctx.logger, requestId, startTime },\n\t\t\t\tasync () => {\n\t\t\t\t\tconst resolved = await discovery.register(services);\n\t\t\t\t\treturn opts.next({\n\t\t\t\t\t\tctx: { ...opts.ctx, ...resolved } as typeof opts.ctx &\n\t\t\t\t\t\t\tServiceRecord<T>,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\n\t\t// Tag the inner middleware function with the requested services so external\n\t\t// tooling (e.g. detect-procedures route generators) can introspect a\n\t\t// procedure's service dependencies without re-executing middleware.\n\t\tconst middlewares = (\n\t\t\tbuilder as unknown as { _middlewares?: Array<{ _services?: Service[] }> }\n\t\t)._middlewares;\n\t\tif (middlewares?.length) {\n\t\t\tconst last = middlewares[middlewares.length - 1];\n\t\t\tif (last) last._services = services as unknown as Service[];\n\t\t}\n\n\t\treturn builder as TRPCMiddlewareBuilder<\n\t\t\tTContext,\n\t\t\tTMeta,\n\t\t\tServiceRecord<T>,\n\t\t\tunknown\n\t\t>;\n\t}) as ServicesMiddleware<TContext, TMeta>;\n}\n\n/**\n * Create a tRPC middleware that establishes a request context for downstream\n * code without resolving any services. Useful when services aren't needed on\n * a procedure but the handler (or libraries it calls) still wants to read\n * `serviceContext.getLogger()` / `getRequestId()` / `getRequestStartTime()`.\n *\n * `requestId` and `startTime` are pulled from the tRPC context when present,\n * otherwise generated (`randomUUID()` and `Date.now()`).\n *\n * @example\n * ```ts\n * const withRequestContext = createRequestContextMiddleware(t.middleware);\n * export const baseProcedure = t.procedure.use(withRequestContext);\n * ```\n */\nexport function createRequestContextMiddleware<\n\tTContext extends ContextWithLogger & object,\n\tTMeta extends object,\n>(\n\tmw: CreateMiddleware<TContext, TMeta>,\n): TRPCMiddlewareBuilder<TContext, TMeta, object, unknown> {\n\treturn mw(async (opts) => {\n\t\tconst ctx = opts.ctx as TContext;\n\t\tconst requestId = ctx.requestId ?? randomUUID();\n\t\tconst startTime = ctx.startTime ?? Date.now();\n\t\treturn runWithRequestContext(\n\t\t\t{ logger: ctx.logger, requestId, startTime },\n\t\t\t() => opts.next(),\n\t\t);\n\t});\n}\n"],"mappings":";;;;AAgGA,SAAgB,yBAIf,IACA,WACsC;CACtC,SAAoC,aAAqB;EACxD,MAAM,UAAU,GAAG,OAAO,SAAS;GAClC,MAAM,MAAM,KAAK;GAEjB,MAAM,YACL,IAAI,oBACJ,iBAAiB,YAChB,oBACQ;IAIN,MAAM,IAAI,MACT,8MAID;GACD,EAAA,CAAG,CACL;GAED,MAAM,YAAY,IAAI,aAAa,WAAW;GAC9C,MAAM,YAAY,IAAI,aAAa,KAAK,IAAI;GAE5C,OAAO,sBACN;IAAE,QAAQ,IAAI;IAAQ;IAAW;GAAU,GAC3C,YAAY;IACX,MAAM,WAAW,MAAM,UAAU,SAAS,QAAQ;IAClD,OAAO,KAAK,KAAK,EAChB,KAAK;KAAE,GAAG,KAAK;KAAK,GAAG;IAAS,EAEjC,CAAC;GACF,CACD;EACD,CAAC;EAKD,MAAM,cACL,QACC;EACF,IAAI,aAAa,QAAQ;GACxB,MAAM,OAAO,YAAY,YAAY,SAAS;GAC9C,IAAI,MAAM,KAAK,YAAY;EAC5B;EAEA,OAAO;CAMR;AACD;;;;;;;;;;;;;;;;AAiBA,SAAgB,+BAIf,IAC0D;CAC1D,OAAO,GAAG,OAAO,SAAS;EACzB,MAAM,MAAM,KAAK;EACjB,MAAM,YAAY,IAAI,aAAa,WAAW;EAC9C,MAAM,YAAY,IAAI,aAAa,KAAK,IAAI;EAC5C,OAAO,sBACN;GAAE,QAAQ,IAAI;GAAQ;GAAW;EAAU,SACrC,KAAK,KAAK,CACjB;CACD,CAAC;AACF"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { Logger } from "@geekmidas/logger";
|
|
2
2
|
import { EnvironmentParser } from "@geekmidas/envkit";
|
|
3
|
-
|
|
4
3
|
//#region src/types.d.ts
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* Request context available to services.
|
|
8
6
|
* Methods are guaranteed to return values when called within a request context.
|
|
@@ -37,6 +35,24 @@ interface ServiceContext {
|
|
|
37
35
|
* Use this to guard calls if you need to handle both cases.
|
|
38
36
|
*/
|
|
39
37
|
hasContext(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Who the current request is for, once its session was verified
|
|
40
|
+
* (`identifyRequest`), or `undefined` — before then, for a request with no
|
|
41
|
+
* session, and outside a request.
|
|
42
|
+
*/
|
|
43
|
+
getUser(): RequestUser | undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Who a request is for: the identity its session was verified as.
|
|
47
|
+
*
|
|
48
|
+
* An id, never an address: it rides on every log line and span of the
|
|
49
|
+
* request, and both leave the process for wherever telemetry is kept.
|
|
50
|
+
*/
|
|
51
|
+
interface RequestUser {
|
|
52
|
+
/** The user's id at the identity provider — Better Auth's `user.id`. */
|
|
53
|
+
id: string;
|
|
54
|
+
/** The session the request was made with. */
|
|
55
|
+
sessionId?: string;
|
|
40
56
|
}
|
|
41
57
|
/**
|
|
42
58
|
* Options passed to service register method.
|
|
@@ -87,7 +103,6 @@ interface Service<TName extends string = string, TInstance = unknown> {
|
|
|
87
103
|
*/
|
|
88
104
|
register(options: ServiceRegisterOptions): TInstance | Promise<TInstance>;
|
|
89
105
|
}
|
|
90
|
-
//# sourceMappingURL=types.d.ts.map
|
|
91
106
|
//#endregion
|
|
92
|
-
export { Service, ServiceContext,
|
|
93
|
-
//# sourceMappingURL=types-
|
|
107
|
+
export { ServiceRegisterOptions as i, Service as n, ServiceContext as r, RequestUser as t };
|
|
108
|
+
//# sourceMappingURL=types-BJldyZ-B.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-BJldyZ-B.d.cts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;UAQiB;;;;;;;;;;;;EAYhB,aAAa;;;;;EAMb;;;;;;EAOA;;;;;EAMA;;;;;;EAOA,WAAW;;;;;;;;UASK;;EAEhB;;EAEA;;;;;UAMgB;;EAEhB,WAAW;;EAEX,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA8BO,QAAQ,+BAA+B;;;;EAIvD,aAAa;;;;;;;EAOb,SAAS,SAAS,yBAAyB,YAAY,QAAQ"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { Logger } from "@geekmidas/logger";
|
|
2
2
|
import { EnvironmentParser } from "@geekmidas/envkit";
|
|
3
|
-
|
|
4
3
|
//#region src/types.d.ts
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* Request context available to services.
|
|
8
6
|
* Methods are guaranteed to return values when called within a request context.
|
|
@@ -37,6 +35,24 @@ interface ServiceContext {
|
|
|
37
35
|
* Use this to guard calls if you need to handle both cases.
|
|
38
36
|
*/
|
|
39
37
|
hasContext(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Who the current request is for, once its session was verified
|
|
40
|
+
* (`identifyRequest`), or `undefined` — before then, for a request with no
|
|
41
|
+
* session, and outside a request.
|
|
42
|
+
*/
|
|
43
|
+
getUser(): RequestUser | undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Who a request is for: the identity its session was verified as.
|
|
47
|
+
*
|
|
48
|
+
* An id, never an address: it rides on every log line and span of the
|
|
49
|
+
* request, and both leave the process for wherever telemetry is kept.
|
|
50
|
+
*/
|
|
51
|
+
interface RequestUser {
|
|
52
|
+
/** The user's id at the identity provider — Better Auth's `user.id`. */
|
|
53
|
+
id: string;
|
|
54
|
+
/** The session the request was made with. */
|
|
55
|
+
sessionId?: string;
|
|
40
56
|
}
|
|
41
57
|
/**
|
|
42
58
|
* Options passed to service register method.
|
|
@@ -87,7 +103,6 @@ interface Service<TName extends string = string, TInstance = unknown> {
|
|
|
87
103
|
*/
|
|
88
104
|
register(options: ServiceRegisterOptions): TInstance | Promise<TInstance>;
|
|
89
105
|
}
|
|
90
|
-
//# sourceMappingURL=types.d.ts.map
|
|
91
106
|
//#endregion
|
|
92
|
-
export { Service, ServiceContext,
|
|
93
|
-
//# sourceMappingURL=types-
|
|
107
|
+
export { ServiceRegisterOptions as i, Service as n, ServiceContext as r, RequestUser as t };
|
|
108
|
+
//# sourceMappingURL=types-BJldyZ-B.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-BJldyZ-B.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;UAQiB;;;;;;;;;;;;EAYhB,aAAa;;;;;EAMb;;;;;;EAOA;;;;;EAMA;;;;;;EAOA,WAAW;;;;;;;;UASK;;EAEhB;;EAEA;;;;;UAMgB;;EAEhB,WAAW;;EAEX,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA8BO,QAAQ,+BAA+B;;;;EAIvD,aAAa;;;;;;;EAOb,SAAS,SAAS,yBAAyB,YAAY,QAAQ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/services",
|
|
3
|
-
"version": "10.0.0-alpha.
|
|
3
|
+
"version": "10.0.0-alpha.110",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"@middy/core": ">=7.9.2",
|
|
62
62
|
"@trpc/server": ">=11.19.0",
|
|
63
63
|
"@types/aws-lambda": ">=8.10.163",
|
|
64
|
-
"@geekmidas/envkit": "^10.0.0-alpha.
|
|
65
|
-
"@geekmidas/logger": "^10.0.0-alpha.
|
|
64
|
+
"@geekmidas/envkit": "^10.0.0-alpha.110",
|
|
65
|
+
"@geekmidas/logger": "^10.0.0-alpha.110"
|
|
66
66
|
},
|
|
67
67
|
"peerDependenciesMeta": {
|
|
68
68
|
"@geekmidas/envkit": {
|
|
@@ -86,10 +86,11 @@
|
|
|
86
86
|
"@trpc/server": "~11.19.0",
|
|
87
87
|
"@types/aws-lambda": "~8.10.163",
|
|
88
88
|
"@types/node": "~24.9.1",
|
|
89
|
-
"@geekmidas/envkit": "^10.0.0-alpha.
|
|
90
|
-
"@geekmidas/logger": "^10.0.0-alpha.
|
|
89
|
+
"@geekmidas/envkit": "^10.0.0-alpha.110",
|
|
90
|
+
"@geekmidas/logger": "^10.0.0-alpha.110"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
|
-
"ts": "tsc --noEmit --skipLibCheck src/**/*.ts"
|
|
93
|
+
"ts": "tsc --noEmit --skipLibCheck src/**/*.ts",
|
|
94
|
+
"build": "tsdown --config ../../tsdown.config.ts --filter ."
|
|
94
95
|
}
|
|
95
96
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceDiscovery-BO8W-RY8.d.cts","names":[],"sources":["../src/ServiceDiscovery.ts"],"sourcesContent":[],"mappings":";;;;;;;AAkCA;;;;;;;;;;;;;;;;;;;;;;;;;;AAgL8B;AAoB9B;AAA+B,cApMlB,gBAoMkB,CAAA,kBApMiB,MAoMjB,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA;EAAA,SAAW,SAAA,EAlJT,iBAkJS,CAAA,CAAA,CAAA,CAAA;EAAO;EAAO,eAAA,SAAA;EAiB5C;EAAa,QAAA,QAAA;EAAA;EAAkB,QACpC,SAAA;EAAC;;;;;;AACG;;;;;;;+BAlMmB,uCACjB,wBACT,iBAAiB;;;;;;;;;;;;;;;;;;yBA2BY;;;;;;;;;;;;;;;;;;;;;;;;;qBA0BP,qBAAqB,IAAI,QAAQ,cAAc;;;;;;;;;;;;;;;;sBAwCpD,0BAA0B,IAAI,QAAQ,UAAU;;;;;;;;;;;;;;;;;;2BA6BrC,kCACnB,KACT,gBAAgB,YAAY,UAAU;;;;;;;;;;;;;;;;;;;;wBA6BnB;;;;;;;;;;;;;KAoBX,8BAA8B,aAAa;;;;;;;;;;;;;;;;KAiB3C,wBAAwB,qBAC7B,aAAa,mBAAmB,UAAU,UAC7C,QAAQ,WAAW"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceDiscovery-BrCUabG_.cjs","names":["envParser: EnvironmentParser<{}>","services: T","serviceContext","name: K","names: [...K]","service: string | Service"],"sources":["../src/ServiceDiscovery.ts"],"sourcesContent":["import type { EnvironmentParser } from '@geekmidas/envkit';\nimport { serviceContext } from './context';\nimport type { Service } from './types';\n\n/**\n * Service discovery container that manages service registration and retrieval.\n * Implements a singleton pattern with lazy initialization of services.\n *\n * @template TServices - Record type mapping service names to their instance types\n *\n * @example\n * ```typescript\n * // Define service types\n * interface MyServices {\n * database: Database;\n * cache: CacheService;\n * auth: AuthService;\n * }\n *\n * // Get service discovery instance\n * const discovery = ServiceDiscovery.getInstance<MyServices>(envParser);\n *\n * // Register services\n * await discovery.register([\n * databaseService,\n * cacheService,\n * authService\n * ]);\n *\n * // Retrieve services\n * const db = await discovery.get('database');\n * const { cache, auth } = await discovery.getMany(['cache', 'auth']);\n * ```\n */\nexport class ServiceDiscovery<TServices extends Record<string, unknown> = {}> {\n\t/** Singleton instance of ServiceDiscovery */\n\tprivate static _instance: ServiceDiscovery<any>;\n\t/** Map of registered service definitions */\n\tprivate services = new Map<string, Service>();\n\t/** Map of instantiated service instances */\n\tprivate instances = new Map<keyof TServices, TServices[keyof TServices]>();\n\n\t/**\n\t * Gets the singleton instance of ServiceDiscovery.\n\t * Creates a new instance if one doesn't exist.\n\t *\n\t * @template T - Record type mapping service names to their instance types\n\t * @param envParser - Environment parser for service configuration\n\t * @returns The ServiceDiscovery singleton instance\n\t *\n\t * @example\n\t * ```typescript\n\t * const services = ServiceDiscovery.getInstance<MyServices>(envParser);\n\t * ```\n\t */\n\tstatic getInstance<T extends Record<any, unknown> = any>(\n\t\tenvParser: EnvironmentParser<{}>,\n\t): ServiceDiscovery<T> {\n\t\tif (!ServiceDiscovery._instance) {\n\t\t\tServiceDiscovery._instance = new ServiceDiscovery<T>(envParser);\n\t\t}\n\t\treturn ServiceDiscovery._instance as ServiceDiscovery<T>;\n\t}\n\n\t/**\n\t * Resets the singleton instance. Use only for testing purposes.\n\t * This clears all cached services and allows a fresh instance to be created.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In test teardown\n\t * afterEach(() => {\n\t * ServiceDiscovery.reset();\n\t * });\n\t * ```\n\t */\n\tstatic reset(): void {\n\t\tServiceDiscovery._instance = undefined as any;\n\t}\n\n\t/**\n\t *\n\t * @param envParser - Environment parser for service configuration\n\t */\n\tconstructor(readonly envParser: EnvironmentParser<{}>) {}\n\n\t/**\n\t * Register multiple services with the service discovery.\n\t * Services are instantiated lazily on first access.\n\t * Already instantiated services are returned from cache.\n\t *\n\t * @template T - Array type of services to register\n\t * @param services - Array of services to register\n\t * @returns Promise resolving to a record of service names to instances\n\t *\n\t * @example\n\t * ```typescript\n\t * const services = await discovery.register([\n\t * databaseService,\n\t * cacheService,\n\t * authService\n\t * ]);\n\t *\n\t * // services = {\n\t * // database: Database instance,\n\t * // cache: CacheService instance,\n\t * // auth: AuthService instance\n\t * // }\n\t * ```\n\t */\n\tasync register<T extends Service[]>(services: T): Promise<ServiceRecord<T>> {\n\t\tconst registeredServices = {} as ServiceRecord<T>;\n\t\tfor (const service of services) {\n\t\t\tconst name = service.serviceName as T[number]['serviceName'];\n\t\t\tif (this.instances.has(name)) {\n\t\t\t\t(registeredServices as any)[name] = this.instances.get(\n\t\t\t\t\tname,\n\t\t\t\t) as TServices[keyof TServices];\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Pass both envParser and context to service\n\t\t\tconst instance = await service.register({\n\t\t\t\tenvParser: this.envParser,\n\t\t\t\tcontext: serviceContext,\n\t\t\t});\n\n\t\t\tthis.instances.set(name, instance as TServices[keyof TServices]);\n\t\t\t(registeredServices as any)[name] =\n\t\t\t\tinstance as TServices[keyof TServices];\n\t\t}\n\n\t\treturn registeredServices;\n\t}\n\n\t/**\n\t * Get a service from the service discovery.\n\t * Services are instantiated on first access if not already cached.\n\t *\n\t * @template K - The service name key\n\t * @param name - The name of the service to get\n\t * @returns Promise resolving to the service instance\n\t * @throws {Error} If the service is not registered\n\t *\n\t * @example\n\t * ```typescript\n\t * const database = await discovery.get('database');\n\t * const users = await database.query('SELECT * FROM users');\n\t * ```\n\t */\n\tget<K extends keyof TServices & string>(name: K): Promise<TServices[K]> {\n\t\tconst service = this.services.get(name);\n\n\t\tif (!service) {\n\t\t\tthrow new Error(`Service '${name}' not found in service discovery`);\n\t\t}\n\n\t\treturn service.register({\n\t\t\tenvParser: this.envParser,\n\t\t\tcontext: serviceContext,\n\t\t}) as Promise<TServices[K]>;\n\t}\n\t/**\n\t * Get multiple services from the service discovery.\n\t * Useful for retrieving multiple dependencies at once.\n\t *\n\t * @template K - Array of service name keys\n\t * @param names - Array of service names to retrieve\n\t * @returns Promise resolving to an object containing the service instances\n\t *\n\t * @example\n\t * ```typescript\n\t * const { database, cache, auth } = await discovery.getMany([\n\t * 'database',\n\t * 'cache',\n\t * 'auth'\n\t * ]);\n\t * ```\n\t */\n\tasync getMany<K extends (keyof TServices & string)[]>(\n\t\tnames: [...K],\n\t): Promise<{ [P in K[number]]: TServices[P] }> {\n\t\tconst result = {} as { [P in K[number]]: TServices[P] };\n\n\t\tfor (const name of names) {\n\t\t\tresult[name] = await this.get(name);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Check if a service exists in the service discovery.\n\t * Can check by service name or service instance.\n\t *\n\t * @param service - The service name or service instance to check\n\t * @returns True if the service exists, false otherwise\n\t *\n\t * @example\n\t * ```typescript\n\t * if (discovery.has('database')) {\n\t * const db = await discovery.get('database');\n\t * }\n\t *\n\t * // Or check with service instance\n\t * if (!discovery.has(databaseService)) {\n\t * await discovery.register([databaseService]);\n\t * }\n\t * ```\n\t */\n\thas(service: string | Service): boolean {\n\t\tif (typeof service === 'string') {\n\t\t\treturn this.services.has(service);\n\t\t}\n\n\t\treturn this.services.has(service.serviceName);\n\t}\n}\n\n/**\n * Utility type to extract service names from an array of services.\n *\n * @template T - Array of Service types\n *\n * @example\n * ```typescript\n * type Names = ExtractServiceNames<[typeof databaseService, typeof cacheService]>;\n * // type Names = 'database' | 'cache'\n * ```\n */\nexport type ExtractServiceNames<T extends Service[]> = T[number]['serviceName'];\n\n/**\n * Utility type to create a record type from an array of services.\n * Maps service names to their registered instance types.\n *\n * @template T - Array of Service types\n *\n * @example\n * ```typescript\n * type MyServiceRecord = ServiceRecord<[typeof databaseService, typeof cacheService]>;\n * // type MyServiceRecord = {\n * // database: DatabaseInstance;\n * // cache: CacheInstance;\n * // }\n * ```\n */\nexport type ServiceRecord<T extends Service[]> = {\n\t[K in T[number] as K['serviceName']]: K extends Service\n\t\t? Awaited<ReturnType<K['register']>>\n\t\t: never;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,IAAa,mBAAb,MAAa,iBAAiE;;CAE7E,OAAe;;CAEf,AAAQ,2BAAW,IAAI;;CAEvB,AAAQ,4BAAY,IAAI;;;;;;;;;;;;;;CAexB,OAAO,YACNA,WACsB;AACtB,OAAK,iBAAiB,UACrB,kBAAiB,YAAY,IAAI,iBAAoB;AAEtD,SAAO,iBAAiB;CACxB;;;;;;;;;;;;;CAcD,OAAO,QAAc;AACpB,mBAAiB;CACjB;;;;;CAMD,YAAqBA,WAAkC;EAAlC;CAAoC;;;;;;;;;;;;;;;;;;;;;;;;;CA0BzD,MAAM,SAA8BC,UAAwC;EAC3E,MAAM,qBAAqB,CAAE;AAC7B,OAAK,MAAM,WAAW,UAAU;GAC/B,MAAM,OAAO,QAAQ;AACrB,OAAI,KAAK,UAAU,IAAI,KAAK,EAAE;AAC7B,IAAC,mBAA2B,QAAQ,KAAK,UAAU,IAClD,KACA;AACD;GACA;GAGD,MAAM,WAAW,MAAM,QAAQ,SAAS;IACvC,WAAW,KAAK;IAChB,SAASC;GACT,EAAC;AAEF,QAAK,UAAU,IAAI,MAAM,SAAuC;AAChE,GAAC,mBAA2B,QAC3B;EACD;AAED,SAAO;CACP;;;;;;;;;;;;;;;;CAiBD,IAAwCC,MAAgC;EACvE,MAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AAEvC,OAAK,QACJ,OAAM,IAAI,OAAO,WAAW,KAAK;AAGlC,SAAO,QAAQ,SAAS;GACvB,WAAW,KAAK;GAChB,SAASD;EACT,EAAC;CACF;;;;;;;;;;;;;;;;;;CAkBD,MAAM,QACLE,OAC8C;EAC9C,MAAM,SAAS,CAAE;AAEjB,OAAK,MAAM,QAAQ,MAClB,QAAO,QAAQ,MAAM,KAAK,IAAI,KAAK;AAGpC,SAAO;CACP;;;;;;;;;;;;;;;;;;;;CAqBD,IAAIC,SAAoC;AACvC,aAAW,YAAY,SACtB,QAAO,KAAK,SAAS,IAAI,QAAQ;AAGlC,SAAO,KAAK,SAAS,IAAI,QAAQ,YAAY;CAC7C;AACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceDiscovery-CRq_bGbi.d.mts","names":[],"sources":["../src/ServiceDiscovery.ts"],"sourcesContent":[],"mappings":";;;;;;;AAkCA;;;;;;;;;;;;;;;;;;;;;;;;;;AAgL8B;AAoB9B;AAA+B,cApMlB,gBAoMkB,CAAA,kBApMiB,MAoMjB,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA;EAAA,SAAW,SAAA,EAlJT,iBAkJS,CAAA,CAAA,CAAA,CAAA;EAAO;EAAO,eAAA,SAAA;EAiB5C;EAAa,QAAA,QAAA;EAAA;EAAkB,QACpC,SAAA;EAAC;;;;;;AACG;;;;;;;+BAlMmB,uCACjB,wBACT,iBAAiB;;;;;;;;;;;;;;;;;;yBA2BY;;;;;;;;;;;;;;;;;;;;;;;;;qBA0BP,qBAAqB,IAAI,QAAQ,cAAc;;;;;;;;;;;;;;;;sBAwCpD,0BAA0B,IAAI,QAAQ,UAAU;;;;;;;;;;;;;;;;;;2BA6BrC,kCACnB,KACT,gBAAgB,YAAY,UAAU;;;;;;;;;;;;;;;;;;;;wBA6BnB;;;;;;;;;;;;;KAoBX,8BAA8B,aAAa;;;;;;;;;;;;;;;;KAiB3C,wBAAwB,qBAC7B,aAAa,mBAAmB,UAAU,UAC7C,QAAQ,WAAW"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceDiscovery-WHikQSQv.mjs","names":["envParser: EnvironmentParser<{}>","services: T","name: K","names: [...K]","service: string | Service"],"sources":["../src/ServiceDiscovery.ts"],"sourcesContent":["import type { EnvironmentParser } from '@geekmidas/envkit';\nimport { serviceContext } from './context';\nimport type { Service } from './types';\n\n/**\n * Service discovery container that manages service registration and retrieval.\n * Implements a singleton pattern with lazy initialization of services.\n *\n * @template TServices - Record type mapping service names to their instance types\n *\n * @example\n * ```typescript\n * // Define service types\n * interface MyServices {\n * database: Database;\n * cache: CacheService;\n * auth: AuthService;\n * }\n *\n * // Get service discovery instance\n * const discovery = ServiceDiscovery.getInstance<MyServices>(envParser);\n *\n * // Register services\n * await discovery.register([\n * databaseService,\n * cacheService,\n * authService\n * ]);\n *\n * // Retrieve services\n * const db = await discovery.get('database');\n * const { cache, auth } = await discovery.getMany(['cache', 'auth']);\n * ```\n */\nexport class ServiceDiscovery<TServices extends Record<string, unknown> = {}> {\n\t/** Singleton instance of ServiceDiscovery */\n\tprivate static _instance: ServiceDiscovery<any>;\n\t/** Map of registered service definitions */\n\tprivate services = new Map<string, Service>();\n\t/** Map of instantiated service instances */\n\tprivate instances = new Map<keyof TServices, TServices[keyof TServices]>();\n\n\t/**\n\t * Gets the singleton instance of ServiceDiscovery.\n\t * Creates a new instance if one doesn't exist.\n\t *\n\t * @template T - Record type mapping service names to their instance types\n\t * @param envParser - Environment parser for service configuration\n\t * @returns The ServiceDiscovery singleton instance\n\t *\n\t * @example\n\t * ```typescript\n\t * const services = ServiceDiscovery.getInstance<MyServices>(envParser);\n\t * ```\n\t */\n\tstatic getInstance<T extends Record<any, unknown> = any>(\n\t\tenvParser: EnvironmentParser<{}>,\n\t): ServiceDiscovery<T> {\n\t\tif (!ServiceDiscovery._instance) {\n\t\t\tServiceDiscovery._instance = new ServiceDiscovery<T>(envParser);\n\t\t}\n\t\treturn ServiceDiscovery._instance as ServiceDiscovery<T>;\n\t}\n\n\t/**\n\t * Resets the singleton instance. Use only for testing purposes.\n\t * This clears all cached services and allows a fresh instance to be created.\n\t *\n\t * @example\n\t * ```typescript\n\t * // In test teardown\n\t * afterEach(() => {\n\t * ServiceDiscovery.reset();\n\t * });\n\t * ```\n\t */\n\tstatic reset(): void {\n\t\tServiceDiscovery._instance = undefined as any;\n\t}\n\n\t/**\n\t *\n\t * @param envParser - Environment parser for service configuration\n\t */\n\tconstructor(readonly envParser: EnvironmentParser<{}>) {}\n\n\t/**\n\t * Register multiple services with the service discovery.\n\t * Services are instantiated lazily on first access.\n\t * Already instantiated services are returned from cache.\n\t *\n\t * @template T - Array type of services to register\n\t * @param services - Array of services to register\n\t * @returns Promise resolving to a record of service names to instances\n\t *\n\t * @example\n\t * ```typescript\n\t * const services = await discovery.register([\n\t * databaseService,\n\t * cacheService,\n\t * authService\n\t * ]);\n\t *\n\t * // services = {\n\t * // database: Database instance,\n\t * // cache: CacheService instance,\n\t * // auth: AuthService instance\n\t * // }\n\t * ```\n\t */\n\tasync register<T extends Service[]>(services: T): Promise<ServiceRecord<T>> {\n\t\tconst registeredServices = {} as ServiceRecord<T>;\n\t\tfor (const service of services) {\n\t\t\tconst name = service.serviceName as T[number]['serviceName'];\n\t\t\tif (this.instances.has(name)) {\n\t\t\t\t(registeredServices as any)[name] = this.instances.get(\n\t\t\t\t\tname,\n\t\t\t\t) as TServices[keyof TServices];\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Pass both envParser and context to service\n\t\t\tconst instance = await service.register({\n\t\t\t\tenvParser: this.envParser,\n\t\t\t\tcontext: serviceContext,\n\t\t\t});\n\n\t\t\tthis.instances.set(name, instance as TServices[keyof TServices]);\n\t\t\t(registeredServices as any)[name] =\n\t\t\t\tinstance as TServices[keyof TServices];\n\t\t}\n\n\t\treturn registeredServices;\n\t}\n\n\t/**\n\t * Get a service from the service discovery.\n\t * Services are instantiated on first access if not already cached.\n\t *\n\t * @template K - The service name key\n\t * @param name - The name of the service to get\n\t * @returns Promise resolving to the service instance\n\t * @throws {Error} If the service is not registered\n\t *\n\t * @example\n\t * ```typescript\n\t * const database = await discovery.get('database');\n\t * const users = await database.query('SELECT * FROM users');\n\t * ```\n\t */\n\tget<K extends keyof TServices & string>(name: K): Promise<TServices[K]> {\n\t\tconst service = this.services.get(name);\n\n\t\tif (!service) {\n\t\t\tthrow new Error(`Service '${name}' not found in service discovery`);\n\t\t}\n\n\t\treturn service.register({\n\t\t\tenvParser: this.envParser,\n\t\t\tcontext: serviceContext,\n\t\t}) as Promise<TServices[K]>;\n\t}\n\t/**\n\t * Get multiple services from the service discovery.\n\t * Useful for retrieving multiple dependencies at once.\n\t *\n\t * @template K - Array of service name keys\n\t * @param names - Array of service names to retrieve\n\t * @returns Promise resolving to an object containing the service instances\n\t *\n\t * @example\n\t * ```typescript\n\t * const { database, cache, auth } = await discovery.getMany([\n\t * 'database',\n\t * 'cache',\n\t * 'auth'\n\t * ]);\n\t * ```\n\t */\n\tasync getMany<K extends (keyof TServices & string)[]>(\n\t\tnames: [...K],\n\t): Promise<{ [P in K[number]]: TServices[P] }> {\n\t\tconst result = {} as { [P in K[number]]: TServices[P] };\n\n\t\tfor (const name of names) {\n\t\t\tresult[name] = await this.get(name);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Check if a service exists in the service discovery.\n\t * Can check by service name or service instance.\n\t *\n\t * @param service - The service name or service instance to check\n\t * @returns True if the service exists, false otherwise\n\t *\n\t * @example\n\t * ```typescript\n\t * if (discovery.has('database')) {\n\t * const db = await discovery.get('database');\n\t * }\n\t *\n\t * // Or check with service instance\n\t * if (!discovery.has(databaseService)) {\n\t * await discovery.register([databaseService]);\n\t * }\n\t * ```\n\t */\n\thas(service: string | Service): boolean {\n\t\tif (typeof service === 'string') {\n\t\t\treturn this.services.has(service);\n\t\t}\n\n\t\treturn this.services.has(service.serviceName);\n\t}\n}\n\n/**\n * Utility type to extract service names from an array of services.\n *\n * @template T - Array of Service types\n *\n * @example\n * ```typescript\n * type Names = ExtractServiceNames<[typeof databaseService, typeof cacheService]>;\n * // type Names = 'database' | 'cache'\n * ```\n */\nexport type ExtractServiceNames<T extends Service[]> = T[number]['serviceName'];\n\n/**\n * Utility type to create a record type from an array of services.\n * Maps service names to their registered instance types.\n *\n * @template T - Array of Service types\n *\n * @example\n * ```typescript\n * type MyServiceRecord = ServiceRecord<[typeof databaseService, typeof cacheService]>;\n * // type MyServiceRecord = {\n * // database: DatabaseInstance;\n * // cache: CacheInstance;\n * // }\n * ```\n */\nexport type ServiceRecord<T extends Service[]> = {\n\t[K in T[number] as K['serviceName']]: K extends Service\n\t\t? Awaited<ReturnType<K['register']>>\n\t\t: never;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,IAAa,mBAAb,MAAa,iBAAiE;;CAE7E,OAAe;;CAEf,AAAQ,2BAAW,IAAI;;CAEvB,AAAQ,4BAAY,IAAI;;;;;;;;;;;;;;CAexB,OAAO,YACNA,WACsB;AACtB,OAAK,iBAAiB,UACrB,kBAAiB,YAAY,IAAI,iBAAoB;AAEtD,SAAO,iBAAiB;CACxB;;;;;;;;;;;;;CAcD,OAAO,QAAc;AACpB,mBAAiB;CACjB;;;;;CAMD,YAAqBA,WAAkC;EAAlC;CAAoC;;;;;;;;;;;;;;;;;;;;;;;;;CA0BzD,MAAM,SAA8BC,UAAwC;EAC3E,MAAM,qBAAqB,CAAE;AAC7B,OAAK,MAAM,WAAW,UAAU;GAC/B,MAAM,OAAO,QAAQ;AACrB,OAAI,KAAK,UAAU,IAAI,KAAK,EAAE;AAC7B,IAAC,mBAA2B,QAAQ,KAAK,UAAU,IAClD,KACA;AACD;GACA;GAGD,MAAM,WAAW,MAAM,QAAQ,SAAS;IACvC,WAAW,KAAK;IAChB,SAAS;GACT,EAAC;AAEF,QAAK,UAAU,IAAI,MAAM,SAAuC;AAChE,GAAC,mBAA2B,QAC3B;EACD;AAED,SAAO;CACP;;;;;;;;;;;;;;;;CAiBD,IAAwCC,MAAgC;EACvE,MAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AAEvC,OAAK,QACJ,OAAM,IAAI,OAAO,WAAW,KAAK;AAGlC,SAAO,QAAQ,SAAS;GACvB,WAAW,KAAK;GAChB,SAAS;EACT,EAAC;CACF;;;;;;;;;;;;;;;;;;CAkBD,MAAM,QACLC,OAC8C;EAC9C,MAAM,SAAS,CAAE;AAEjB,OAAK,MAAM,QAAQ,MAClB,QAAO,QAAQ,MAAM,KAAK,IAAI,KAAK;AAGpC,SAAO;CACP;;;;;;;;;;;;;;;;;;;;CAqBD,IAAIC,SAAoC;AACvC,aAAW,YAAY,SACtB,QAAO,KAAK,SAAS,IAAI,QAAQ;AAGlC,SAAO,KAAK,SAAS,IAAI,QAAQ,YAAY;CAC7C;AACD"}
|