@classytic/arc 2.20.0 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/dist/{BaseController-D-MHZ27_.mjs → BaseController-C6FlRWxF.mjs} +2 -2
  2. package/dist/{EventTransport-IEn7Tn-Q.d.mts → EventTransport-QmY7A258.d.mts} +0 -1
  3. package/dist/{QueryCache-TRfXau3W.d.mts → QueryCache-Z1B38koh.d.mts} +0 -1
  4. package/dist/{actionPermissions-C9RMiIpc.mjs → actionPermissions-ze70xXJi.mjs} +1 -1
  5. package/dist/audit/index.d.mts +9 -5
  6. package/dist/auth/audit.d.mts +7 -4
  7. package/dist/auth/audit.mjs +5 -0
  8. package/dist/auth/index.d.mts +35 -14
  9. package/dist/auth/index.mjs +6 -3
  10. package/dist/auth/redis-session.d.mts +1 -2
  11. package/dist/cache/index.d.mts +2 -3
  12. package/dist/cli/commands/describe.d.mts +1 -2
  13. package/dist/cli/commands/docs.mjs +1 -1
  14. package/dist/cli/commands/init.mjs +1 -1
  15. package/dist/cli/index.mjs +1 -1
  16. package/dist/context/index.d.mts +2 -2
  17. package/dist/core/index.d.mts +3 -3
  18. package/dist/core/index.mjs +4 -4
  19. package/dist/{core-CWhyGkiM.mjs → core-b6fgFgnd.mjs} +129 -17
  20. package/dist/{createActionRouter-HlQso0jO.mjs → createActionRouter-h1cEEaEX.mjs} +10 -6
  21. package/dist/{createAggregationRouter-5LzPzgw1.mjs → createAggregationRouter-B1C0kvTL.mjs} +3 -3
  22. package/dist/{createApp-D6uwzCKu.mjs → createApp-Ci7yG5gv.mjs} +390 -192
  23. package/dist/discovery/index.d.mts +0 -1
  24. package/dist/docs/index.d.mts +1 -2
  25. package/dist/docs/index.mjs +1 -1
  26. package/dist/{elevation-xGUBq6p_.d.mts → elevation-C9s5hFP_.d.mts} +0 -1
  27. package/dist/encryption/index.d.mts +2 -144
  28. package/dist/encryption/index.mjs +9 -5
  29. package/dist/{errorHandler-Dxf6P_kV.mjs → errorHandler-BTzXSwIg.mjs} +24 -3
  30. package/dist/{errorHandler-BtUUDPEa.d.mts → errorHandler-C6yv4ZTW.d.mts} +13 -1
  31. package/dist/{errors-DOHkjQlD.d.mts → errors-DHcHVAgk.d.mts} +0 -1
  32. package/dist/{eventPlugin-DbBFd3x_.d.mts → eventPlugin-A6EbthXR.d.mts} +10 -6
  33. package/dist/events/index.d.mts +9 -6
  34. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  35. package/dist/events/transports/redis.d.mts +1 -2
  36. package/dist/factory/index.d.mts +30 -9
  37. package/dist/factory/index.mjs +35 -4
  38. package/dist/{fastify-augmentation-CCQJEDgh.d.mts → fastify-augmentation-9_fuetB4.d.mts} +2 -3
  39. package/dist/fields-D3lhgzhD.d.mts +121 -0
  40. package/dist/health-ScyjIVo5.mjs +202 -0
  41. package/dist/hooks/index.d.mts +1 -1
  42. package/dist/idempotency/index.d.mts +4 -3
  43. package/dist/idempotency/index.mjs +2 -0
  44. package/dist/idempotency/redis.d.mts +1 -1
  45. package/dist/{types-BHMKlMBU.d.mts → index-BEu4wjbL.d.mts} +241 -80
  46. package/dist/{index-DUa8WHz3.d.mts → index-D8MKYGDa.d.mts} +88 -7
  47. package/dist/{index-_--GyzcO.d.mts → index-DbtgCOCj.d.mts} +1324 -1228
  48. package/dist/{index-CdFkIMEd.d.mts → index-ogIHvOjo.d.mts} +36 -7
  49. package/dist/index.d.mts +8 -7
  50. package/dist/index.mjs +6 -6
  51. package/dist/{init-YH_nslQR.mjs → init-DleK3p9f.mjs} +272 -139
  52. package/dist/integrations/event-gateway.d.mts +2 -3
  53. package/dist/integrations/index.d.mts +2 -2
  54. package/dist/integrations/jobs.d.mts +0 -1
  55. package/dist/integrations/mcp/index.d.mts +6 -7
  56. package/dist/integrations/mcp/index.mjs +1 -1
  57. package/dist/integrations/mcp/testing.d.mts +1 -2
  58. package/dist/integrations/mcp/testing.mjs +1 -1
  59. package/dist/integrations/streamline.d.mts +2 -2
  60. package/dist/integrations/webhooks.d.mts +8 -5
  61. package/dist/integrations/webhooks.mjs +9 -5
  62. package/dist/integrations/websocket-pushref-redis.d.mts +1 -2
  63. package/dist/integrations/websocket-redis.d.mts +1 -2
  64. package/dist/integrations/websocket.d.mts +2 -2
  65. package/dist/jsonBody-BlzAoGCe.mjs +43 -0
  66. package/dist/{loadResources-B8UmpITt.mjs → loadResources-DpU8pfjV.mjs} +4 -3
  67. package/dist/logger/index.d.mts +26 -1
  68. package/dist/logger/index.mjs +39 -1
  69. package/dist/{mcpPlugin-CuW6L_uD.mjs → mcpPlugin-ByA2tf6D.mjs} +8 -4
  70. package/dist/middleware/index.d.mts +1 -2
  71. package/dist/{module-JYH9V0I8.d.mts → module-B4u10iOJ.d.mts} +71 -1
  72. package/dist/{openapi-Dq6RbEGK.mjs → openapi-BRpMZD7C.mjs} +3 -3
  73. package/dist/permissions/index.d.mts +4 -3
  74. package/dist/permissions/index.mjs +2 -2
  75. package/dist/{permissions-CgbOLJZG.mjs → permissions-BJMuKMl7.mjs} +33 -1
  76. package/dist/pipeline/index.d.mts +1 -2
  77. package/dist/plugins/index.d.mts +96 -7
  78. package/dist/plugins/index.mjs +86 -268
  79. package/dist/plugins/response-cache.d.mts +5 -3
  80. package/dist/plugins/response-cache.mjs +1 -0
  81. package/dist/plugins/tracing-entry.d.mts +1 -1
  82. package/dist/plugins/tracing-entry.mjs +7 -4
  83. package/dist/presets/filesUpload.d.mts +4 -5
  84. package/dist/presets/filesUpload.mjs +1 -1
  85. package/dist/presets/index.d.mts +1 -2
  86. package/dist/presets/index.mjs +1 -1
  87. package/dist/presets/multiTenant.d.mts +1 -2
  88. package/dist/presets/search.d.mts +2 -3
  89. package/dist/presets/search.mjs +1 -1
  90. package/dist/{presets-DWsYQdbV.mjs → presets-gw0ciIUD.mjs} +1 -1
  91. package/dist/{pushref-registry-DnCqL3aa.d.mts → pushref-registry-BbcnpNTm.d.mts} +4 -2
  92. package/dist/{queryCachePlugin-xzFyKAjT.d.mts → queryCachePlugin-CfYWq-Ak.d.mts} +1 -2
  93. package/dist/rateLimitKey-BoWRH3e7.mjs +14 -0
  94. package/dist/{redis-C3W0qbz8.d.mts → redis-UDtLaNj6.d.mts} +0 -1
  95. package/dist/{redis-stream-DsP1vqZB.d.mts → redis-stream-iVR2l7aS.d.mts} +1 -2
  96. package/dist/{registerRoute-DGSREwPw.mjs → registerRoute-xHc42fwB.mjs} +38 -18
  97. package/dist/registry/index.d.mts +2 -2
  98. package/dist/requestId-5BhTVzBv.mjs +113 -0
  99. package/dist/schemaConverter-Ds5reSGs.mjs +168 -0
  100. package/dist/{schemaIR-ajetw3Fv.mjs → schemaIR-B-6SPe7g.mjs} +2 -2
  101. package/dist/schemas/index.d.mts +0 -1
  102. package/dist/scim/index.d.mts +0 -1
  103. package/dist/scim/index.mjs +6 -7
  104. package/dist/scope/index.d.mts +2 -3
  105. package/dist/scope/index.mjs +2 -76
  106. package/dist/scope-k15RXfcq.mjs +64 -0
  107. package/dist/{sessionManager-BXG-HGwG.d.mts → sessionManager-BHOM3N_0.d.mts} +10 -6
  108. package/dist/{storage-Co_PQpeQ.d.mts → storage-DLUZ04kK.d.mts} +8 -4
  109. package/dist/testing/index.d.mts +83 -4
  110. package/dist/testing/index.mjs +74 -4
  111. package/dist/testing/storageContract.d.mts +1 -2
  112. package/dist/{tracing-D8jlGXP7.d.mts → tracing-CsGKQJGg.d.mts} +0 -1
  113. package/dist/types/index.d.mts +4 -4
  114. package/dist/types/storage.d.mts +1 -1
  115. package/dist/{types-C9b2HR5W.d.mts → types-Bc42CUyk.d.mts} +1 -2
  116. package/dist/types-Cc91nXuA.d.mts +132 -0
  117. package/dist/{fields-C7ahdGYf.d.mts → types-Csxga7d3.d.mts} +2 -123
  118. package/dist/{types-LNebCoJx.d.mts → types-DH0GupI7.d.mts} +8 -4
  119. package/dist/usage/index.d.mts +142 -0
  120. package/dist/usage/index.mjs +0 -0
  121. package/dist/utils/index.d.mts +220 -144
  122. package/dist/utils/index.mjs +3 -3
  123. package/dist/{utils-ChjYQpjn.mjs → utils-FhJ88TJE.mjs} +129 -39
  124. package/dist/{versioning-D_eBCfNr.d.mts → versioning-DLwklPlG.d.mts} +1 -7
  125. package/dist/{websocket-MlYlrYq0.d.mts → websocket-uuWqM6UY.d.mts} +5 -4
  126. package/llms.txt +39 -0
  127. package/package.json +453 -447
  128. package/skills/arc/SKILL.md +14 -8
  129. package/skills/arc/references/api-reference.md +34 -0
  130. package/skills/arc/references/auth.md +21 -4
  131. package/skills/arc/references/mcp.md +1 -1
  132. package/skills/arc/references/production.md +44 -2
  133. package/skills/arc-code-review/SKILL.md +1 -1
  134. package/skills/arc-code-review/references/anti-patterns.md +71 -18
  135. package/skills/arc-code-review/references/arc-cheatsheet.md +15 -2
  136. package/skills/arc-code-review/references/migration-recipes.md +7 -7
  137. package/skills/arc-code-review/references/mongokit-migration.md +4 -3
  138. package/skills/arc-module-publishing/SKILL.md +243 -0
  139. package/skills/arc-module-publishing/references/authoring-modules.md +327 -0
  140. package/skills/arc-module-publishing/references/package-manifest.md +157 -0
  141. package/skills/arc-module-publishing/references/publishing-workflow.md +182 -0
  142. package/dist/preloadResources-CHw3_oA_.mjs +0 -45
  143. package/dist/schemaConverter-U0MnO9vd.mjs +0 -110
