@nodii/grpc-interceptors 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compose.d.ts +7 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +20 -0
- package/dist/compose.js.map +1 -0
- package/dist/configure.d.ts +66 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +169 -0
- package/dist/configure.js.map +1 -0
- package/dist/factory.d.ts +7 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +100 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -4
- package/dist/index.js.map +1 -1
- package/dist/interceptors/audit-context.d.ts +3 -0
- package/dist/interceptors/audit-context.d.ts.map +1 -0
- package/dist/interceptors/audit-context.js +59 -0
- package/dist/interceptors/audit-context.js.map +1 -0
- package/dist/interceptors/audit.d.ts +7 -0
- package/dist/interceptors/audit.d.ts.map +1 -0
- package/dist/interceptors/audit.js +111 -0
- package/dist/interceptors/audit.js.map +1 -0
- package/dist/interceptors/cancellation-guard.d.ts +3 -0
- package/dist/interceptors/cancellation-guard.d.ts.map +1 -0
- package/dist/interceptors/cancellation-guard.js +54 -0
- package/dist/interceptors/cancellation-guard.js.map +1 -0
- package/dist/interceptors/deadline-guard.d.ts +3 -0
- package/dist/interceptors/deadline-guard.d.ts.map +1 -0
- package/dist/interceptors/deadline-guard.js +90 -0
- package/dist/interceptors/deadline-guard.js.map +1 -0
- package/dist/interceptors/enrich-auth.d.ts +3 -0
- package/dist/interceptors/enrich-auth.d.ts.map +1 -0
- package/dist/interceptors/enrich-auth.js +85 -0
- package/dist/interceptors/enrich-auth.js.map +1 -0
- package/dist/interceptors/error-map.d.ts +4 -0
- package/dist/interceptors/error-map.d.ts.map +1 -0
- package/dist/interceptors/error-map.js +94 -0
- package/dist/interceptors/error-map.js.map +1 -0
- package/dist/interceptors/logging.d.ts +7 -0
- package/dist/interceptors/logging.d.ts.map +1 -0
- package/dist/interceptors/logging.js +66 -0
- package/dist/interceptors/logging.js.map +1 -0
- package/dist/interceptors/saga-headers.d.ts +23 -0
- package/dist/interceptors/saga-headers.d.ts.map +1 -0
- package/dist/interceptors/saga-headers.js +40 -0
- package/dist/interceptors/saga-headers.js.map +1 -0
- package/dist/interceptors/signal-binder.d.ts +3 -0
- package/dist/interceptors/signal-binder.d.ts.map +1 -0
- package/dist/interceptors/signal-binder.js +83 -0
- package/dist/interceptors/signal-binder.js.map +1 -0
- package/dist/interceptors/tenant-context.d.ts +3 -0
- package/dist/interceptors/tenant-context.d.ts.map +1 -0
- package/dist/interceptors/tenant-context.js +40 -0
- package/dist/interceptors/tenant-context.js.map +1 -0
- package/dist/interceptors-exports.d.ts +9 -0
- package/dist/interceptors-exports.d.ts.map +1 -0
- package/dist/interceptors-exports.js +12 -0
- package/dist/interceptors-exports.js.map +1 -0
- package/dist/reexports.d.ts +10 -0
- package/dist/reexports.d.ts.map +1 -0
- package/dist/reexports.js +27 -0
- package/dist/reexports.js.map +1 -0
- package/dist/telemetry-shim.d.ts +12 -0
- package/dist/telemetry-shim.d.ts.map +1 -0
- package/dist/telemetry-shim.js +94 -0
- package/dist/telemetry-shim.js.map +1 -0
- package/dist/types.d.ts +228 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +36 -0
- package/dist/types.js.map +1 -0
- package/package.json +14 -7
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// withSagaHeaders — spec § 5.1.
|
|
2
|
+
//
|
|
3
|
+
// D25 client-side header auto-injector. When a saga is active on the
|
|
4
|
+
// current ALS context (via `@nodii/saga.currentSaga()`), stamps:
|
|
5
|
+
//
|
|
6
|
+
// - x-nodii-saga-id — the active saga id
|
|
7
|
+
// - x-nodii-saga-tenant-id — the active saga tenant (if any)
|
|
8
|
+
//
|
|
9
|
+
// onto outbound gRPC metadata. This is the @grpc/grpc-js client
|
|
10
|
+
// interceptor shape — returns an interceptor factory that the consumer
|
|
11
|
+
// passes to `grpc.credentials.createFromInterceptors` or the client
|
|
12
|
+
// constructor's `interceptors` option.
|
|
13
|
+
//
|
|
14
|
+
// When no saga is active or `@nodii/saga` is not initialized: the
|
|
15
|
+
// interceptor is still installed but adds no headers (pure passthrough).
|
|
16
|
+
import { currentSaga, getSagaOrNull } from "@nodii/saga";
|
|
17
|
+
export function withSagaHeaders() {
|
|
18
|
+
return (options) => {
|
|
19
|
+
const saga = getSagaOrNull();
|
|
20
|
+
if (!saga)
|
|
21
|
+
return;
|
|
22
|
+
try {
|
|
23
|
+
const handle = currentSaga();
|
|
24
|
+
if (!handle)
|
|
25
|
+
return;
|
|
26
|
+
const md = options.metadata;
|
|
27
|
+
if (!md)
|
|
28
|
+
return;
|
|
29
|
+
md.set("x-nodii-saga-id", handle.id);
|
|
30
|
+
if (handle.tenantId) {
|
|
31
|
+
md.set("x-nodii-saga-tenant-id", handle.tenantId);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// currentSaga() throws when no saga in ALS — that's fine, just
|
|
36
|
+
// skip header injection.
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=saga-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saga-headers.js","sourceRoot":"","sources":["../../src/interceptors/saga-headers.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,EAAE;AACF,qEAAqE;AACrE,iEAAiE;AACjE,EAAE;AACF,sDAAsD;AACtD,mEAAmE;AACnE,EAAE;AACF,gEAAgE;AAChE,uEAAuE;AACvE,oEAAoE;AACpE,uCAAuC;AACvC,EAAE;AACF,kEAAkE;AAClE,yEAAyE;AAEzE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAyBzD,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,OAA0B,EAAQ,EAAE;QAC1C,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;YAC5B,IAAI,CAAC,EAAE;gBAAE,OAAO;YAChB,EAAE,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACpB,EAAE,CAAC,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,yBAAyB;QAC3B,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-binder.d.ts","sourceRoot":"","sources":["../../src/interceptors/signal-binder.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAA2B,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAiB1E,wBAAgB,YAAY,IAAI,gBAAgB,CAgD/C"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// signalBinder — spec § 5.4 line 6.
|
|
2
|
+
//
|
|
3
|
+
// Server-side interceptor that reads inbound `x-nodii-saga-signal-*`
|
|
4
|
+
// headers on the call and (if a signal payload was attached out-of-band)
|
|
5
|
+
// routes it into the saga signal bus so the handler can `awaitSagaSignal`
|
|
6
|
+
// it. This bridges the gRPC transport to the saga signal-bus surface.
|
|
7
|
+
//
|
|
8
|
+
// Headers consumed:
|
|
9
|
+
// - `x-nodii-saga-signal-event-type` — the event type to publish
|
|
10
|
+
// - `x-nodii-saga-signal-payload` — JSON payload (utf-8)
|
|
11
|
+
// - `x-nodii-saga-signal-from` — origin saga id
|
|
12
|
+
// - `x-nodii-saga-signal-scope` — siblings | global (default siblings)
|
|
13
|
+
//
|
|
14
|
+
// When `x-nodii-saga-signal-event-type` is absent: no-op passthrough.
|
|
15
|
+
// When `@nodii/saga` is not initialized: also no-op (defensive — test
|
|
16
|
+
// harnesses + services that don't run saga can still use this lib's
|
|
17
|
+
// stack).
|
|
18
|
+
import { getSagaOrNull } from "@nodii/saga";
|
|
19
|
+
import { resolveTelemetry } from "../telemetry-shim";
|
|
20
|
+
function readHeader(call, key) {
|
|
21
|
+
const values = call.metadata?.get(key);
|
|
22
|
+
if (!values || values.length === 0)
|
|
23
|
+
return undefined;
|
|
24
|
+
const first = values[0];
|
|
25
|
+
if (typeof first === "string")
|
|
26
|
+
return first;
|
|
27
|
+
if (first instanceof Uint8Array || Buffer.isBuffer?.(first)) {
|
|
28
|
+
try {
|
|
29
|
+
return Buffer.from(first).toString("utf8");
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
export function signalBinder() {
|
|
38
|
+
return (_methodName, handler) => {
|
|
39
|
+
return async (call) => {
|
|
40
|
+
const eventType = readHeader(call, "x-nodii-saga-signal-event-type");
|
|
41
|
+
if (!eventType)
|
|
42
|
+
return handler(call);
|
|
43
|
+
const saga = getSagaOrNull();
|
|
44
|
+
if (!saga) {
|
|
45
|
+
// Saga library not initialized — defensive no-op.
|
|
46
|
+
return handler(call);
|
|
47
|
+
}
|
|
48
|
+
const fromSaga = readHeader(call, "x-nodii-saga-signal-from");
|
|
49
|
+
const payloadRaw = readHeader(call, "x-nodii-saga-signal-payload");
|
|
50
|
+
const scopeRaw = readHeader(call, "x-nodii-saga-signal-scope");
|
|
51
|
+
const scope = scopeRaw === "global" ? "global" : "siblings";
|
|
52
|
+
let payload = null;
|
|
53
|
+
if (payloadRaw) {
|
|
54
|
+
try {
|
|
55
|
+
payload = JSON.parse(payloadRaw);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
payload = payloadRaw;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// We can't address a saga we're not the owner of; instead we publish
|
|
62
|
+
// to the bus tagged with `from` so awaitSagaSignal observers can pick
|
|
63
|
+
// it up. The saga signal-bus accepts emit() from any context.
|
|
64
|
+
try {
|
|
65
|
+
await saga.signalBus.emit({
|
|
66
|
+
sagaId: fromSaga ?? "external",
|
|
67
|
+
eventType,
|
|
68
|
+
payload,
|
|
69
|
+
scope,
|
|
70
|
+
to: undefined,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
resolveTelemetry().logger.warn("signal_binder.emit_failed", {
|
|
75
|
+
event_type: eventType,
|
|
76
|
+
error: err instanceof Error ? err.message : String(err),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return handler(call);
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=signal-binder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-binder.js","sourceRoot":"","sources":["../../src/interceptors/signal-binder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-context.d.ts","sourceRoot":"","sources":["../../src/interceptors/tenant-context.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,mBAAmB,EAGnB,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAGlB,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,gBAAgB,CAmC3E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// tenantContext — spec § 5.8.
|
|
2
|
+
//
|
|
3
|
+
// On call entry: issues `SET LOCAL app.tenant_id = '<tenant_id>'` on the
|
|
4
|
+
// configured Postgres connection. If `call.auth.userActor` is present, also
|
|
5
|
+
// sets `app.user_id`. Skipped for methods in `systemContextMethods`.
|
|
6
|
+
//
|
|
7
|
+
// The connection lifecycle (acquire / release) is the *consumer's*
|
|
8
|
+
// responsibility — this library only writes the GUC. Real wiring with
|
|
9
|
+
// `pg.Pool` / `drizzle` rides as `DbConnection`.
|
|
10
|
+
import { GrpcStatusError } from "../types";
|
|
11
|
+
export function tenantContext(config) {
|
|
12
|
+
if (!config.db) {
|
|
13
|
+
throw new GrpcStatusError("INTERNAL", "tenant_context_db_unconfigured");
|
|
14
|
+
}
|
|
15
|
+
const systemMethods = config.systemContextMethods ?? new Set();
|
|
16
|
+
return (methodName, handler) => {
|
|
17
|
+
return async (call) => {
|
|
18
|
+
if (systemMethods.has(methodName))
|
|
19
|
+
return handler(call);
|
|
20
|
+
const tenantId = call.auth?.requestContext?.tenant_id;
|
|
21
|
+
if (!tenantId) {
|
|
22
|
+
// enrichAuthContext should have rejected — defensive.
|
|
23
|
+
throw new GrpcStatusError("FAILED_PRECONDITION", "tenant_context_required");
|
|
24
|
+
}
|
|
25
|
+
// `SET LOCAL app.tenant_id = $1` (Postgres requires literal for
|
|
26
|
+
// identifier/SET; use parameter-binding via set_config for safety).
|
|
27
|
+
await config.db.exec("SELECT set_config('app.tenant_id', $1, true)", [
|
|
28
|
+
tenantId,
|
|
29
|
+
]);
|
|
30
|
+
const userId = call.auth?.userActor?.user_id;
|
|
31
|
+
if (userId) {
|
|
32
|
+
await config.db.exec("SELECT set_config('app.user_id', $1, true)", [
|
|
33
|
+
userId,
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
return handler(call);
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=tenant-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-context.js","sourceRoot":"","sources":["../../src/interceptors/tenant-context.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAC5E,qEAAqE;AACrE,EAAE;AACF,mEAAmE;AACnE,sEAAsE;AACtE,iDAAiD;AAQjD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,UAAU,aAAa,CAAC,MAA2B;IACvD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,gCAAgC,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,aAAa,GAAG,MAAM,CAAC,oBAAoB,IAAI,IAAI,GAAG,EAAU,CAAC;IAEvE,OAAO,CAAC,UAAkB,EAAE,OAAqB,EAAgB,EAAE;QACjE,OAAO,KAAK,EAAE,IAAe,EAAoB,EAAE;YACjD,IAAI,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;YAExD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC;YACtD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,sDAAsD;gBACtD,MAAM,IAAI,eAAe,CACvB,qBAAqB,EACrB,yBAAyB,CAC1B,CAAC;YACJ,CAAC;YAED,gEAAgE;YAChE,oEAAoE;YACpE,MAAM,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,8CAA8C,EAAE;gBACnE,QAAQ;aACT,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC;YAC7C,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,4CAA4C,EAAE;oBACjE,MAAM;iBACP,CAAC,CAAC;YACL,CAAC;YAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { withLoggingUnary } from "./interceptors/logging";
|
|
2
|
+
export { withAuditUnary } from "./interceptors/audit";
|
|
3
|
+
export { enrichAuthContext } from "./interceptors/enrich-auth";
|
|
4
|
+
export { tenantContext } from "./interceptors/tenant-context";
|
|
5
|
+
export { auditContext } from "./interceptors/audit-context";
|
|
6
|
+
export { deadlineGuard } from "./interceptors/deadline-guard";
|
|
7
|
+
export { cancellationGuard } from "./interceptors/cancellation-guard";
|
|
8
|
+
export { errorMap, STANDARD_ERROR_CATALOG, } from "./interceptors/error-map";
|
|
9
|
+
//# sourceMappingURL=interceptors-exports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptors-exports.d.ts","sourceRoot":"","sources":["../src/interceptors-exports.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EACL,QAAQ,EACR,sBAAsB,GACvB,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Internal barrel — owned-interceptor exports used by both `factory.ts`
|
|
2
|
+
// (createStandardServerStack) and `configure.ts` (configureGrpcInterceptors).
|
|
3
|
+
// Keeping this internal sidesteps the circular re-export through `index.ts`.
|
|
4
|
+
export { withLoggingUnary } from "./interceptors/logging";
|
|
5
|
+
export { withAuditUnary } from "./interceptors/audit";
|
|
6
|
+
export { enrichAuthContext } from "./interceptors/enrich-auth";
|
|
7
|
+
export { tenantContext } from "./interceptors/tenant-context";
|
|
8
|
+
export { auditContext } from "./interceptors/audit-context";
|
|
9
|
+
export { deadlineGuard } from "./interceptors/deadline-guard";
|
|
10
|
+
export { cancellationGuard } from "./interceptors/cancellation-guard";
|
|
11
|
+
export { errorMap, STANDARD_ERROR_CATALOG, } from "./interceptors/error-map";
|
|
12
|
+
//# sourceMappingURL=interceptors-exports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptors-exports.js","sourceRoot":"","sources":["../src/interceptors-exports.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,8EAA8E;AAC9E,6EAA6E;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EACL,QAAQ,EACR,sBAAsB,GACvB,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { withAuthUnary, createServerAuthInterceptor, requireScope, grpcError, type WithAuthUnaryOptions, type ServerAuthOptions, } from "@nodii/grpc-auth/server";
|
|
2
|
+
export { createClientAuthInterceptor, S2STokenManager, } from "@nodii/grpc-auth/client";
|
|
3
|
+
export type { S2SAuthContext, ServerUnaryCallWithAuth, } from "@nodii/grpc-auth/types";
|
|
4
|
+
export { sagaContext, emitSagaSignal, awaitSagaSignal, awaitChildren, awaitAnySibling, getSiblings, currentSaga, initSaga, getSagaOrNull, SagaContextRequired, } from "@nodii/saga";
|
|
5
|
+
export type { SagaContextInterceptorOpts, SagaInterceptorCall, InitSagaConfig, } from "@nodii/saga";
|
|
6
|
+
export { idempotencyGuard, IdempotencyServiceError, wrapForWebhook, wrapConsumerWorker, wrapForSagaStep, computeIdempotencyKey, initIdempotency, getIdempotencyOrNull, } from "@nodii/idempotency";
|
|
7
|
+
export type { IdempotencyGuardConfig, UnaryCallLike as IdempotencyUnaryCallLike, InitIdempotencyConfig, } from "@nodii/idempotency";
|
|
8
|
+
export { signalBinder } from "./interceptors/signal-binder";
|
|
9
|
+
export { withSagaHeaders } from "./interceptors/saga-headers";
|
|
10
|
+
//# sourceMappingURL=reexports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reexports.d.ts","sourceRoot":"","sources":["../src/reexports.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,YAAY,EACZ,SAAS,EACT,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,2BAA2B,EAC3B,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,cAAc,EACd,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,eAAe,EACf,WAAW,EACX,WAAW,EACX,QAAQ,EACR,aAAa,EACb,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,cAAc,GACf,MAAM,aAAa,CAAC;AAIrB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,sBAAsB,EACtB,aAAa,IAAI,wBAAwB,EACzC,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAS5B,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Re-export façade — spec § 5.1.
|
|
2
|
+
//
|
|
3
|
+
// v0.1.1: real re-exports from @nodii/saga + @nodii/idempotency now that
|
|
4
|
+
// both libraries have landed at v0.1.1 (sibling impl on main per the redo
|
|
5
|
+
// PRs). Per Q4 resolution: re-exports are bytewise identical to importing
|
|
6
|
+
// from the source package — same module instance, same identity.
|
|
7
|
+
//
|
|
8
|
+
// `signalBinder` and `withSagaHeaders` are owned thin wrappers around the
|
|
9
|
+
// saga signal-bus + saga ALS context (saga does not ship them under those
|
|
10
|
+
// names; this library defines the canonical cross-cutting interceptor
|
|
11
|
+
// surface for them per spec § 5.1).
|
|
12
|
+
// ── @nodii/grpc-auth re-exports (real) ───────────────────────────────────────
|
|
13
|
+
export { withAuthUnary, createServerAuthInterceptor, requireScope, grpcError, } from "@nodii/grpc-auth/server";
|
|
14
|
+
export { createClientAuthInterceptor, S2STokenManager, } from "@nodii/grpc-auth/client";
|
|
15
|
+
// ── @nodii/saga re-exports (real) ────────────────────────────────────────────
|
|
16
|
+
export { sagaContext, emitSagaSignal, awaitSagaSignal, awaitChildren, awaitAnySibling, getSiblings, currentSaga, initSaga, getSagaOrNull, SagaContextRequired, } from "@nodii/saga";
|
|
17
|
+
// ── @nodii/idempotency re-exports (real) ─────────────────────────────────────
|
|
18
|
+
export { idempotencyGuard, IdempotencyServiceError, wrapForWebhook, wrapConsumerWorker, wrapForSagaStep, computeIdempotencyKey, initIdempotency, getIdempotencyOrNull, } from "@nodii/idempotency";
|
|
19
|
+
// ── Owned interceptors: signalBinder + withSagaHeaders ──────────────────────
|
|
20
|
+
//
|
|
21
|
+
// These are cross-cutting glue between the gRPC layer and saga. They live
|
|
22
|
+
// here (not in @nodii/saga) so that the canonical interceptor surface in
|
|
23
|
+
// `@nodii/grpc-interceptors` owns the wire shape. Both operate against the
|
|
24
|
+
// saga library's bootstrapped state — no new state introduced.
|
|
25
|
+
export { signalBinder } from "./interceptors/signal-binder";
|
|
26
|
+
export { withSagaHeaders } from "./interceptors/saga-headers";
|
|
27
|
+
//# sourceMappingURL=reexports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reexports.js","sourceRoot":"","sources":["../src/reexports.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,iEAAiE;AACjE,EAAE;AACF,0EAA0E;AAC1E,0EAA0E;AAC1E,sEAAsE;AACtE,oCAAoC;AAEpC,gFAAgF;AAEhF,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,YAAY,EACZ,SAAS,GAGV,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,2BAA2B,EAC3B,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAOjC,gFAAgF;AAEhF,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,eAAe,EACf,WAAW,EACX,WAAW,EACX,QAAQ,EACR,aAAa,EACb,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAQrB,gFAAgF;AAEhF,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAQ5B,+EAA+E;AAC/E,EAAE;AACF,0EAA0E;AAC1E,yEAAyE;AACzE,2EAA2E;AAC3E,+DAA+D;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TelemetryShim } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve `@nodii/telemetry` lazily. Cached after first successful import.
|
|
4
|
+
* Returns a stderr-JSON fallback if the peer is unavailable so the
|
|
5
|
+
* interceptor chain stays usable in tests that don't init telemetry.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveTelemetry(): TelemetryShim;
|
|
8
|
+
/** Test-only — drop cached resolver. */
|
|
9
|
+
export declare function _resetTelemetryShimForTests(): void;
|
|
10
|
+
/** Test-only — inject a fake telemetry shim. */
|
|
11
|
+
export declare function _setTelemetryShimForTests(shim: TelemetryShim): void;
|
|
12
|
+
//# sourceMappingURL=telemetry-shim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-shim.d.ts","sourceRoot":"","sources":["../src/telemetry-shim.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAmC,aAAa,EAAE,MAAM,SAAS,CAAC;AA+C9E;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CA4BhD;AAED,wCAAwC;AACxC,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED,gDAAgD;AAChD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAEnE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Lazy telemetry resolver — keeps the interceptor library from
|
|
2
|
+
// crashing-on-import when `@nodii/telemetry` is present but not yet
|
|
3
|
+
// bootstrapped (services boot grpc-auth → saga → idempotency → telemetry
|
|
4
|
+
// in that order; the interceptor stack assembly runs last).
|
|
5
|
+
//
|
|
6
|
+
// The shim re-exposes only the surface this library uses:
|
|
7
|
+
// - logger.{debug,info,warn,error}
|
|
8
|
+
// - audit.emit
|
|
9
|
+
//
|
|
10
|
+
// At call time it tries to import `@nodii/telemetry`; on failure (peer
|
|
11
|
+
// not installed, init not run yet) it falls back to a stderr-JSON logger
|
|
12
|
+
// + no-op audit. This guarantees the interceptor chain never throws
|
|
13
|
+
// because telemetry isn't initialized — that's the service's choice.
|
|
14
|
+
const stderrLogger = {
|
|
15
|
+
debug(msg, fields) {
|
|
16
|
+
write("debug", msg, fields);
|
|
17
|
+
},
|
|
18
|
+
info(msg, fields) {
|
|
19
|
+
write("info", msg, fields);
|
|
20
|
+
},
|
|
21
|
+
warn(msg, fields) {
|
|
22
|
+
write("warn", msg, fields);
|
|
23
|
+
},
|
|
24
|
+
error(msg, fields) {
|
|
25
|
+
write("error", msg, fields);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
const noopAudit = {
|
|
29
|
+
async emit(_args) {
|
|
30
|
+
/* no-op fallback */
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
function write(level, msg, fields) {
|
|
34
|
+
try {
|
|
35
|
+
const line = JSON.stringify({
|
|
36
|
+
level,
|
|
37
|
+
msg,
|
|
38
|
+
ts: new Date().toISOString(),
|
|
39
|
+
...fields,
|
|
40
|
+
});
|
|
41
|
+
if (level === "warn" || level === "error") {
|
|
42
|
+
process.stderr.write(`${line}\n`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
process.stdout.write(`${line}\n`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* swallow — fallback path must never throw */
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let cached;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve `@nodii/telemetry` lazily. Cached after first successful import.
|
|
55
|
+
* Returns a stderr-JSON fallback if the peer is unavailable so the
|
|
56
|
+
* interceptor chain stays usable in tests that don't init telemetry.
|
|
57
|
+
*/
|
|
58
|
+
export function resolveTelemetry() {
|
|
59
|
+
if (cached)
|
|
60
|
+
return cached;
|
|
61
|
+
try {
|
|
62
|
+
// Lazy require so `@nodii/telemetry` is a true peer.
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
64
|
+
const mod = require("@nodii/telemetry");
|
|
65
|
+
if (mod.logger && mod.audit) {
|
|
66
|
+
const auditWrap = {
|
|
67
|
+
emit: async (args) => {
|
|
68
|
+
await mod.audit?.emit({
|
|
69
|
+
action: args.action,
|
|
70
|
+
target_kind: args.target_kind,
|
|
71
|
+
target_id: args.target_id,
|
|
72
|
+
payload: args.payload,
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
cached = { logger: mod.logger, audit: auditWrap };
|
|
77
|
+
return cached;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
/* fall through to stderr fallback */
|
|
82
|
+
}
|
|
83
|
+
cached = { logger: stderrLogger, audit: noopAudit };
|
|
84
|
+
return cached;
|
|
85
|
+
}
|
|
86
|
+
/** Test-only — drop cached resolver. */
|
|
87
|
+
export function _resetTelemetryShimForTests() {
|
|
88
|
+
cached = undefined;
|
|
89
|
+
}
|
|
90
|
+
/** Test-only — inject a fake telemetry shim. */
|
|
91
|
+
export function _setTelemetryShimForTests(shim) {
|
|
92
|
+
cached = shim;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=telemetry-shim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-shim.js","sourceRoot":"","sources":["../src/telemetry-shim.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic unary call shape the owned interceptors read from / write to.
|
|
3
|
+
*
|
|
4
|
+
* Intentionally loose so the same interceptor composes under a real
|
|
5
|
+
* `@grpc/grpc-js` `ServerUnaryCall` or a synthetic test fixture
|
|
6
|
+
* (`MockGrpcCall`). The keys we touch are the ones the spec § 5.6 ff
|
|
7
|
+
* mention (`auth`, `metadata`, `request`, `on`, `cancelled`).
|
|
8
|
+
*/
|
|
9
|
+
export interface UnaryCall {
|
|
10
|
+
/** Filled by `@nodii/grpc-auth`'s `withAuthUnary` and read downstream. */
|
|
11
|
+
auth?: AuthOnCall;
|
|
12
|
+
metadata: {
|
|
13
|
+
get(key: string): readonly unknown[];
|
|
14
|
+
};
|
|
15
|
+
request: unknown;
|
|
16
|
+
/**
|
|
17
|
+
* `@grpc/grpc-js` `ServerUnaryCall` exposes `.on("cancelled", ...)`.
|
|
18
|
+
* Synthetic test calls can omit it; `cancellationGuard` no-ops when
|
|
19
|
+
* absent.
|
|
20
|
+
*/
|
|
21
|
+
on?: (event: "cancelled", handler: () => void) => void;
|
|
22
|
+
/** Optional flag set by the cancellation guard fixture. */
|
|
23
|
+
cancelled?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Inbound deadline in milliseconds remaining at the boundary. Real
|
|
26
|
+
* transports (`@grpc/grpc-js`) set this from `call.getDeadline()` -
|
|
27
|
+
* `Date.now()`; downstream consumers can set it directly when
|
|
28
|
+
* constructing a call without going through gRPC (synthetic tests,
|
|
29
|
+
* custom transports). The `deadlineGuard` interceptor reads this in
|
|
30
|
+
* preference to the `grpc-timeout` metadata header.
|
|
31
|
+
*/
|
|
32
|
+
deadlineMs?: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* What `@nodii/grpc-auth`'s server interceptor attaches on success. We
|
|
36
|
+
* declare the shape locally (not via type re-export) so cycles are
|
|
37
|
+
* impossible and the typing matches what `withAuthUnary` actually
|
|
38
|
+
* mutates onto the call.
|
|
39
|
+
*/
|
|
40
|
+
export interface AuthOnCall {
|
|
41
|
+
/** Service-to-service actor stamp. */
|
|
42
|
+
serviceActor?: {
|
|
43
|
+
service_id?: string;
|
|
44
|
+
serviceId?: string;
|
|
45
|
+
service_name?: string;
|
|
46
|
+
serviceName?: string;
|
|
47
|
+
tenant_id?: string;
|
|
48
|
+
scopes?: readonly string[];
|
|
49
|
+
};
|
|
50
|
+
/** Optional user-context envelope (`x-user-context`). */
|
|
51
|
+
userActor?: {
|
|
52
|
+
user_id?: string;
|
|
53
|
+
tenant_id?: string;
|
|
54
|
+
user_role?: string;
|
|
55
|
+
};
|
|
56
|
+
/** Stamped by `enrichAuthContext`. */
|
|
57
|
+
requestContext?: {
|
|
58
|
+
tenant_id?: string;
|
|
59
|
+
intent_id?: string;
|
|
60
|
+
actor_type?: "user" | "agent" | "system";
|
|
61
|
+
correlationId?: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Handler shape every interceptor wraps. */
|
|
65
|
+
export type UnaryHandler = (call: UnaryCall) => Promise<unknown>;
|
|
66
|
+
/**
|
|
67
|
+
* Interceptor factory: `(methodName, handler) -> handler`. Matches the
|
|
68
|
+
* shape re-exported from `@nodii/grpc-auth` as `composeUnaryInterceptors`
|
|
69
|
+
* is fed.
|
|
70
|
+
*/
|
|
71
|
+
export type UnaryInterceptor = (methodName: string, handler: UnaryHandler) => UnaryHandler;
|
|
72
|
+
/** Per-call grpc status codes the library names by string for portability. */
|
|
73
|
+
export type GrpcStatusCode = "OK" | "CANCELLED" | "UNKNOWN" | "INVALID_ARGUMENT" | "DEADLINE_EXCEEDED" | "NOT_FOUND" | "ALREADY_EXISTS" | "PERMISSION_DENIED" | "RESOURCE_EXHAUSTED" | "FAILED_PRECONDITION" | "ABORTED" | "OUT_OF_RANGE" | "UNIMPLEMENTED" | "INTERNAL" | "UNAVAILABLE" | "DATA_LOSS" | "UNAUTHENTICATED";
|
|
74
|
+
/** Service-supplied entry in the `errorCatalog`. */
|
|
75
|
+
export interface ErrorMapEntry {
|
|
76
|
+
code: GrpcStatusCode;
|
|
77
|
+
detail: string;
|
|
78
|
+
}
|
|
79
|
+
/** A thrown gRPC error carrying status + detail (matches `errorMap` output). */
|
|
80
|
+
export declare class GrpcStatusError extends Error {
|
|
81
|
+
readonly code: GrpcStatusCode;
|
|
82
|
+
readonly detail: string;
|
|
83
|
+
constructor(code: GrpcStatusCode, detail: string, cause?: unknown);
|
|
84
|
+
}
|
|
85
|
+
/** Typed error surfaced by `cancellationGuard` when the call is cancelled. */
|
|
86
|
+
export declare class RpcCancelledError extends GrpcStatusError {
|
|
87
|
+
constructor(detail?: string);
|
|
88
|
+
}
|
|
89
|
+
/** Marker for deferred saga/idempotency stub re-exports. */
|
|
90
|
+
export declare class NotImplementedError extends Error {
|
|
91
|
+
constructor(message: string);
|
|
92
|
+
}
|
|
93
|
+
/** Pluggable Postgres connection used by `tenantContext` + `auditContext`. */
|
|
94
|
+
export interface DbConnection {
|
|
95
|
+
/**
|
|
96
|
+
* Execute a parameterized SQL statement. The signature mirrors what
|
|
97
|
+
* `pg` / `drizzle` consumers can adapt to with a thin wrapper. The
|
|
98
|
+
* library calls `exec` only with `SET LOCAL ...` and
|
|
99
|
+
* `SELECT set_config(...)` — no row-returning queries.
|
|
100
|
+
*/
|
|
101
|
+
exec(sql: string, params?: readonly unknown[]): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
/** Pluggable audit emitter. Defaults to `@nodii/telemetry.audit.emit`. */
|
|
104
|
+
export interface AuditEmitter {
|
|
105
|
+
emit(args: {
|
|
106
|
+
action: string;
|
|
107
|
+
target_kind: string;
|
|
108
|
+
target_id: string | null;
|
|
109
|
+
payload?: Record<string, unknown>;
|
|
110
|
+
}): Promise<void>;
|
|
111
|
+
}
|
|
112
|
+
/** Logger interface — the library uses `@nodii/telemetry.logger` by default. */
|
|
113
|
+
export interface InterceptorLogger {
|
|
114
|
+
debug(msg: string, fields?: Record<string, unknown>): void;
|
|
115
|
+
info(msg: string, fields?: Record<string, unknown>): void;
|
|
116
|
+
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
117
|
+
error(msg: string, fields?: Record<string, unknown>): void;
|
|
118
|
+
}
|
|
119
|
+
/** Logging interceptor config — spec § 5.5. */
|
|
120
|
+
export interface LoggingConfig {
|
|
121
|
+
/** Sample ratio for successful (OK) calls. Default 0.01 (1%). */
|
|
122
|
+
successSample?: number;
|
|
123
|
+
/**
|
|
124
|
+
* gRPC codes that are always logged regardless of `successSample`.
|
|
125
|
+
* Defaults to the spec § 5.5 list:
|
|
126
|
+
* `["UNAUTHENTICATED", "PERMISSION_DENIED", "FAILED_PRECONDITION",
|
|
127
|
+
* "INVALID_ARGUMENT", "INTERNAL", "UNAVAILABLE", "UNKNOWN"]`.
|
|
128
|
+
*/
|
|
129
|
+
alwaysEmit?: readonly GrpcStatusCode[];
|
|
130
|
+
/** Optional logger override; defaults to `@nodii/telemetry.logger`. */
|
|
131
|
+
logger?: InterceptorLogger;
|
|
132
|
+
/** Optional sample-rate hook for deterministic tests. Default `Math.random`. */
|
|
133
|
+
random?: () => number;
|
|
134
|
+
}
|
|
135
|
+
/** Audit interceptor config — spec § 5.6. */
|
|
136
|
+
export interface AuditConfig {
|
|
137
|
+
/** Optional emitter override; defaults to `@nodii/telemetry.audit.emit`. */
|
|
138
|
+
emitter?: AuditEmitter;
|
|
139
|
+
/**
|
|
140
|
+
* Method names (`/svc/Method`) that emit an audit-on-read framing row
|
|
141
|
+
* per spec § 5.6. Methods NOT in this set are still audited if they
|
|
142
|
+
* are not in `skipMethods` — the default applies to every gRPC call
|
|
143
|
+
* including rejections (Pattern C).
|
|
144
|
+
*/
|
|
145
|
+
auditOnReadMethods?: ReadonlySet<string>;
|
|
146
|
+
/** Methods skipped entirely (e.g. health checks). */
|
|
147
|
+
skipMethods?: ReadonlySet<string>;
|
|
148
|
+
}
|
|
149
|
+
/** Deadline guard config — spec § 5.10. */
|
|
150
|
+
export interface DeadlineConfig {
|
|
151
|
+
/** Budget reserved at the inbound boundary in ms. Default 50ms per § 5.10. */
|
|
152
|
+
budgetMs?: number;
|
|
153
|
+
/** Per-method budget overrides. */
|
|
154
|
+
perMethodBudgetMs?: Record<string, number>;
|
|
155
|
+
}
|
|
156
|
+
/** Cancellation guard config — spec § 5.11. */
|
|
157
|
+
export interface CancellationConfig {
|
|
158
|
+
/** Grace period in ms before hard-cut. Default 250ms per § 5.11. */
|
|
159
|
+
gracePeriodMs?: number;
|
|
160
|
+
/** Service-registered cancel handlers — run on cancel before the grace timer. */
|
|
161
|
+
onCancel?: readonly (() => Promise<void> | void)[];
|
|
162
|
+
}
|
|
163
|
+
/** Tenant context interceptor config — spec § 5.8. */
|
|
164
|
+
export interface TenantContextConfig {
|
|
165
|
+
/** Required Postgres connection abstraction. */
|
|
166
|
+
db: DbConnection;
|
|
167
|
+
/**
|
|
168
|
+
* Method names that opt-in to system-context (no tenant scoping) — the
|
|
169
|
+
* interceptor skips `SET app.tenant_id` for those.
|
|
170
|
+
*/
|
|
171
|
+
systemContextMethods?: ReadonlySet<string>;
|
|
172
|
+
}
|
|
173
|
+
/** Audit context interceptor config — spec § 5.9. */
|
|
174
|
+
export interface AuditContextConfig {
|
|
175
|
+
/** Required Postgres connection abstraction (shared with tenantContext). */
|
|
176
|
+
db: DbConnection;
|
|
177
|
+
/** Service short-name baked into the `<short>.audit_ctx` GUC. */
|
|
178
|
+
serviceShortName: string;
|
|
179
|
+
}
|
|
180
|
+
/** Enrich auth context config — spec § 5.7. */
|
|
181
|
+
export interface EnrichAuthConfig {
|
|
182
|
+
/**
|
|
183
|
+
* Per-method tenant requirement. Missing entries default to `true`
|
|
184
|
+
* (tenant required). Health methods opt out with `false`.
|
|
185
|
+
*/
|
|
186
|
+
tenantRequiredByMethod?: Record<string, boolean>;
|
|
187
|
+
/** Override for the proto field name carrying tenant id. Default `tenant_id`. */
|
|
188
|
+
tenantField?: string;
|
|
189
|
+
/** Override the correlation id minter. Default — local uuid-ish. */
|
|
190
|
+
mintCorrelationId?: () => string;
|
|
191
|
+
}
|
|
192
|
+
/** Top-level config consumed by `configureGrpcInterceptors` + the factory. */
|
|
193
|
+
export interface StandardServerStackConfig {
|
|
194
|
+
serviceShortName: string;
|
|
195
|
+
db?: DbConnection;
|
|
196
|
+
errorCatalog?: Record<string, ErrorMapEntry>;
|
|
197
|
+
logging?: LoggingConfig;
|
|
198
|
+
audit?: AuditConfig;
|
|
199
|
+
enrich?: EnrichAuthConfig;
|
|
200
|
+
tenant?: {
|
|
201
|
+
systemContextMethods?: ReadonlySet<string>;
|
|
202
|
+
};
|
|
203
|
+
cancellation?: CancellationConfig;
|
|
204
|
+
deadline?: DeadlineConfig;
|
|
205
|
+
/** Methods to skip the full stack on (e.g. `/health.Health/Check`). */
|
|
206
|
+
skipForMethods?: ReadonlySet<string>;
|
|
207
|
+
/** Inject an alternate logger across all interceptors. */
|
|
208
|
+
logger?: InterceptorLogger;
|
|
209
|
+
/**
|
|
210
|
+
* gRPC methods that REQUIRE `x-nodii-idempotency-key`. Passed straight
|
|
211
|
+
* to the @nodii/idempotency `idempotencyGuard` re-export. Empty set =
|
|
212
|
+
* guard is a no-op for every method.
|
|
213
|
+
*/
|
|
214
|
+
mutatorMethods?: ReadonlySet<string>;
|
|
215
|
+
/**
|
|
216
|
+
* Methods tagged `require_saga_context: true` per spec § 5.7 — passed
|
|
217
|
+
* to the @nodii/saga `sagaContext` re-export.
|
|
218
|
+
*/
|
|
219
|
+
requireSagaContextMethods?: ReadonlySet<string>;
|
|
220
|
+
/** sagaContext enforcement mode: 'warn' (default) | 'reject'. */
|
|
221
|
+
sagaContextEnforce?: "warn" | "reject";
|
|
222
|
+
}
|
|
223
|
+
/** Subset of `@nodii/telemetry` we depend on at runtime. */
|
|
224
|
+
export interface TelemetryShim {
|
|
225
|
+
logger: InterceptorLogger;
|
|
226
|
+
audit: AuditEmitter;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|