@classytic/arc 2.11.3 → 2.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -18
- package/dist/{BaseController-swXruJ2_.mjs → BaseController-DX_T-bDB.mjs} +388 -423
- package/dist/EventTransport-CT_52aWU.d.mts +34 -0
- package/dist/EventTransport-DLWoUMHy.mjs +103 -0
- package/dist/{QueryCache-DOBNHBE0.d.mts → QueryCache-D41bfdBB.d.mts} +1 -1
- package/dist/{ResourceRegistry-DkAeAuTX.mjs → ResourceRegistry-CTERg_2x.mjs} +139 -66
- package/dist/audit/index.d.mts +2 -2
- package/dist/audit/index.mjs +1 -1
- package/dist/auth/audit.d.mts +199 -0
- package/dist/auth/audit.mjs +288 -0
- package/dist/auth/index.d.mts +5 -5
- package/dist/auth/index.mjs +117 -191
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-DwxtK3uG.mjs → betterAuthOpenApi--M_i87dQ.mjs} +1 -1
- package/dist/buildHandler-olo-gt94.mjs +610 -0
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/cli/commands/describe.d.mts +89 -13
- package/dist/cli/commands/describe.mjs +56 -2
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +147 -48
- package/dist/cli/commands/init.d.mts +13 -0
- package/dist/cli/commands/init.mjs +237 -112
- package/dist/cli/commands/introspect.mjs +8 -1
- package/dist/context/index.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/core-D72ia0EH.mjs +1399 -0
- package/dist/{createActionRouter-u3ql2EDo.mjs → createActionRouter-CEvzKcy8.mjs} +7 -20
- package/dist/createAggregationRouter-CyecOxnO.mjs +114 -0
- package/dist/{createApp-BFxtdKy6.mjs → createApp-XX2-N0Yd.mjs} +31 -27
- package/dist/defineEvent-D5h7EvAx.mjs +188 -0
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DOFoxoDs.mjs → elevation-DgoeTyfX.mjs} +1 -1
- package/dist/errorHandler-Bk-AGhkU.mjs +174 -0
- package/dist/errorHandler-DFr45ZG4.d.mts +45 -0
- package/dist/errors-j4aJm1Wg.mjs +184 -0
- package/dist/{eventPlugin-KrFIQ097.mjs → eventPlugin-CaKTYkYM.mjs} +35 -137
- package/dist/{eventPlugin-CUNjYYRY.d.mts → eventPlugin-qXpqTebY.d.mts} +57 -7
- package/dist/events/index.d.mts +164 -5
- package/dist/events/index.mjs +133 -209
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +204 -31
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +2 -2
- package/dist/factory/index.mjs +2 -2
- package/dist/{fields-C8Y0XLAu.d.mts → fields-COhcH3fk.d.mts} +23 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/index.mjs +1 -20
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +1 -1
- package/dist/{index-BYCqHCVu.d.mts → index-BTqLEvhu.d.mts} +164 -4
- package/dist/{index-6u4_Gg6G.d.mts → index-BtW7qYwa.d.mts} +661 -281
- package/dist/{index-BdXnTPRj.d.mts → index-Ds61mrJE.d.mts} +50 -4
- package/dist/{index-DdQ3O9Pg.d.mts → index-Dz5IKsrE.d.mts} +360 -219
- package/dist/index.d.mts +6 -7
- package/dist/index.mjs +9 -10
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/streamline.d.mts +60 -11
- package/dist/integrations/streamline.mjs +75 -85
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +2 -8
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +2 -2
- package/dist/migrations/index.d.mts +23 -3
- package/dist/migrations/index.mjs +0 -7
- package/dist/{multipartBody-CvTR1Un6.mjs → multipartBody-BOvVSVCD.mjs} +11 -8
- package/dist/{openapi-BGUn7Ki1.mjs → openapi-CiOMVW1p.mjs} +143 -13
- package/dist/org/index.d.mts +2 -2
- package/dist/org/index.mjs +1 -1
- package/dist/permissions/index.d.mts +3 -3
- package/dist/permissions/index.mjs +3 -3
- package/dist/{permissions-gd_aUWrR.mjs → permissions-ohQyv50e.mjs} +404 -176
- package/dist/{pipe-DVoIheVC.mjs → pipe-Zr0KXjQe.mjs} +1 -1
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +18 -33
- package/dist/plugins/index.mjs +33 -13
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +5 -5
- package/dist/presets/filesUpload.mjs +6 -9
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +2 -2
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +6 -8
- package/dist/{presets-Z7P5w4gF.mjs → presets-BbkjdPeH.mjs} +6 -28
- package/dist/{queryCachePlugin-BUXBSm4F.d.mts → queryCachePlugin-CqMdLI2-.d.mts} +2 -2
- package/dist/{queryCachePlugin-Bq6bO6vc.mjs → queryCachePlugin-m1XsgAIJ.mjs} +3 -3
- package/dist/{redis-Cm1gnRDf.d.mts → redis-DiMkdHEl.d.mts} +1 -1
- package/dist/redis-stream-D6HzR1Z_.d.mts +232 -0
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{replyHelpers-ByllIXXV.mjs → replyHelpers-CK-FNO8E.mjs} +3 -21
- package/dist/{resourceToTools-ByZpgjeH.mjs → resourceToTools-C5coh64w.mjs} +224 -71
- package/dist/{routerShared-BqLRb5l7.mjs → routerShared-D6_fEGHh.mjs} +40 -36
- package/dist/{schemaIR-BlG9bY7v.mjs → schemaIR-7Vl611Qs.mjs} +1 -1
- package/dist/schemas/index.d.mts +100 -30
- package/dist/schemas/index.mjs +86 -29
- package/dist/scim/index.d.mts +264 -0
- package/dist/scim/index.mjs +963 -0
- package/dist/scope/index.d.mts +3 -3
- package/dist/scope/index.mjs +4 -4
- package/dist/{sse-V7aXc3bW.mjs → sse-Bz-5ZeTt.mjs} +1 -1
- package/dist/{store-helpers-BhrzxvyQ.mjs → store-helpers-BkIN9-vu.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -8
- package/dist/testing/index.mjs +16 -24
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-BH7dEGvU.d.mts → types-BvqwCCSx.d.mts} +77 -29
- package/dist/{types-tgR4Pt8F.d.mts → types-CTYvcwHe.d.mts} +195 -1
- package/dist/{types-AOD8fxIw.mjs → types-C_s5moIu.mjs} +117 -1
- package/dist/{types-9beEMe25.d.mts → types-DQHFc8PM.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +5 -5
- package/dist/{utils-CcYTj09l.mjs → utils-_h9B3c57.mjs} +1269 -1334
- package/dist/{versioning-M9lNLhO8.d.mts → versioning-DTTvc80y.d.mts} +1 -1
- package/package.json +24 -34
- package/skills/arc/SKILL.md +521 -785
- package/skills/arc/references/agent-auth.md +238 -0
- package/skills/arc/references/api-reference.md +187 -0
- package/skills/arc/references/auth.md +354 -7
- package/skills/arc/references/enterprise-auth.md +94 -0
- package/skills/arc/references/events.md +8 -6
- package/skills/arc/references/mcp.md +2 -2
- package/skills/arc/references/multi-tenancy.md +11 -2
- package/skills/arc/references/production.md +10 -9
- package/skills/arc/references/scim.md +247 -0
- package/skills/arc/references/testing.md +1 -1
- package/skills/arc-code-review/SKILL.md +141 -0
- package/skills/arc-code-review/references/anti-patterns.md +911 -0
- package/skills/arc-code-review/references/arc-cheatsheet.md +380 -0
- package/skills/arc-code-review/references/migration-recipes.md +700 -0
- package/skills/arc-code-review/references/mongokit-migration.md +386 -0
- package/skills/arc-code-review/references/scaffolding.md +230 -0
- package/skills/arc-code-review/references/severity.md +127 -0
- package/dist/EventTransport-CfVEGaEl.d.mts +0 -293
- package/dist/adapters/index.d.mts +0 -3
- package/dist/adapters/index.mjs +0 -2
- package/dist/adapters-D0tT2Tyo.mjs +0 -949
- package/dist/auth/mongoose.d.mts +0 -191
- package/dist/auth/mongoose.mjs +0 -73
- package/dist/core-DnUsRpuX.mjs +0 -1049
- package/dist/errorHandler-BQm8ZxTK.mjs +0 -173
- package/dist/errorHandler-Co3lnVmJ.d.mts +0 -114
- package/dist/errors-D5c-5BJL.mjs +0 -232
- package/dist/index-BbMrcvGp.d.mts +0 -362
- package/dist/redis-stream-CM8TXTix.d.mts +0 -110
- /package/dist/{HookSystem-CGsMd6oK.mjs → HookSystem-Iiebom92.mjs} +0 -0
- /package/dist/{actionPermissions-sUUKDhtP.mjs → actionPermissions-CyUkQu6O.mjs} +0 -0
- /package/dist/{caching-CheW3m-S.mjs → caching-SM8gghN6.mjs} +0 -0
- /package/dist/{constants-BhY1OHoH.mjs → constants-Cxde4rpC.mjs} +0 -0
- /package/dist/{elevation-s5ykdNHr.d.mts → elevation-BXOWoGCF.d.mts} +0 -0
- /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BD5nw6St.d.mts} +0 -0
- /package/dist/{interface-CkkWm5uR.d.mts → interface-DfLGcus7.d.mts} +0 -0
- /package/dist/{interface-Da0r7Lna.d.mts → interface-beEtJyWM.d.mts} +0 -0
- /package/dist/{keys-CARyUjiR.mjs → keys-CGcCbNyu.mjs} +0 -0
- /package/dist/{loadResources-CPpkyKfM.mjs → loadResources-DBMQg_Aj.mjs} +0 -0
- /package/dist/{memory-DikHSvWa.mjs → memory-UBydS5ku.mjs} +0 -0
- /package/dist/{metrics-Csh4nsvv.mjs → metrics-Qnvwc-LQ.mjs} +0 -0
- /package/dist/{pluralize-BneOJkpi.mjs → pluralize-DQgqgifU.mjs} +0 -0
- /package/dist/{registry-D63ee7fl.mjs → registry-I-ogLgL9.mjs} +0 -0
- /package/dist/{requestContext-C5XeK3VA.mjs → requestContext-SSaaTgW8.mjs} +0 -0
- /package/dist/{schemaConverter-B0oKLuqI.mjs → schemaConverter-De34B1ZG.mjs} +0 -0
- /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-C4Le_UB3.d.mts} +0 -0
- /package/dist/{storage-BwGQXUpd.d.mts → storage-Dfzt4VTl.d.mts} +0 -0
- /package/dist/{tracing-DokiEsuz.d.mts → tracing-QJVprktp.d.mts} +0 -0
- /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-BzkXkvVv.mjs} +0 -0
- /package/dist/{types-DV9WDfeg.mjs → types-D57iXYb8.mjs} +0 -0
- /package/dist/{versioning-CGPjkqAg.mjs → versioning-BUrT5aP4.mjs} +0 -0
- /package/dist/{websocket-CyJ1VIFI.d.mts → websocket-ChC2rqe1.d.mts} +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { DeadLetteredEvent, DomainEvent, DomainEvent as DomainEvent$1, EventHandler, EventHandler as EventHandler$1, EventLogger, EventLogger as EventLogger$1, EventTransport, EventTransport as EventTransport$1, PublishManyResult } from "@classytic/primitives/events";
|
|
2
|
+
|
|
3
|
+
//#region src/events/EventTransport.d.ts
|
|
4
|
+
interface MemoryEventTransportOptions {
|
|
5
|
+
/** Logger for error/warning messages (default: console) */
|
|
6
|
+
logger?: EventLogger;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* In-memory event transport (default).
|
|
10
|
+
*
|
|
11
|
+
* Events are delivered synchronously within the process. Not suitable for
|
|
12
|
+
* multi-instance deployments — pair with `RedisEventTransport` /
|
|
13
|
+
* `RedisStreamTransport` (subpath imports) for those.
|
|
14
|
+
*/
|
|
15
|
+
declare class MemoryEventTransport implements EventTransport {
|
|
16
|
+
readonly name = "memory";
|
|
17
|
+
private handlers;
|
|
18
|
+
private logger;
|
|
19
|
+
constructor(options?: MemoryEventTransportOptions);
|
|
20
|
+
publish(event: DomainEvent): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Reference `publishMany` implementation — delegates to `publish()` in order.
|
|
23
|
+
*
|
|
24
|
+
* Production transports (Kafka, Redis pipeline, SQS batch) should override
|
|
25
|
+
* this with a single batched network call. Memory transport has nothing to
|
|
26
|
+
* batch, so we just loop — the loop still returns a proper result map so
|
|
27
|
+
* `EventOutbox.relay` can exercise the batched code path in tests.
|
|
28
|
+
*/
|
|
29
|
+
publishMany(events: readonly DomainEvent[]): Promise<PublishManyResult>;
|
|
30
|
+
subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { EventTransport$1 as a, EventLogger$1 as i, DomainEvent$1 as n, MemoryEventTransport as o, EventHandler$1 as r, MemoryEventTransportOptions as s, DeadLetteredEvent as t };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createEvent, matchEventPattern } from "@classytic/primitives/events";
|
|
2
|
+
//#region src/events/EventTransport.ts
|
|
3
|
+
/**
|
|
4
|
+
* Internal arc events module — concrete in-memory transport.
|
|
5
|
+
*
|
|
6
|
+
* **Public type contracts moved out (arc 2.12).** `EventMeta`, `DomainEvent`,
|
|
7
|
+
* `EventHandler`, `EventLogger`, `EventTransport`, `DeadLetteredEvent`,
|
|
8
|
+
* `PublishManyResult`, plus the `createEvent` / `createChildEvent` /
|
|
9
|
+
* `matchEventPattern` helpers, are now owned by `@classytic/primitives/events`.
|
|
10
|
+
* Two reasons:
|
|
11
|
+
*
|
|
12
|
+
* 1. The shapes ARE the cross-package contract. arc, arc-next, mongokit's
|
|
13
|
+
* audit-log plugin, future kits and downstream services all share them.
|
|
14
|
+
* Owning them in `primitives` (pure types, zero runtime, zero deps)
|
|
15
|
+
* eliminates the "manually mirror in two places" problem the previous
|
|
16
|
+
* `primitives/src/events.ts` header explicitly called out.
|
|
17
|
+
* 2. Inverting the dependency direction lets future packages (sqlitekit
|
|
18
|
+
* audit, billing services) consume the contract without depending on
|
|
19
|
+
* arc's HTTP-coupled stack.
|
|
20
|
+
*
|
|
21
|
+
* Hosts MUST import the types from primitives directly:
|
|
22
|
+
*
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import type {
|
|
25
|
+
* EventMeta, DomainEvent, EventHandler, EventTransport,
|
|
26
|
+
* DeadLetteredEvent, PublishManyResult,
|
|
27
|
+
* } from '@classytic/primitives/events';
|
|
28
|
+
* import { createEvent, createChildEvent } from '@classytic/primitives/events';
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* arc's `events/index.ts` barrel does NOT re-export these — by design, so
|
|
32
|
+
* that consumer code is forced into the canonical import path and the org's
|
|
33
|
+
* "no re-exports" rule holds at every public surface.
|
|
34
|
+
*
|
|
35
|
+
* What stays here:
|
|
36
|
+
* - `MemoryEventTransport` — the in-memory `EventTransport` implementation
|
|
37
|
+
* used as arc's default transport. Its handler-set state is process-local;
|
|
38
|
+
* wrong layer for primitives.
|
|
39
|
+
* - `MemoryEventTransportOptions` — its options shape.
|
|
40
|
+
*
|
|
41
|
+
* Inside arc, files that previously imported types from `./EventTransport.js`
|
|
42
|
+
* keep working: this file re-exports them from primitives for arc's own
|
|
43
|
+
* call sites. That re-export is an internal refactor convenience — the
|
|
44
|
+
* public `events/index.ts` barrel stays clean.
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* In-memory event transport (default).
|
|
48
|
+
*
|
|
49
|
+
* Events are delivered synchronously within the process. Not suitable for
|
|
50
|
+
* multi-instance deployments — pair with `RedisEventTransport` /
|
|
51
|
+
* `RedisStreamTransport` (subpath imports) for those.
|
|
52
|
+
*/
|
|
53
|
+
var MemoryEventTransport = class {
|
|
54
|
+
name = "memory";
|
|
55
|
+
handlers = /* @__PURE__ */ new Map();
|
|
56
|
+
logger;
|
|
57
|
+
constructor(options) {
|
|
58
|
+
this.logger = options?.logger ?? console;
|
|
59
|
+
}
|
|
60
|
+
async publish(event) {
|
|
61
|
+
const allHandlers = /* @__PURE__ */ new Set();
|
|
62
|
+
for (const [pattern, handlers] of this.handlers) if (matchEventPattern(pattern, event.type)) for (const h of handlers) allHandlers.add(h);
|
|
63
|
+
for (const handler of allHandlers) try {
|
|
64
|
+
await handler(event);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Reference `publishMany` implementation — delegates to `publish()` in order.
|
|
71
|
+
*
|
|
72
|
+
* Production transports (Kafka, Redis pipeline, SQS batch) should override
|
|
73
|
+
* this with a single batched network call. Memory transport has nothing to
|
|
74
|
+
* batch, so we just loop — the loop still returns a proper result map so
|
|
75
|
+
* `EventOutbox.relay` can exercise the batched code path in tests.
|
|
76
|
+
*/
|
|
77
|
+
async publishMany(events) {
|
|
78
|
+
const results = /* @__PURE__ */ new Map();
|
|
79
|
+
for (const event of events) try {
|
|
80
|
+
await this.publish(event);
|
|
81
|
+
results.set(event.meta.id, null);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
results.set(event.meta.id, err instanceof Error ? err : new Error(String(err)));
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
async subscribe(pattern, handler) {
|
|
88
|
+
if (!this.handlers.has(pattern)) this.handlers.set(pattern, /* @__PURE__ */ new Set());
|
|
89
|
+
this.handlers.get(pattern)?.add(handler);
|
|
90
|
+
return () => {
|
|
91
|
+
const set = this.handlers.get(pattern);
|
|
92
|
+
if (set) {
|
|
93
|
+
set.delete(handler);
|
|
94
|
+
if (set.size === 0) this.handlers.delete(pattern);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async close() {
|
|
99
|
+
this.handlers.clear();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
export { createEvent as n, MemoryEventTransport as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./constants-Cxde4rpC.mjs";
|
|
2
2
|
//#region src/registry/ResourceRegistry.ts
|
|
3
3
|
/**
|
|
4
4
|
* Resource Registry
|
|
@@ -46,7 +46,7 @@ var ResourceRegistry = class {
|
|
|
46
46
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
47
47
|
disableDefaultRoutes: resource.disableDefaultRoutes,
|
|
48
48
|
updateMethod: resource.updateMethod,
|
|
49
|
-
disabledRoutes: resource.disabledRoutes,
|
|
49
|
+
disabledRoutes: resource.disabledRoutes ? [...resource.disabledRoutes] : void 0,
|
|
50
50
|
openApiSchemas: options.openApiSchemas,
|
|
51
51
|
fieldPermissions: extractFieldPermissions(resource.fields),
|
|
52
52
|
pipelineSteps: extractPipelineSteps(resource.pipe),
|
|
@@ -63,6 +63,18 @@ var ResourceRegistry = class {
|
|
|
63
63
|
mcp: entry.mcp
|
|
64
64
|
};
|
|
65
65
|
}) : void 0,
|
|
66
|
+
aggregations: resource.aggregations ? Object.entries(resource.aggregations).map(([name, entry]) => ({
|
|
67
|
+
name,
|
|
68
|
+
summary: entry.summary,
|
|
69
|
+
description: entry.description,
|
|
70
|
+
permissions: entry.permissions,
|
|
71
|
+
groupBy: entry.groupBy,
|
|
72
|
+
measures: stringifyMeasureMap(entry.measures),
|
|
73
|
+
lookupAliases: (entry.lookups ?? []).map((l) => l.as ?? l.from),
|
|
74
|
+
requireDateRange: entry.requireDateRange,
|
|
75
|
+
requireFilters: entry.requireFilters,
|
|
76
|
+
mcp: entry.mcp
|
|
77
|
+
})) : void 0,
|
|
66
78
|
plugin: resource.toPlugin()
|
|
67
79
|
};
|
|
68
80
|
this._resources.set(resource.name, entry);
|
|
@@ -100,6 +112,11 @@ var ResourceRegistry = class {
|
|
|
100
112
|
}
|
|
101
113
|
/**
|
|
102
114
|
* Get registry statistics
|
|
115
|
+
*
|
|
116
|
+
* `totalRoutes` is derived from `enumerateRoutes()` — single source of
|
|
117
|
+
* truth shared with `getIntrospection()` and consistent with what
|
|
118
|
+
* OpenAPI / Fastify actually mount. New route sources (e.g. v2.13
|
|
119
|
+
* aggregations) light up here automatically.
|
|
103
120
|
*/
|
|
104
121
|
getStats() {
|
|
105
122
|
const resources = this.getAll();
|
|
@@ -109,82 +126,110 @@ var ResourceRegistry = class {
|
|
|
109
126
|
totalResources: resources.length,
|
|
110
127
|
byModule: this._groupBy(resources, "module"),
|
|
111
128
|
presetUsage: presetCounts,
|
|
112
|
-
totalRoutes: resources.reduce((sum, r) =>
|
|
113
|
-
const actionsCount = (r.actions?.length ?? 0) > 0 ? 1 : 0;
|
|
114
|
-
if (r.disableDefaultRoutes) return sum + (r.customRoutes?.length ?? 0) + actionsCount;
|
|
115
|
-
const disabledSet = new Set(r.disabledRoutes ?? []);
|
|
116
|
-
let defaultCount = CRUD_OPERATIONS.filter((route) => !disabledSet.has(route)).length;
|
|
117
|
-
if (!disabledSet.has("update") && r.updateMethod === "both") defaultCount += 1;
|
|
118
|
-
return sum + defaultCount + (r.customRoutes?.length ?? 0) + actionsCount;
|
|
119
|
-
}, 0),
|
|
129
|
+
totalRoutes: resources.reduce((sum, r) => sum + this.enumerateRoutes(r).length, 0),
|
|
120
130
|
totalEvents: resources.reduce((sum, r) => sum + (r.events?.length ?? 0), 0)
|
|
121
131
|
};
|
|
122
132
|
}
|
|
123
133
|
/**
|
|
124
134
|
* Get full introspection data
|
|
135
|
+
*
|
|
136
|
+
* Routes come from `enumerateRoutes()` so consumers see the complete
|
|
137
|
+
* surface — CRUD + custom + actions + aggregations — and match what
|
|
138
|
+
* `getStats()` counts.
|
|
125
139
|
*/
|
|
126
140
|
getIntrospection() {
|
|
127
141
|
return {
|
|
128
|
-
resources: this.getAll().map((r) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
method: "GET",
|
|
139
|
-
path: `${r.prefix}/:id`,
|
|
140
|
-
operation: "get"
|
|
141
|
-
}] : [],
|
|
142
|
-
...!disabledSet.has("create") ? [{
|
|
143
|
-
method: "POST",
|
|
144
|
-
path: r.prefix,
|
|
145
|
-
operation: "create"
|
|
146
|
-
}] : [],
|
|
147
|
-
...!disabledSet.has("update") ? updateMethod === "both" ? [{
|
|
148
|
-
method: "PUT",
|
|
149
|
-
path: `${r.prefix}/:id`,
|
|
150
|
-
operation: "update"
|
|
151
|
-
}, {
|
|
152
|
-
method: "PATCH",
|
|
153
|
-
path: `${r.prefix}/:id`,
|
|
154
|
-
operation: "update"
|
|
155
|
-
}] : [{
|
|
156
|
-
method: updateMethod,
|
|
157
|
-
path: `${r.prefix}/:id`,
|
|
158
|
-
operation: "update"
|
|
159
|
-
}] : [],
|
|
160
|
-
...!disabledSet.has("delete") ? [{
|
|
161
|
-
method: "DELETE",
|
|
162
|
-
path: `${r.prefix}/:id`,
|
|
163
|
-
operation: "delete"
|
|
164
|
-
}] : []
|
|
165
|
-
];
|
|
166
|
-
return {
|
|
167
|
-
name: r.name,
|
|
168
|
-
displayName: r.displayName,
|
|
169
|
-
prefix: r.prefix,
|
|
170
|
-
module: r.module,
|
|
171
|
-
presets: r.presets,
|
|
172
|
-
permissions: r.permissions,
|
|
173
|
-
routes: [...defaultRoutes, ...r.customRoutes?.map((ar) => ({
|
|
174
|
-
method: ar.method,
|
|
175
|
-
path: `${r.prefix}${ar.path}`,
|
|
176
|
-
operation: ar.operation ?? (typeof ar.handler === "string" ? ar.handler : "custom"),
|
|
177
|
-
handler: typeof ar.handler === "string" ? ar.handler : void 0,
|
|
178
|
-
summary: ar.summary
|
|
179
|
-
})) ?? []],
|
|
180
|
-
events: r.events
|
|
181
|
-
};
|
|
182
|
-
}),
|
|
142
|
+
resources: this.getAll().map((r) => ({
|
|
143
|
+
name: r.name,
|
|
144
|
+
displayName: r.displayName,
|
|
145
|
+
prefix: r.prefix,
|
|
146
|
+
module: r.module,
|
|
147
|
+
presets: r.presets,
|
|
148
|
+
permissions: r.permissions,
|
|
149
|
+
routes: this.enumerateRoutes(r),
|
|
150
|
+
events: r.events
|
|
151
|
+
})),
|
|
183
152
|
stats: this.getStats(),
|
|
184
153
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
185
154
|
};
|
|
186
155
|
}
|
|
187
156
|
/**
|
|
157
|
+
* Single source of truth for "what routes does this resource expose?".
|
|
158
|
+
*
|
|
159
|
+
* Enumerates every wire route the resource will mount on Fastify:
|
|
160
|
+
* - default CRUD (respecting `disabledRoutes` + `updateMethod`)
|
|
161
|
+
* - host-declared `customRoutes` (alias: `routes`)
|
|
162
|
+
* - the unified `POST /:id/action` endpoint when `actions` is set
|
|
163
|
+
* - one `GET /:resource/aggregations/:name` per declared aggregation
|
|
164
|
+
*
|
|
165
|
+
* Both `getStats()` and `getIntrospection()` consume this list, so a
|
|
166
|
+
* new route source (e.g. future webhook routes) only has to be added
|
|
167
|
+
* here — the count and the introspection contract update together.
|
|
168
|
+
* Mirrors the same set of paths emitted by `docs/openapi.ts`.
|
|
169
|
+
*/
|
|
170
|
+
enumerateRoutes(r) {
|
|
171
|
+
const routes = [];
|
|
172
|
+
if (!r.disableDefaultRoutes) {
|
|
173
|
+
const disabled = new Set(r.disabledRoutes ?? []);
|
|
174
|
+
const updateMethod = r.updateMethod ?? "PATCH";
|
|
175
|
+
if (!disabled.has("list")) routes.push({
|
|
176
|
+
method: "GET",
|
|
177
|
+
path: r.prefix,
|
|
178
|
+
operation: "list"
|
|
179
|
+
});
|
|
180
|
+
if (!disabled.has("get")) routes.push({
|
|
181
|
+
method: "GET",
|
|
182
|
+
path: `${r.prefix}/:id`,
|
|
183
|
+
operation: "get"
|
|
184
|
+
});
|
|
185
|
+
if (!disabled.has("create")) routes.push({
|
|
186
|
+
method: "POST",
|
|
187
|
+
path: r.prefix,
|
|
188
|
+
operation: "create"
|
|
189
|
+
});
|
|
190
|
+
if (!disabled.has("update")) if (updateMethod === "both") {
|
|
191
|
+
routes.push({
|
|
192
|
+
method: "PUT",
|
|
193
|
+
path: `${r.prefix}/:id`,
|
|
194
|
+
operation: "update"
|
|
195
|
+
});
|
|
196
|
+
routes.push({
|
|
197
|
+
method: "PATCH",
|
|
198
|
+
path: `${r.prefix}/:id`,
|
|
199
|
+
operation: "update"
|
|
200
|
+
});
|
|
201
|
+
} else routes.push({
|
|
202
|
+
method: updateMethod,
|
|
203
|
+
path: `${r.prefix}/:id`,
|
|
204
|
+
operation: "update"
|
|
205
|
+
});
|
|
206
|
+
if (!disabled.has("delete")) routes.push({
|
|
207
|
+
method: "DELETE",
|
|
208
|
+
path: `${r.prefix}/:id`,
|
|
209
|
+
operation: "delete"
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
for (const ar of r.customRoutes ?? []) routes.push({
|
|
213
|
+
method: ar.method,
|
|
214
|
+
path: `${r.prefix}${ar.path}`,
|
|
215
|
+
operation: ar.operation ?? (typeof ar.handler === "string" ? ar.handler : "custom"),
|
|
216
|
+
handler: typeof ar.handler === "string" ? ar.handler : void 0,
|
|
217
|
+
summary: ar.summary
|
|
218
|
+
});
|
|
219
|
+
if (r.actions && r.actions.length > 0) routes.push({
|
|
220
|
+
method: "POST",
|
|
221
|
+
path: `${r.prefix}/:id/action`,
|
|
222
|
+
operation: "action"
|
|
223
|
+
});
|
|
224
|
+
for (const agg of r.aggregations ?? []) routes.push({
|
|
225
|
+
method: "GET",
|
|
226
|
+
path: `${r.prefix}/aggregations/${agg.name}`,
|
|
227
|
+
operation: `aggregation:${agg.name}`,
|
|
228
|
+
summary: agg.summary
|
|
229
|
+
});
|
|
230
|
+
return routes;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
188
233
|
* Freeze registry (prevent further registrations)
|
|
189
234
|
*/
|
|
190
235
|
freeze() {
|
|
@@ -261,5 +306,33 @@ function extractPipelineSteps(pipe) {
|
|
|
261
306
|
operations: s.operations ? [...s.operations] : void 0
|
|
262
307
|
}));
|
|
263
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Stringify a measure map for the registry. Object IR (`{ op: 'sum',
|
|
311
|
+
* field: 'price' }`) collapses to its op-tag form (`'sum:price'`) so
|
|
312
|
+
* the OpenAPI / MCP / describe layers can render docs without
|
|
313
|
+
* re-implementing IR walking. Bare `count` (no field) stays `'count'`.
|
|
314
|
+
*
|
|
315
|
+
* Exported so the CLI describe command renders the same string form —
|
|
316
|
+
* single source of truth for "how a measure looks to tooling".
|
|
317
|
+
*/
|
|
318
|
+
function stringifyMeasureMap(measures) {
|
|
319
|
+
const out = {};
|
|
320
|
+
for (const [alias, m] of Object.entries(measures)) {
|
|
321
|
+
if (typeof m === "string") {
|
|
322
|
+
out[alias] = m;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (m.op === "count" && !("field" in m && m.field)) {
|
|
326
|
+
out[alias] = "count";
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if ("field" in m && m.field) {
|
|
330
|
+
out[alias] = `${m.op}:${m.field}`;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
out[alias] = m.op;
|
|
334
|
+
}
|
|
335
|
+
return out;
|
|
336
|
+
}
|
|
264
337
|
//#endregion
|
|
265
|
-
export { ResourceRegistry as t };
|
|
338
|
+
export { stringifyMeasureMap as n, ResourceRegistry as t };
|
package/dist/audit/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as UserBase } from "../fields-C8Y0XLAu.mjs";
|
|
1
|
+
import { d as UserBase } from "../fields-COhcH3fk.mjs";
|
|
3
2
|
import { FastifyPluginAsync } from "fastify";
|
|
3
|
+
import { RepositoryLike } from "@classytic/repo-core/adapter";
|
|
4
4
|
|
|
5
5
|
//#region src/audit/stores/interface.d.ts
|
|
6
6
|
type AuditAction = "create" | "update" | "delete" | "restore" | "custom";
|
package/dist/audit/index.mjs
CHANGED
|
@@ -50,7 +50,7 @@ function repositoryAsAuditStore(repository) {
|
|
|
50
50
|
page,
|
|
51
51
|
limit
|
|
52
52
|
});
|
|
53
|
-
return (Array.isArray(result) ? result : result.
|
|
53
|
+
return (Array.isArray(result) ? result : result.data ?? []).map((d) => ({
|
|
54
54
|
id: String(d[idField] ?? ""),
|
|
55
55
|
resource: d.resource ?? "",
|
|
56
56
|
documentId: d.documentId ?? "",
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { FastifyInstance } from "fastify";
|
|
2
|
+
|
|
3
|
+
//#region src/auth/audit.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Canonical auth event names emitted by the bridge. Hosts pattern-match
|
|
6
|
+
* with glob (`session.*`, `mfa.*`, `*.failed`) when listing `events`.
|
|
7
|
+
*
|
|
8
|
+
* Names mirror BA's database-hook + endpoint-hook taxonomy. Not exhaustive —
|
|
9
|
+
* unknown events still flow through when matched, just with the BA-supplied
|
|
10
|
+
* name verbatim. Use this list for autocomplete-friendly defaults.
|
|
11
|
+
*/
|
|
12
|
+
type AuthEventName = "session.create" | "session.delete" | "session.update" | "user.create" | "user.update" | "user.delete" | "mfa.enroll" | "mfa.verify" | "mfa.failed" | "mfa.disable" | "password.reset.request" | "password.reset.complete" | "email.verify" | "org.create" | "org.delete" | "org.invite.create" | "org.invite.accept" | "org.invite.reject" | "org.member.add" | "org.member.remove" | "org.member.role.update" | "apikey.create" | "apikey.delete" | "apikey.failed" | "endpoint.before" | "endpoint.after" | "endpoint.error";
|
|
13
|
+
/**
|
|
14
|
+
* Resolved auth event ready for audit. The bridge constructs this from
|
|
15
|
+
* BA's hook context, then forwards to `app.audit.custom('auth', subjectId,
|
|
16
|
+
* event.name, event.payload)`.
|
|
17
|
+
*/
|
|
18
|
+
interface AuthEvent {
|
|
19
|
+
/** Canonical name (see {@link AuthEventName}). */
|
|
20
|
+
name: string;
|
|
21
|
+
/**
|
|
22
|
+
* Subject id — the user / session / org / invite id this event is about.
|
|
23
|
+
* Empty string when the event is pre-creation (e.g. `mfa.failed` before
|
|
24
|
+
* the session exists); audit rows accept empty `documentId`.
|
|
25
|
+
*/
|
|
26
|
+
subjectId: string;
|
|
27
|
+
/** User performing the action (when known); audit infers from request when omitted. */
|
|
28
|
+
userId?: string;
|
|
29
|
+
/** Organization context (when known). */
|
|
30
|
+
organizationId?: string;
|
|
31
|
+
/** Free-form payload — provider name, IP, user-agent, MFA method, etc. */
|
|
32
|
+
payload?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Options for `wireBetterAuthAudit`.
|
|
36
|
+
*/
|
|
37
|
+
interface WireBetterAuthAuditOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Glob patterns selecting which events to audit. `*` matches a single
|
|
40
|
+
* segment (`session.*` matches `session.create` but not `session.create.foo`),
|
|
41
|
+
* `**` matches deeply. Defaults to `['session.*', 'user.create', 'user.delete']`
|
|
42
|
+
* — the SOC2/HIPAA minimum. Pass `['**']` to audit everything.
|
|
43
|
+
*/
|
|
44
|
+
events?: readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* Custom event-name resolver — invoked when the bridge can't classify
|
|
47
|
+
* an endpoint hook firing. Return a string (used as the audit `action`)
|
|
48
|
+
* to keep it; return `null` to drop. Default behaviour: emits
|
|
49
|
+
* `endpoint.before` / `endpoint.after` / `endpoint.error` with the
|
|
50
|
+
* matched path in `payload.path`.
|
|
51
|
+
*/
|
|
52
|
+
resolveEndpointEvent?: (phase: "before" | "after" | "error", ctx: {
|
|
53
|
+
path?: string;
|
|
54
|
+
method?: string;
|
|
55
|
+
error?: unknown;
|
|
56
|
+
}) => string | null;
|
|
57
|
+
/**
|
|
58
|
+
* Maximum number of events to buffer before `attach(app)` is called.
|
|
59
|
+
* Older events are dropped FIFO once full. Default 1000 — enough for
|
|
60
|
+
* boot-time flow even on slow Fastify init paths.
|
|
61
|
+
*/
|
|
62
|
+
bufferSize?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Optional pre-flight transform — runs before the audit row is written.
|
|
65
|
+
* Return `null` to drop the event; otherwise the returned event is
|
|
66
|
+
* forwarded. Use to redact tokens, add custom payload fields, or
|
|
67
|
+
* map BA-specific event names to your own taxonomy.
|
|
68
|
+
*/
|
|
69
|
+
transform?: (event: AuthEvent) => AuthEvent | null | Promise<AuthEvent | null>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Result of `wireBetterAuthAudit` — duck-typed BA `hooks` + `databaseHooks`
|
|
73
|
+
* config plus an `attach(app)` method to connect the live audit logger.
|
|
74
|
+
*/
|
|
75
|
+
interface BetterAuthAuditBridge {
|
|
76
|
+
/**
|
|
77
|
+
* Spread into `betterAuth({ hooks })`. BA's top-level `hooks.before` /
|
|
78
|
+
* `hooks.after` slots take a single async function each (not an array).
|
|
79
|
+
* The bridge collapses its internal endpoint classifier into one dispatcher
|
|
80
|
+
* per phase. Returns `{}` so BA's `runAfterHooks` reads `.headers` / `.response`
|
|
81
|
+
* on a real object instead of crashing on undefined. For plugin-author array
|
|
82
|
+
* form, see {@link asPluginHooks}.
|
|
83
|
+
*/
|
|
84
|
+
hooks: {
|
|
85
|
+
before: (ctx: BetterAuthHookContext) => Promise<Record<string, never>>;
|
|
86
|
+
after: (ctx: BetterAuthHookContext) => Promise<Record<string, never>>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Plugin-form hooks — array of `{ matcher, handler }` entries suitable for
|
|
90
|
+
* `betterAuth({ plugins: [{ id, hooks: bridge.asPluginHooks() }] })`. Use
|
|
91
|
+
* when you're writing a BA plugin and want the audit dispatch to ride along
|
|
92
|
+
* with your plugin's own hooks instead of occupying the top-level slot.
|
|
93
|
+
*/
|
|
94
|
+
asPluginHooks(): {
|
|
95
|
+
before: BetterAuthHookEntry[];
|
|
96
|
+
after: BetterAuthHookEntry[];
|
|
97
|
+
};
|
|
98
|
+
/** Spread into `betterAuth({ databaseHooks })`. */
|
|
99
|
+
databaseHooks: {
|
|
100
|
+
user: {
|
|
101
|
+
create: {
|
|
102
|
+
after: (user: {
|
|
103
|
+
id?: string;
|
|
104
|
+
}) => Promise<void>;
|
|
105
|
+
};
|
|
106
|
+
update: {
|
|
107
|
+
after: (user: {
|
|
108
|
+
id?: string;
|
|
109
|
+
}) => Promise<void>;
|
|
110
|
+
};
|
|
111
|
+
delete?: {
|
|
112
|
+
after: (user: {
|
|
113
|
+
id?: string;
|
|
114
|
+
}) => Promise<void>;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
session: {
|
|
118
|
+
create: {
|
|
119
|
+
after: (session: SessionLike) => Promise<void>;
|
|
120
|
+
};
|
|
121
|
+
update?: {
|
|
122
|
+
after: (session: SessionLike) => Promise<void>;
|
|
123
|
+
};
|
|
124
|
+
delete?: {
|
|
125
|
+
after: (session: SessionLike) => Promise<void>;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Connect a live Fastify instance after boot. Buffered events from the
|
|
131
|
+
* BA construction phase are flushed in order; subsequent events stream
|
|
132
|
+
* through the connected `app.audit.custom(...)` directly.
|
|
133
|
+
*/
|
|
134
|
+
attach(app: FastifyInstance): void;
|
|
135
|
+
/**
|
|
136
|
+
* Manual emit — for hosts that need to record auth events outside BA's
|
|
137
|
+
* hook surface (e.g. webhook signature failures, custom MFA flows).
|
|
138
|
+
*/
|
|
139
|
+
emit(event: AuthEvent): void;
|
|
140
|
+
/**
|
|
141
|
+
* Observability counters — surface to your metrics backend. Counters are
|
|
142
|
+
* cumulative since bridge construction; reset when `wireBetterAuthAudit`
|
|
143
|
+
* is called again. Useful for Prometheus exporters that scrape periodically.
|
|
144
|
+
*/
|
|
145
|
+
getStats(): {
|
|
146
|
+
/** Events buffered during pre-`attach` phase that were dropped due to `bufferSize` overflow. */droppedFromBuffer: number; /** Events that reached `app.audit.custom(...)` but threw (audit store failure). */
|
|
147
|
+
dispatchFailures: number; /** Total `dispatch` calls — useful to verify BA is actually invoking the bridge's hooks. */
|
|
148
|
+
dispatchAttempts: number; /** Events currently buffered awaiting `attach`. */
|
|
149
|
+
pendingBuffered: number;
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Single BA hook entry — duck-typed to avoid pinning a BA major version.
|
|
154
|
+
* The shape mirrors `better-auth`'s public `hooks.{before,after}` API.
|
|
155
|
+
*/
|
|
156
|
+
interface BetterAuthHookEntry {
|
|
157
|
+
matcher: (ctx: BetterAuthHookContext) => boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Returns a (possibly empty) object so BA's `runBeforeHooks` /
|
|
160
|
+
* `runAfterHooks` can read `.headers` / `.response` off the result without
|
|
161
|
+
* the `Cannot read properties of undefined` crash that hits when handlers
|
|
162
|
+
* return `void`. The bridge always returns `{}` because it's a side-effect
|
|
163
|
+
* dispatcher — no header rewrites or response substitution.
|
|
164
|
+
*/
|
|
165
|
+
handler: (ctx: BetterAuthHookContext) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
166
|
+
}
|
|
167
|
+
/** Subset of BA's hook context the bridge actually reads. */
|
|
168
|
+
interface BetterAuthHookContext {
|
|
169
|
+
path?: string;
|
|
170
|
+
method?: string;
|
|
171
|
+
body?: Record<string, unknown>;
|
|
172
|
+
headers?: Record<string, unknown>;
|
|
173
|
+
context?: {
|
|
174
|
+
session?: {
|
|
175
|
+
user?: {
|
|
176
|
+
id?: string;
|
|
177
|
+
};
|
|
178
|
+
activeOrganizationId?: string;
|
|
179
|
+
};
|
|
180
|
+
request?: {
|
|
181
|
+
ip?: string;
|
|
182
|
+
headers?: Record<string, string | undefined>;
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
returned?: unknown;
|
|
186
|
+
error?: unknown;
|
|
187
|
+
}
|
|
188
|
+
/** Subset of BA's session shape the bridge reads from databaseHooks. */
|
|
189
|
+
interface SessionLike {
|
|
190
|
+
id?: string;
|
|
191
|
+
userId?: string;
|
|
192
|
+
activeOrganizationId?: string;
|
|
193
|
+
ipAddress?: string;
|
|
194
|
+
userAgent?: string;
|
|
195
|
+
impersonatedBy?: string;
|
|
196
|
+
}
|
|
197
|
+
declare function wireBetterAuthAudit(opts?: WireBetterAuthAuditOptions): BetterAuthAuditBridge;
|
|
198
|
+
//#endregion
|
|
199
|
+
export { AuthEvent, AuthEventName, BetterAuthAuditBridge, BetterAuthHookContext, BetterAuthHookEntry, WireBetterAuthAuditOptions, wireBetterAuthAudit };
|