@@ -1,5 +1,4 @@
1
1
  import { FastifyPluginAsync, FastifyReply, FastifyRequest } from "fastify";
2
-
3
2
  //#region src/auth/sessionManager.d.ts
4
3
  /**
5
4
  * Session data stored in the session store.
@@ -81,13 +80,18 @@ declare module "fastify" {
81
80
  authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
82
81
  /** Session management helpers */
83
82
  sessionManager: {
84
- /** Create a new session for a user */createSession: (userId: string, metadata?: Record<string, unknown>) => Promise<{
83
+ /** Create a new session for a user */
84
+ createSession: (userId: string, metadata?: Record<string, unknown>) => Promise<{
85
85
  sessionId: string;
86
86
  cookie: string;
87
- }>; /** Revoke a specific session */
88
- revokeSession: (sessionId: string) => Promise<void>; /** Revoke all sessions for a user */
89
- revokeAllSessions: (userId: string) => Promise<void>; /** Revoke all sessions except the current one */
90
- revokeOtherSessions: (userId: string, currentSessionId: string) => Promise<void>; /** Refresh a session (reset updatedAt, extend expiry if needed) */
87
+ }>;
88
+ /** Revoke a specific session */
89
+ revokeSession: (sessionId: string) => Promise<void>;
90
+ /** Revoke all sessions for a user */
91
+ revokeAllSessions: (userId: string) => Promise<void>;
92
+ /** Revoke all sessions except the current one */
93
+ revokeOtherSessions: (userId: string, currentSessionId: string) => Promise<void>;
94
+ /** Refresh a session (reset updatedAt, extend expiry if needed) */
91
95
  refreshSession: (sessionId: string) => Promise<SessionData | null>;
92
96
  };
93
97
  }
@@ -98,14 +98,18 @@ interface StorageReadRange {
98
98
  type StorageReadResult = {
99
99
  kind: "stream";
100
100
  stream: NodeJS.ReadableStream;
101
- contentType: string; /** Total size of the full object (NOT the ranged slice). Required for `Content-Range`. */
102
- bytes?: number; /** Actual byte range returned when the caller passed `range`. */
101
+ contentType: string;
102
+ /** Total size of the full object (NOT the ranged slice). Required for `Content-Range`. */
103
+ bytes?: number;
104
+ /** Actual byte range returned when the caller passed `range`. */
103
105
  range?: StorageReadRange;
104
106
  } | {
105
107
  kind: "buffer";
106
108
  buffer: Buffer;
107
- contentType: string; /** Total size of the full object. Used for `Content-Range` on partial reads. */
108
- totalBytes?: number; /** Actual byte range returned when the caller passed `range`. */
109
+ contentType: string;
110
+ /** Total size of the full object. Used for `Content-Range` on partial reads. */
111
+ totalBytes?: number;
112
+ /** Actual byte range returned when the caller passed `range`. */
109
113
  range?: StorageReadRange;
110
114
  };
111
115
  /**
@@ -1,10 +1,10 @@
1
- import { V as ResourceDefinition, qt as AnyRecord } from "../index-_--GyzcO.mjs";
2
- import { d as preloadResourcesAsync, r as CreateAppOptions, u as preloadResources } from "../types-BHMKlMBU.mjs";
1
+ import { V as ResourceDefinition, qt as AnyRecord } from "../index-DbtgCOCj.mjs";
2
+ import { n as ArcModuleInput } from "../module-B4u10iOJ.mjs";
3
+ import { d as preloadResourcesAsync, t as CreateAppOptions, u as preloadResources } from "../index-BEu4wjbL.mjs";
3
4
  import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
4
5
  import { FastifyInstance, FastifyServerOptions } from "fastify";
5
6
  import { Mock } from "vitest";
6
7
  import { StandardRepo } from "@classytic/repo-core/repository";
7
-
8
8
  //#region src/testing/assertions.d.ts
9
9
  /**
10
10
  * expectArc — Arc-specific response assertions
@@ -297,6 +297,85 @@ declare function createBetterAuthTestHelpers(options?: BetterAuthTestHelpersOpti
297
297
  */
298
298
  declare function setupBetterAuthTestApp(input: SetupBetterAuthTestAppInput): Promise<SetupBetterAuthTestAppResult>;
299
299
  //#endregion
300
+ //#region src/testing/bootModuleApp.d.ts
301
+ /** Handed to a modules factory — the in-memory DB is live at call time. */
302
+ /**
303
+ * A provisioned test database — what the `database` seam yields. Arc
304
+ * core never names a driver: kits ship factories (`mongoMemoryDatabase`
305
+ * is the built-in default; a sqlitekit/pgkit testkit ships its own) and
306
+ * the connection flows through as an opaque generic.
307
+ */
308
+ interface TestDatabase<TConn = unknown> {
309
+ /** Connection string, when the backend has one (informational). */
310
+ uri: string;
311
+ /** Driver connection handle passed to the modules factory. */
312
+ connection: TConn;
313
+ /** Stop/disconnect everything this factory started. MUST be idempotent-safe to call once. */
314
+ teardown(): Promise<void>;
315
+ }
316
+ /** The DB-provisioning seam — `bootModuleApp({ database })`. */
317
+ type TestDatabaseFactory<TConn = unknown> = (opts: {
318
+ replset?: boolean;
319
+ }) => Promise<TestDatabase<TConn>>;
320
+ interface TestkitContext<TConn = unknown> {
321
+ /** The provisioned database's connection string. */
322
+ uri: string;
323
+ /** @deprecated Alias of `uri` from the Mongo-default era — prefer `uri`. */
324
+ mongoUri: string;
325
+ /**
326
+ * Driver connection handle (the default factory yields mongoose's
327
+ * DEFAULT connection). Generic so DB-typed wrappers assert the driver
328
+ * type ONCE: `bootModuleApp<Connection>(...)`. Arc core stays DB-agnostic.
329
+ */
330
+ connection: TConn;
331
+ }
332
+ type BootModulesInput<TConn = unknown> = ArcModuleInput | readonly ArcModuleInput[] | ((ctx: TestkitContext<TConn>) => ArcModuleInput | readonly ArcModuleInput[] | Promise<ArcModuleInput | readonly ArcModuleInput[]>);
333
+ interface BootModuleAppOptions<TConn = unknown> {
334
+ /**
335
+ * DB provisioner. Default: `mongoMemoryDatabase` (in-memory MongoDB —
336
+ * lazy devDep imports, nothing Mongo touches arc's runtime). Kits for
337
+ * other stores inject their own factory here; the rest of the harness
338
+ * (module resolution, app boot, teardown ordering) is DB-agnostic.
339
+ */
340
+ database?: TestDatabaseFactory<TConn>;
341
+ /** Single-node replica set (transactions). Default: standalone. Passed to the database factory. */
342
+ replset?: boolean;
343
+ /**
344
+ * Extra `createApp` options merged over the testing defaults
345
+ * (`preset: 'testing'`, `auth: false`, `sensible: false` — utility
346
+ * plugins stay off so the testkit is dependency-light; re-enable per
347
+ * boot when a module genuinely exercises one).
348
+ */
349
+ app?: Partial<CreateAppOptions>;
350
+ }
351
+ interface ModuleTestApp<TConn = unknown> {
352
+ app: FastifyInstance;
353
+ /** The provisioned database's connection string. */
354
+ uri: string;
355
+ /** @deprecated Alias of `uri` from the Mongo-default era — prefer `uri`. */
356
+ mongoUri: string;
357
+ /** The mongoose `Connection` handed to the modules factory. */
358
+ connection: TConn;
359
+ /**
360
+ * Typed module-export accessor — `t.exports<CatalogEngine>('catalog')`
361
+ * instead of reaching through `(t.app as ...).arc.modules.catalog`.
362
+ * Delegates to `getModuleExports` (throws with the registered-module
363
+ * list when the name is unknown — same contract hosts get).
364
+ */
365
+ exports<TExports = unknown>(name: string): TExports;
366
+ /** Close app → disconnect mongoose → stop the in-memory server. Idempotent. */
367
+ close(): Promise<void>;
368
+ }
369
+ /**
370
+ * The built-in DB factory: in-memory MongoDB via lazy devDep imports.
371
+ * Everything Mongo-specific about the harness lives HERE — the harness
372
+ * itself is driver-blind and any kit can replace this via `database`.
373
+ */
374
+ declare function mongoMemoryDatabase(opts: {
375
+ replset?: boolean;
376
+ }): Promise<TestDatabase<unknown>>;
377
+ declare function bootModuleApp<TConn = unknown>(modules: BootModulesInput<TConn>, options?: BootModuleAppOptions<TConn>): Promise<ModuleTestApp<TConn>>;
378
+ //#endregion
300
379
  //#region src/testing/fixtures.d.ts
301
380
  type FixtureFactory<T extends AnyRecord = AnyRecord> = (data: Partial<T>) => Promise<T>;
302
381
  /** Delete hook invoked by `clear()` for records that were created through a factory. */
@@ -541,4 +620,4 @@ declare function createTestApp(options?: CreateTestAppOptions): Promise<TestAppC
541
620
  */
542
621
  declare function createMinimalTestApp(options?: FastifyServerOptions): FastifyInstance;
543
622
  //#endregion
544
- export { type ArcAssertion, type ArcResponseLike, type AuthMode, type AuthResponse, type BetterAuthTestHelpers, type BetterAuthTestHelpersOptions, type BetterAuthTestUser, type CreateOrgInput, type CreateTestAppOptions, type DbMode, type FixtureDestroyer, type FixtureFactory, type FixtureRegistration, HttpTestHarness, type HttpTestHarnessOptions, type MockRepository, type OrgResponse, type RoleConfig, type SetupBetterAuthTestAppInput, type SetupBetterAuthTestAppResult, type SignInInput, type SignUpInput, type StorageContractSetup, type StorageContractSetupResult, type TestAppContext, type TestAuthProvider, type TestAuthSession, type TestFixtures, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestTimer, expectArc, preloadResources, preloadResourcesAsync, runStorageContract, safeParseBody, setupBetterAuthTestApp, waitFor };
623
+ export { type ArcAssertion, type ArcResponseLike, type AuthMode, type AuthResponse, type BetterAuthTestHelpers, type BetterAuthTestHelpersOptions, type BetterAuthTestUser, type BootModuleAppOptions, type BootModulesInput, type CreateOrgInput, type CreateTestAppOptions, type DbMode, type FixtureDestroyer, type FixtureFactory, type FixtureRegistration, HttpTestHarness, type HttpTestHarnessOptions, type MockRepository, type ModuleTestApp, type OrgResponse, type RoleConfig, type SetupBetterAuthTestAppInput, type SetupBetterAuthTestAppResult, type SignInInput, type SignUpInput, type StorageContractSetup, type StorageContractSetupResult, type TestAppContext, type TestAuthProvider, type TestAuthSession, type TestDatabase, type TestDatabaseFactory, type TestFixtures, type TestkitContext, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runStorageContract, safeParseBody, setupBetterAuthTestApp, waitFor };
@@ -1,5 +1,5 @@
1
1
  import { t as CRUD_OPERATIONS } from "../constants-DNre0wRg.mjs";
2
- import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-CHw3_oA_.mjs";
2
+ import { d as getModuleExports, h as preloadResourcesAsync, m as preloadResources, n as createApp } from "../createApp-Ci7yG5gv.mjs";
3
3
  import { runStorageContract } from "./storageContract.mjs";
4
4
  import Fastify from "fastify";
5
5
  import { afterAll, describe, expect, it, vi } from "vitest";
@@ -210,7 +210,10 @@ function createJwtAuthProvider(app, opts = {}) {
210
210
  if (!config.user) throw new Error(`[jwt] role '${role}' has neither 'user' nor 'token'`);
211
211
  const jwt = app.jwt;
212
212
  if (!jwt?.sign) throw new Error(`[jwt] app.jwt.sign() is unavailable — register @fastify/jwt before calling createJwtAuthProvider.`);
213
- return jwt.sign(config.user);
213
+ return jwt.sign({
214
+ type: "access",
215
+ ...config.user
216
+ });
214
217
  }
215
218
  });
216
219
  }
@@ -459,6 +462,73 @@ async function setupBetterAuthTestApp(input) {
459
462
  };
460
463
  }
461
464
  //#endregion
465
+ //#region src/testing/bootModuleApp.ts
466
+ /**
467
+ * The built-in DB factory: in-memory MongoDB via lazy devDep imports.
468
+ * Everything Mongo-specific about the harness lives HERE — the harness
469
+ * itself is driver-blind and any kit can replace this via `database`.
470
+ */
471
+ async function mongoMemoryDatabase(opts) {
472
+ let mms;
473
+ try {
474
+ mms = await import("mongodb-memory-server");
475
+ } catch {
476
+ throw new Error("[arc-testing] bootModuleApp's default database is in-memory MongoDB — install 'mongodb-memory-server' + 'mongoose' as devDependencies, or inject your own `database` factory for a different store");
477
+ }
478
+ const server = opts.replset ? await mms.MongoMemoryReplSet.create({ replSet: { count: 1 } }) : await mms.MongoMemoryServer.create();
479
+ const uri = server.getUri();
480
+ const mongoose = (await import("mongoose")).default;
481
+ if (mongoose.connection.readyState !== 0) await mongoose.disconnect();
482
+ await mongoose.connect(uri);
483
+ mongoose.connection.deleteModel(/.*/);
484
+ return {
485
+ uri,
486
+ connection: mongoose.connection,
487
+ teardown: async () => {
488
+ if (mongoose.connection.readyState !== 0) await mongoose.disconnect().catch(() => void 0);
489
+ await server.stop().catch(() => void 0);
490
+ }
491
+ };
492
+ }
493
+ async function bootModuleApp(modules, options = {}) {
494
+ const db = await (options.database ?? mongoMemoryDatabase)({ replset: options.replset ?? false });
495
+ const ctx = {
496
+ uri: db.uri,
497
+ mongoUri: db.uri,
498
+ connection: db.connection
499
+ };
500
+ const resolved = typeof modules === "function" ? await modules(ctx) : modules;
501
+ const list = Array.isArray(resolved) ? resolved : [resolved];
502
+ let app;
503
+ try {
504
+ app = await createApp({
505
+ preset: "testing",
506
+ auth: false,
507
+ sensible: false,
508
+ ...options.app,
509
+ modules: list
510
+ });
511
+ await app.ready();
512
+ } catch (err) {
513
+ await db.teardown().catch(() => void 0);
514
+ throw err;
515
+ }
516
+ let closed = false;
517
+ return {
518
+ app,
519
+ uri: db.uri,
520
+ mongoUri: db.uri,
521
+ connection: db.connection,
522
+ exports: (name) => getModuleExports(app, name),
523
+ close: async () => {
524
+ if (closed) return;
525
+ closed = true;
526
+ await app.close().catch(() => void 0);
527
+ await db.teardown().catch(() => void 0);
528
+ }
529
+ };
530
+ }
531
+ //#endregion
462
532
  //#region src/testing/fixtures.ts
463
533
  function createTestFixtures() {
464
534
  const registry = /* @__PURE__ */ new Map();
@@ -1046,7 +1116,7 @@ function pickDefaultAuth(authMode, callerAuth) {
1046
1116
  };
1047
1117
  }
1048
1118
  async function createTestApp(options = {}) {
1049
- const { createApp } = await import("../createApp-D6uwzCKu.mjs").then((n) => n.r);
1119
+ const { createApp } = await import("../createApp-Ci7yG5gv.mjs").then((n) => n.r);
1050
1120
  const { resources = [], db = "in-memory", connectMongoose = false, authMode = "jwt", defaultOrgId, plugins, auth: callerAuth, ...appOptions } = options;
1051
1121
  let dbHandle;
1052
1122
  let dbUri;
@@ -1116,4 +1186,4 @@ function createMinimalTestApp(options = {}) {
1116
1186
  });
1117
1187
  }
1118
1188
  //#endregion
1119
- export { HttpTestHarness, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestTimer, expectArc, preloadResources, preloadResourcesAsync, runStorageContract, safeParseBody, setupBetterAuthTestApp, waitFor };
1189
+ export { HttpTestHarness, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runStorageContract, safeParseBody, setupBetterAuthTestApp, waitFor };
@@ -1,5 +1,4 @@
1
- import { t as Storage } from "../storage-Co_PQpeQ.mjs";
2
-
1
+ import { t as Storage } from "../storage-DLUZ04kK.mjs";
3
2
  //#region src/testing/storageContract.d.ts
4
3
  interface StorageContractSetupResult {
5
4
  storage: Storage;
@@ -1,6 +1,5 @@
1
1
  import { FastifyInstance, FastifyRequest } from "fastify";
2
2
  import { Span, Tracer } from "@opentelemetry/api";
3
-
4
3
  //#region src/plugins/tracing.d.ts
5
4
  interface TracingOptions {
6
5
  /**
@@ -1,5 +1,5 @@
1
- import { $ as OnTenantDeleteConfig, $t as UserOrganization, A as RequestIdOptions, C as RequestContext, D as HealthCheck, E as GracefulShutdownOptions, F as FastifyWithDecorators, Fn as BaseControllerOptions, G as ActionsMap, Gt as JwtContext, H as ActionDefinition, Ht as AuthPluginOptions, I as MiddlewareHandler, J as CrudRouteKey, Jt as ApiResponse, K as ArcFieldRule, Kt as TokenPair, L as RequestWithExtras, M as EventsDecorator, N as FastifyRequestExtras, O as HealthOptions, P as FastifyWithAuth, Q as MiddlewareConfig, Qt as UserLike, S as QueryParserInterface, St as RouteHandler, T as CrudRouterOptions, U as ActionEntry, Ut as Authenticator, Vt as AuthHelpers, W as ActionHandlerFn, Wt as AuthenticatorContext, X as EventDefinition, Xt as JWTPayload, Y as CrudSchemas, Yt as ArcRequest, Z as FieldRule, Zt as ObjectId, _ as ControllerQueryOptions, _t as ControllerLike, a as InferAdapterDoc, at as ResolvedTenantPurge, b as ParsedQuery, bt as IControllerResponse, c as TypedController, ct as ResourceExtensions, d as PaginationResult, dt as ResourcePermissions, et as OpenApiSchemas, f as IntrospectionData, ft as RouteDefinition, g as ArcInternalMetadata, gt as ControllerHandler, h as ResourceMetadata, ht as RouteSchemaOptions, i as ValidationResult, it as RateLimitConfig, j as ArcDecorator, k as IntrospectionPluginOptions, l as TypedRepository, lt as ResourceHookContext, m as RegistryStats, mt as RouteMethod, n as ConfigError, nt as PresetHook, o as InferDocType, ot as ResourceCacheConfig, p as RegistryEntry, pt as RouteMcpConfig, q as CrudController, qt as AnyRecord, r as ValidateOptions, rt as PresetResult, s as InferResourceDoc, st as ResourceConfig, t as RouteHandlerMethod, tt as PresetFunction, u as TypedResourceConfig, ut as ResourceHooks, v as LookupOption, vt as FastifyHandler, w as ServiceContext, x as PopulateOption, xt as IRequestContext, y as OwnershipCheck, yt as IController } from "../index-_--GyzcO.mjs";
2
- import { i as RequestScope } from "../types-LNebCoJx.mjs";
3
- import { c as PermissionCheck, d as UserBase, l as PermissionContext, u as PermissionResult } from "../fields-C7ahdGYf.mjs";
4
- import { n as ElevationOptions, t as ElevationEvent } from "../elevation-xGUBq6p_.mjs";
1
+ import { $ as OpenApiSchemas, $t as UserOrganization, A as RequestIdOptions, At as RouteDefinition, Bt as RouteHandler, C as RequestContext, D as HealthCheck, Dt as ActionEntry, E as GracefulShutdownOptions, Et as ActionDefinition, F as FastifyWithDecorators, Fn as BaseControllerOptions, Ft as ControllerLike, G as OnTenantDeleteConfig, Gt as JwtContext, H as CrudController, Ht as AuthPluginOptions, I as MiddlewareHandler, It as FastifyHandler, J as PresetHook, Jt as ApiResponse, K as ResolvedTenantPurge, Kt as TokenPair, L as RequestWithExtras, Lt as IController, M as EventsDecorator, Mt as RouteMethod, N as FastifyRequestExtras, Nt as RateLimitConfig, O as HealthOptions, Ot as ActionHandlerFn, P as FastifyWithAuth, Pt as ControllerHandler, Q as MiddlewareConfig, Qt as UserLike, Rt as IControllerResponse, S as QueryParserInterface, T as CrudRouterOptions, Tt as ResourceCacheConfig, U as ResourceConfig, Ut as Authenticator, Vt as AuthHelpers, W as ResourcePermissions, Wt as AuthenticatorContext, X as CrudRouteKey, Xt as JWTPayload, Y as PresetResult, Yt as ArcRequest, Z as CrudSchemas, Zt as ObjectId, _ as ControllerQueryOptions, a as InferAdapterDoc, at as ResourceExtensions, b as ParsedQuery, c as TypedController, d as PaginationResult, et as RouteSchemaOptions, f as IntrospectionData, g as ArcInternalMetadata, h as ResourceMetadata, i as ValidationResult, it as ResourceHooks, j as ArcDecorator, jt as RouteMcpConfig, k as IntrospectionPluginOptions, kt as ActionsMap, l as TypedRepository, m as RegistryStats, n as ConfigError, nt as FieldRule, o as InferDocType, ot as EventDefinition, p as RegistryEntry, q as PresetFunction, qt as AnyRecord, r as ValidateOptions, rt as ResourceHookContext, s as InferResourceDoc, t as RouteHandlerMethod, tt as ArcFieldRule, u as TypedResourceConfig, v as LookupOption, w as ServiceContext, x as PopulateOption, y as OwnershipCheck, zt as IRequestContext } from "../index-DbtgCOCj.mjs";
2
+ import { i as RequestScope } from "../types-DH0GupI7.mjs";
3
+ import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "../types-Csxga7d3.mjs";
4
+ import { n as ElevationOptions, t as ElevationEvent } from "../elevation-C9s5hFP_.mjs";
5
5
  export type { ActionDefinition, ActionEntry, ActionHandlerFn, ActionsMap, AnyRecord, ApiResponse, ArcDecorator, ArcFieldRule, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRouteKey, CrudRouterOptions, CrudSchemas, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OnTenantDeleteConfig, OpenApiSchemas, OwnershipCheck, PaginationResult, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResolvedTenantPurge, ResourceCacheConfig, ResourceConfig, ResourceExtensions, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteDefinition, RouteHandler, RouteHandlerMethod, RouteMcpConfig, RouteMethod, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult };
@@ -1,2 +1,2 @@
1
- import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-Co_PQpeQ.mjs";
1
+ import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-DLUZ04kK.mjs";
2
2
  export { Storage, StorageContext, StorageFile, StorageReadRange, StorageReadResult, StorageUploadInput };
@@ -1,6 +1,5 @@
1
- import { V as ResourceDefinition } from "./index-_--GyzcO.mjs";
1
+ import { V as ResourceDefinition } from "./index-DbtgCOCj.mjs";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/integrations/mcp/types.d.ts
5
4
  /** Behavioral hints for MCP clients (tool annotations per MCP spec) */
6
5
  interface ToolAnnotations {
@@ -0,0 +1,132 @@
1
+ import { FastifyRequest } from "fastify";
2
+ //#region src/encryption/types.d.ts
3
+ /** JWE key-management algorithm — the protected-header `alg`. */
4
+ type JweAlg = "RSA-OAEP-256" | "RSA-OAEP-384" | "RSA-OAEP-512" | "ECDH-ES" | "ECDH-ES+A256KW" | "A256GCMKW" | "dir";
5
+ /** JWE content-encryption algorithm — the protected-header `enc`. AEAD only. */
6
+ type JweEnc = "A128GCM" | "A192GCM" | "A256GCM";
7
+ /** Encryption strategy for a route's response. */
8
+ type EncryptionMode = "jwe" | "fields";
9
+ /**
10
+ * Opaque key material. For `jwe` mode this is a `jose` `KeyLike` /
11
+ * `CryptoKey` / `Uint8Array`; for `fields` mode a 32-byte secret
12
+ * (`Buffer` / `Uint8Array`). Kept `unknown` at the contract layer so the
13
+ * `KeyProvider` interface carries no hard `jose` type dependency — hosts
14
+ * without `jose` installed can still implement field-mode providers.
15
+ */
16
+ type KeyMaterial = unknown;
17
+ /** A key paired with its identifier — what encrypt operations consume. */
18
+ interface ActiveKey {
19
+ /** Key id, stamped into the JWE `kid` header / field envelope for rotation. */
20
+ readonly kid: string;
21
+ /** The key material (public key for JWE, 32-byte secret for fields). */
22
+ readonly key: KeyMaterial;
23
+ /** Optional per-key `alg` override (else the plugin default applies). */
24
+ readonly alg?: JweAlg;
25
+ }
26
+ /** Context handed to the key provider so resolution can be request-scoped. */
27
+ interface KeyContext {
28
+ readonly request: FastifyRequest;
29
+ }
30
+ type MaybePromise<T> = T | Promise<T>;
31
+ /**
32
+ * Pluggable key resolution. Arc owns the request-time plumbing — `kid` →
33
+ * key, algorithm allowlist enforcement; the host owns the trust store —
34
+ * which keys are valid and where they live (file / env / AWS KMS / GCP KMS
35
+ * / Vault). Encryption and decryption are deliberately separate operations
36
+ * because they often use DIFFERENT keys (JWE: a public key encrypts the
37
+ * outbound response, a private key by `kid` decrypts the inbound request —
38
+ * exactly Visa's two-key-pair model).
39
+ *
40
+ * Rotation mirrors `@fastify/secure-session`: the active key encrypts; any
41
+ * key resolvable by `kid` can decrypt, so you can roll keys without dropping
42
+ * in-flight traffic.
43
+ */
44
+ interface KeyProvider {
45
+ /** Active key for encrypting OUTBOUND responses. */
46
+ encryptionKey(ctx: KeyContext): MaybePromise<ActiveKey>;
47
+ /** Resolve a DECRYPTION key by the inbound message's `kid`. */
48
+ decryptionKey(kid: string, ctx: KeyContext): MaybePromise<KeyMaterial | undefined>;
49
+ }
50
+ /**
51
+ * Per-resource encryption directive — the typed slice plugins register on
52
+ * `ResourceExtensions`. Declared on a resource via
53
+ * `defineResource({ extensions: { encryption: { … } } })`; arc threads it
54
+ * to request time on `request.routeOptions.config.arcExtensions.encryption`.
55
+ */
56
+ interface EncryptionDirective {
57
+ /** Strategy. Defaults to the plugin-level `mode` (default `'jwe'`). */
58
+ readonly mode?: EncryptionMode;
59
+ /**
60
+ * For `mode: 'fields'` — dot-paths of fields to encrypt, resolved against
61
+ * the serialized response body (e.g. `'cardNumber'`, `'account.iban'`).
62
+ * Ignored for `mode: 'jwe'` (the whole body is encrypted).
63
+ */
64
+ readonly fields?: readonly string[];
65
+ /**
66
+ * Explicit opt-out — set `false` to disable encryption for this resource
67
+ * even when a plugin-level default (`routes`) would otherwise apply.
68
+ */
69
+ readonly enabled?: boolean;
70
+ }
71
+ /**
72
+ * Plugin-level options. `keyProvider` is the only required field; everything
73
+ * else has a secure default.
74
+ */
75
+ interface EncryptionOptions {
76
+ /**
77
+ * Master on/off. Default `true`. Set `false` to register the plugin as a
78
+ * typed no-op (config-gated environments) — same pattern as
79
+ * `idempotencyPlugin`.
80
+ */
81
+ readonly enabled?: boolean;
82
+ /** Key provider — resolves `kid` → key for encrypt/decrypt. Required. */
83
+ readonly keyProvider: KeyProvider;
84
+ /** Default mode when a route opts in without naming one. Default `'jwe'`. */
85
+ readonly mode?: EncryptionMode;
86
+ /** JWE key-management algorithm. Default `'RSA-OAEP-256'`. */
87
+ readonly alg?: JweAlg;
88
+ /** JWE content-encryption algorithm. Default `'A256GCM'`. */
89
+ readonly enc?: JweEnc;
90
+ /**
91
+ * Inbound-decryption algorithm allowlists — block algorithm-substitution
92
+ * downgrade attacks. Default `[alg]` / `[enc]`. Set explicitly only when a
93
+ * client legitimately uses more than one algorithm.
94
+ */
95
+ readonly allowedAlgs?: readonly JweAlg[];
96
+ readonly allowedEncs?: readonly JweEnc[];
97
+ /**
98
+ * Fallback opt-in for routes that don't declare
99
+ * `extensions.encryption`. Return a directive (or `true` for the default
100
+ * mode) to encrypt, `false`/`undefined` to skip. The per-resource
101
+ * `extensions.encryption` ALWAYS wins when present. Use this to scope ALE
102
+ * to sensitive prefixes without touching every resource.
103
+ *
104
+ * @example confine ALE to `/payments` and `/accounts`
105
+ * ```ts
106
+ * routes: (req) => /^\/(payments|accounts)\b/.test(req.url)
107
+ * ```
108
+ */
109
+ readonly routes?: (request: FastifyRequest) => EncryptionDirective | boolean | undefined;
110
+ /** Decrypt inbound `application/jose` request bodies. Default `true`. */
111
+ readonly decryptRequests?: boolean;
112
+ /** Media type that signals an encrypted REQUEST body. Default `'application/jose'`. */
113
+ readonly contentType?: string;
114
+ /** Content-Type set on full-body JWE RESPONSES. Default `'application/jose'`. */
115
+ readonly responseContentType?: string;
116
+ /**
117
+ * Response header advertising that the body is encrypted, so generic
118
+ * client SDKs know to decrypt. Default `'x-encrypted'`; set `false` to omit.
119
+ */
120
+ readonly flagHeader?: string | false;
121
+ }
122
+ /** Request decorations added by the plugin. */
123
+ declare module "fastify" {
124
+ interface FastifyRequest {
125
+ /** `true` when the inbound body was decrypted from a JWE by this plugin. */
126
+ requestDecrypted?: boolean;
127
+ /** `true` when the outbound body was encrypted by this plugin. */
128
+ responseEncrypted?: boolean;
129
+ }
130
+ }
131
+ //#endregion
132
+ export { JweAlg as a, KeyMaterial as c, EncryptionOptions as i, KeyProvider as l, EncryptionDirective as n, JweEnc as o, EncryptionMode as r, KeyContext as s, ActiveKey as t };
@@ -1,6 +1,5 @@
1
- import { i as RequestScope } from "./types-LNebCoJx.mjs";
1
+ import { i as RequestScope } from "./types-DH0GupI7.mjs";
2
2
  import { FastifyRequest } from "fastify";
3
-
4
3
  //#region src/permissions/types.d.ts
5
4
  /**
6
5
  * User base interface - minimal shape Arc expects
@@ -196,124 +195,4 @@ interface PermissionCheckMeta {
196
195
  };
197
196
  }
198
197
  //#endregion
199
- //#region src/permissions/fields.d.ts
200
- /**
201
- * Field-Level Permissions
202
- *
203
- * Control field visibility and writability per role.
204
- * Integrated into the response path (read) and sanitization path (write).
205
- *
206
- * @example
207
- * ```typescript
208
- * import { fields, defineResource } from '@classytic/arc';
209
- *
210
- * const userResource = defineResource({
211
- * name: 'user',
212
- * adapter: userAdapter,
213
- * fields: {
214
- * salary: fields.visibleTo(['admin', 'hr']),
215
- * internalNotes: fields.writableBy(['admin']),
216
- * email: fields.redactFor(['viewer']),
217
- * password: fields.hidden(),
218
- * },
219
- * });
220
- * ```
221
- */
222
- type FieldPermissionType = "hidden" | "visibleTo" | "writableBy" | "redactFor";
223
- interface FieldPermission {
224
- readonly _type: FieldPermissionType;
225
- readonly roles?: readonly string[];
226
- readonly redactValue?: unknown;
227
- }
228
- type FieldPermissionMap = Record<string, FieldPermission>;
229
- declare const fields: {
230
- /**
231
- * Field is never included in responses. Not writable via API.
232
- *
233
- * @example
234
- * ```typescript
235
- * fields: { password: fields.hidden() }
236
- * ```
237
- */
238
- hidden(): FieldPermission;
239
- /**
240
- * Field is only visible to users with specified roles.
241
- * Other users don't see the field at all.
242
- *
243
- * @example
244
- * ```typescript
245
- * fields: { salary: fields.visibleTo(['admin', 'hr']) }
246
- * ```
247
- */
248
- visibleTo(roles: readonly string[]): FieldPermission;
249
- /**
250
- * Field is only writable by users with specified roles.
251
- * All users can still read the field. Users without the role
252
- * have the field silently stripped from write operations.
253
- *
254
- * @example
255
- * ```typescript
256
- * fields: { role: fields.writableBy(['admin']) }
257
- * ```
258
- */
259
- writableBy(roles: readonly string[]): FieldPermission;
260
- /**
261
- * Field is redacted (replaced with a placeholder) for specified roles.
262
- * Other users see the real value.
263
- *
264
- * @param roles - Roles that see the redacted value
265
- * @param redactValue - Replacement value (default: '***')
266
- *
267
- * @example
268
- * ```typescript
269
- * fields: {
270
- * email: fields.redactFor(['viewer']),
271
- * ssn: fields.redactFor(['basic'], '***-**-****'),
272
- * }
273
- * ```
274
- */
275
- redactFor(roles: readonly string[], redactValue?: unknown): FieldPermission;
276
- };
277
- /**
278
- * Apply field-level READ permissions to a response object.
279
- * Strips hidden fields, enforces visibility, and applies redaction.
280
- *
281
- * @param data - The response object (mutated in place for performance)
282
- * @param fieldPermissions - Field permission map from resource config
283
- * @param userRoles - Current user's roles (empty array for unauthenticated)
284
- * @returns The filtered object
285
- */
286
- declare function applyFieldReadPermissions<T extends Record<string, unknown>>(data: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): T;
287
- /**
288
- * Result of applying write permissions — includes both the filtered body
289
- * and the list of fields that were stripped so callers can decide whether
290
- * to reject the request (secure default) or silently strip (legacy).
291
- */
292
- interface FieldWritePermissionResult<T extends Record<string, unknown>> {
293
- readonly body: T;
294
- readonly deniedFields: readonly string[];
295
- }
296
- /**
297
- * Apply field-level WRITE permissions to request body.
298
- *
299
- * Returns both the filtered body and the list of denied fields. Callers are
300
- * expected to reject the request when `deniedFields.length > 0` — silently
301
- * stripping fields hides misconfigurations and real attacks. See
302
- * `BodySanitizer` for the default policy.
303
- *
304
- * @param body - The request body (returns a new filtered copy)
305
- * @param fieldPermissions - Field permission map from resource config
306
- * @param userRoles - Current user's roles
307
- */
308
- declare function applyFieldWritePermissions<T extends Record<string, unknown>>(body: T, fieldPermissions: FieldPermissionMap, userRoles: readonly string[]): FieldWritePermissionResult<T>;
309
- /**
310
- * Resolve effective roles by merging global user roles with org-level roles.
311
- *
312
- * Global roles come from `req.user.role` (normalized via getUserRoles()).
313
- * Org roles come from `req.context.orgRoles` (set by BA adapter's org bridge).
314
- *
315
- * When no org context exists, returns global roles only — backward compatible.
316
- */
317
- declare function resolveEffectiveRoles(userRoles: readonly string[], orgRoles: readonly string[]): string[];
318
- //#endregion
319
- export { applyFieldWritePermissions as a, PermissionCheck as c, UserBase as d, getUserRoles as f, applyFieldReadPermissions as i, PermissionContext as l, FieldPermissionMap as n, fields as o, normalizeRoles as p, FieldPermissionType as r, resolveEffectiveRoles as s, FieldPermission as t, PermissionResult as u };
198
+ export { getUserRoles as a, UserBase as i, PermissionContext as n, normalizeRoles as o, PermissionResult as r, PermissionCheck as t };
@@ -168,8 +168,10 @@ type RequestScope = {
168
168
  kind: "service";
169
169
  clientId: string;
170
170
  organizationId: string;
171
- scopes?: readonly string[]; /** App-defined scope dimensions — see `member.context` for details. */
172
- context?: Readonly<Record<string, string>>; /** Parent organizations — see `member.ancestorOrgIds` for details. */
171
+ scopes?: readonly string[];
172
+ /** App-defined scope dimensions — see `member.context` for details. */
173
+ context?: Readonly<Record<string, string>>;
174
+ /** Parent organizations — see `member.ancestorOrgIds` for details. */
173
175
  ancestorOrgIds?: readonly string[];
174
176
  /**
175
177
  * Capability mandate — narrows what the caller may do beyond OAuth `scopes`.
@@ -207,8 +209,10 @@ type RequestScope = {
207
209
  kind: "elevated";
208
210
  userId?: string;
209
211
  organizationId?: string;
210
- elevatedBy: string; /** App-defined scope dimensions — see `member.context` for details. */
211
- context?: Readonly<Record<string, string>>; /** Parent organizations — see `member.ancestorOrgIds` for details. */
212
+ elevatedBy: string;
213
+ /** App-defined scope dimensions — see `member.context` for details. */
214
+ context?: Readonly<Record<string, string>>;
215
+ /** Parent organizations — see `member.ancestorOrgIds` for details. */
212
216
  ancestorOrgIds?: readonly string[];
213
217
  };
214
218
  /** Check if scope is `member` kind */