@classytic/arc 2.28.0 → 2.30.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 (83) hide show
  1. package/dist/{BaseController-B65zbz9m.mjs → BaseController-B5DwufbB.mjs} +12 -10
  2. package/dist/EventTransport-C6YA8xY9.mjs +103 -0
  3. package/dist/{HookSystem-C1vB_Gc9.mjs → HookSystem-WkIougo6.mjs} +15 -35
  4. package/dist/applyPermissionResult-Cf6zUCvb.mjs +257 -0
  5. package/dist/audit/index.d.mts +2 -2
  6. package/dist/audit/index.mjs +1 -1
  7. package/dist/auth/index.d.mts +2 -2
  8. package/dist/auth/index.mjs +1 -1
  9. package/dist/{buildHandler-Dtwd8fdz.mjs → buildHandler-BYS3Vkfz.mjs} +32 -6
  10. package/dist/cleanup/index.d.mts +2 -2
  11. package/dist/cleanup/index.mjs +1 -1
  12. package/dist/cli/commands/describe.d.mts +1 -1
  13. package/dist/cli/commands/docs.mjs +1 -1
  14. package/dist/core/index.d.mts +2 -2
  15. package/dist/core/index.mjs +5 -4
  16. package/dist/{core-BGa8TXJR.mjs → core-poalJLvp.mjs} +2 -48
  17. package/dist/{createActionRouter-C-N7z2EL.mjs → createActionRouter-BxuywVRB.mjs} +2 -2
  18. package/dist/{createAggregationRouter-wzwFa_dW.mjs → createAggregationRouter-BiY-lGdY.mjs} +7 -20
  19. package/dist/{createApp-Du5G54TM.mjs → createApp-CXrKFciH.mjs} +24 -3
  20. package/dist/defineAggregation-ufWjUwml.mjs +47 -0
  21. package/dist/{defineResource-2zvVVpxg.mjs → defineResource-CxWqDCAy.mjs} +35 -42
  22. package/dist/docs/index.d.mts +1 -1
  23. package/dist/docs/index.mjs +1 -1
  24. package/dist/{eventPlugin-DrQ_FesK.mjs → eventPlugin-D2NNR4py.mjs} +2 -103
  25. package/dist/events/index.mjs +4 -339
  26. package/dist/factory/index.d.mts +4 -4
  27. package/dist/factory/index.mjs +1 -1
  28. package/dist/{fastify-augmentation-OzYGIiU1.d.mts → fastify-augmentation-0WhPnUH7.d.mts} +3 -3
  29. package/dist/{applyPermissionResult-BnyVE9eD.mjs → fields-CQ_7KQWw.mjs} +1 -107
  30. package/dist/hooks/index.d.mts +1 -1
  31. package/dist/hooks/index.mjs +1 -1
  32. package/dist/idempotency/index.mjs +1 -1
  33. package/dist/{index-CZY4EGga.d.mts → index-CCzVR-N3.d.mts} +1 -1
  34. package/dist/{index-BMnbzvtO.d.mts → index-Ch16aAah.d.mts} +201 -21
  35. package/dist/{index-CjVg-Epg.d.mts → index-Cx7bro4R.d.mts} +4 -4
  36. package/dist/{index-DPRH0Cme.d.mts → index-Q5gzEIWY.d.mts} +97 -66
  37. package/dist/index.d.mts +6 -6
  38. package/dist/index.mjs +8 -7
  39. package/dist/integrations/index.d.mts +1 -1
  40. package/dist/integrations/mcp/index.d.mts +6 -6
  41. package/dist/integrations/mcp/index.mjs +1 -1
  42. package/dist/integrations/mcp/testing.d.mts +1 -1
  43. package/dist/integrations/mcp/testing.mjs +1 -1
  44. package/dist/{mcpPlugin-Cs6nRGCt.mjs → mcpPlugin-nRzm5g2s.mjs} +36 -43
  45. package/dist/middleware/index.d.mts +1 -1
  46. package/dist/migrations/index.d.mts +0 -3
  47. package/dist/migrations/index.mjs +0 -3
  48. package/dist/{openapi-BLV4OMXb.mjs → openapi-B8Vkbxbn.mjs} +1 -1
  49. package/dist/permissions/index.d.mts +3 -3
  50. package/dist/permissions/index.mjs +4 -3
  51. package/dist/{permissions-BrtiBKGs.mjs → permissions-Bfu_8y1U.mjs} +318 -289
  52. package/dist/pipeline/index.d.mts +1 -1
  53. package/dist/{pipeline-BGRnV-To.mjs → pipeline-BJnpkY9i.mjs} +4 -18
  54. package/dist/plugins/index.d.mts +4 -4
  55. package/dist/plugins/index.mjs +2 -2
  56. package/dist/plugins/tracing-entry.mjs +1 -1
  57. package/dist/{preloadResources-CM4uUaFv.d.mts → preloadResources-DCfa2egz.d.mts} +3 -3
  58. package/dist/presets/filesUpload.d.mts +2 -2
  59. package/dist/presets/filesUpload.mjs +1 -1
  60. package/dist/presets/index.d.mts +14 -2
  61. package/dist/presets/index.mjs +1 -1
  62. package/dist/presets/multiTenant.d.mts +1 -1
  63. package/dist/presets/search.d.mts +2 -2
  64. package/dist/presets/search.mjs +1 -1
  65. package/dist/{presets-DwFDVKP0.mjs → presets-CJOEXLuk.mjs} +25 -9
  66. package/dist/projection-UBDgfMwu.mjs +17 -0
  67. package/dist/{realtime-DEuDu9io.mjs → realtime-B9nmIY5V.mjs} +2 -1
  68. package/dist/{registerRoute-DTp18Ah_.mjs → registerRoute-JkxIEBJq.mjs} +3 -1
  69. package/dist/registry/index.d.mts +2 -2
  70. package/dist/registry/index.mjs +1 -1
  71. package/dist/{registry-9km_w1aP.mjs → registry-BYXUUg21.mjs} +1 -1
  72. package/dist/repositoryFilter-Dz8k3S4P.mjs +44 -0
  73. package/dist/subscribe-helpers-DfzsivM6.mjs +339 -0
  74. package/dist/testing/index.d.mts +34 -6
  75. package/dist/testing/index.mjs +314 -211
  76. package/dist/types/index.d.mts +3 -3
  77. package/dist/{types-QFGc3Cjv.d.mts → types-Bmmn-fO0.d.mts} +1 -1
  78. package/dist/{types-Dmw-6Qeo.d.mts → types-ChvvVNP8.d.mts} +93 -88
  79. package/dist/{types-Cu6vVJmh.d.mts → types-D_n8L6VY.d.mts} +32 -1
  80. package/dist/usage/index.d.mts +1 -1
  81. package/dist/usage/index.mjs +0 -0
  82. package/dist/utils/index.d.mts +2 -5
  83. package/package.json +539 -539
@@ -0,0 +1,339 @@
1
+ import { n as createEvent } from "./EventTransport-C6YA8xY9.mjs";
2
+ //#region src/events/defineEvent.ts
3
+ /**
4
+ * defineEvent — Typed Event Definitions with Optional Schema Validation
5
+ *
6
+ * Provides:
7
+ * 1. defineEvent() — declare an event with name, schema, version, description
8
+ * 2. EventRegistry — catalog of all known events + payload validation
9
+ * 3. .create() helper — build DomainEvent with auto-generated metadata
10
+ *
11
+ * The built-in validator checks: object type, required fields, and top-level
12
+ * property types. It does NOT recurse into nested objects, validate arrays,
13
+ * enums, patterns, formats, or $ref. This is intentional — it's a lightweight
14
+ * guard, not a full JSON Schema engine.
15
+ *
16
+ * For full validation, pass a custom `validate` function to `createEventRegistry()`:
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import Ajv from 'ajv';
21
+ * const ajv = new Ajv();
22
+ *
23
+ * const registry = createEventRegistry({
24
+ * validate: (schema, payload) => {
25
+ * const valid = ajv.validate(schema, payload);
26
+ * return valid
27
+ * ? { valid: true }
28
+ * : { valid: false, errors: ajv.errorsText().split(', ') };
29
+ * },
30
+ * });
31
+ * ```
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { defineEvent, createEventRegistry } from '@classytic/arc/events';
36
+ *
37
+ * const OrderCreated = defineEvent({
38
+ * name: 'order.created',
39
+ * version: 1,
40
+ * schema: {
41
+ * type: 'object',
42
+ * properties: {
43
+ * orderId: { type: 'string' },
44
+ * total: { type: 'number' },
45
+ * },
46
+ * required: ['orderId', 'total'],
47
+ * },
48
+ * });
49
+ *
50
+ * // Type-safe event creation
51
+ * const event = OrderCreated.create({ orderId: 'o-1', total: 100 });
52
+ * await fastify.events.publish(event.type, event.payload, event.meta);
53
+ *
54
+ * // Registry for introspection + validation
55
+ * const registry = createEventRegistry();
56
+ * registry.register(OrderCreated);
57
+ * const result = registry.validate('order.created', payload);
58
+ * ```
59
+ */
60
+ /**
61
+ * Define a typed event with optional schema validation.
62
+ *
63
+ * @example
64
+ * const OrderCreated = defineEvent({
65
+ * name: 'order.created',
66
+ * schema: { type: 'object', properties: { orderId: { type: 'string' } }, required: ['orderId'] },
67
+ * });
68
+ *
69
+ * const event = OrderCreated.create({ orderId: '123' });
70
+ */
71
+ function defineEvent(input) {
72
+ const { name, schema, version = 1, description } = input;
73
+ return {
74
+ name,
75
+ schema,
76
+ version,
77
+ description,
78
+ create(payload, meta) {
79
+ return createEvent(name, payload, {
80
+ schemaVersion: version,
81
+ ...meta
82
+ });
83
+ }
84
+ };
85
+ }
86
+ /**
87
+ * Create an event registry for cataloging and validating events.
88
+ *
89
+ * The registry is opt-in — unregistered events pass validation.
90
+ * This allows gradual adoption without breaking existing code.
91
+ *
92
+ * @param options.validate - Custom validator replacing the built-in minimal validator.
93
+ * The built-in validator only checks top-level object structure (type, required, property types).
94
+ * For nested objects, arrays, enums, patterns, or $ref, provide AJV or similar.
95
+ */
96
+ function createEventRegistry(options) {
97
+ const customValidator = options?.validate;
98
+ const definitions = /* @__PURE__ */ new Map();
99
+ function registryKey(name, version) {
100
+ return `${name}:v${version}`;
101
+ }
102
+ return {
103
+ register(definition) {
104
+ const key = registryKey(definition.name, definition.version);
105
+ if (definitions.has(key)) throw new Error(`Event '${definition.name}' v${definition.version} is already registered. Use a different version number for schema evolution.`);
106
+ definitions.set(key, definition);
107
+ },
108
+ get(name, version) {
109
+ if (version !== void 0) return definitions.get(registryKey(name, version));
110
+ let latest;
111
+ let latestVersion = -1;
112
+ for (const def of definitions.values()) if (def.name === name && def.version > latestVersion) {
113
+ latest = def;
114
+ latestVersion = def.version;
115
+ }
116
+ return latest;
117
+ },
118
+ catalog() {
119
+ return Array.from(definitions.values()).map((def) => ({
120
+ name: def.name,
121
+ version: def.version,
122
+ description: def.description,
123
+ schema: def.schema
124
+ }));
125
+ },
126
+ validate(name, payload, version) {
127
+ let target = version !== void 0 ? definitions.get(registryKey(name, version)) : void 0;
128
+ if (!target && version === void 0) {
129
+ let latestVersion = -1;
130
+ for (const candidate of definitions.values()) if (candidate.name === name && candidate.version > latestVersion) {
131
+ target = candidate;
132
+ latestVersion = candidate.version;
133
+ }
134
+ }
135
+ if (!target) return { valid: true };
136
+ if (!target.schema) return { valid: true };
137
+ return customValidator ? customValidator(target.schema, payload) : validatePayload(payload, target.schema);
138
+ }
139
+ };
140
+ }
141
+ /**
142
+ * Built-in minimal validator — lightweight guard, NOT a full JSON Schema engine.
143
+ *
144
+ * Checks:
145
+ * - payload is an object (not null, not array)
146
+ * - required fields are present
147
+ * - top-level property types match (string, number, boolean, array, object)
148
+ *
149
+ * Does NOT check:
150
+ * - nested object properties
151
+ * - array item types
152
+ * - enum, pattern, format, minLength, minimum, $ref
153
+ *
154
+ * For full validation, pass a custom `validate` function to `createEventRegistry()`.
155
+ */
156
+ function validatePayload(payload, schema) {
157
+ const errors = [];
158
+ if (schema.type === "object") {
159
+ if (payload === null || payload === void 0 || typeof payload !== "object" || Array.isArray(payload)) return {
160
+ valid: false,
161
+ errors: ["Payload must be an object"]
162
+ };
163
+ const record = payload;
164
+ if (schema.required) {
165
+ for (const field of schema.required) if (!(field in record) || record[field] === void 0) errors.push(`Missing required field: '${field}'`);
166
+ }
167
+ if (schema.properties) {
168
+ for (const [key, propSchema] of Object.entries(schema.properties)) if (key in record && record[key] !== void 0 && record[key] !== null) {
169
+ const expectedType = propSchema.type;
170
+ if (expectedType) {
171
+ const value = record[key];
172
+ const actualType = Array.isArray(value) ? "array" : typeof value;
173
+ if (expectedType === "integer") {
174
+ if (actualType !== "number" || !Number.isInteger(value)) errors.push(`Field '${key}': expected integer, got ${actualType}`);
175
+ } else if (expectedType !== actualType) errors.push(`Field '${key}': expected ${expectedType}, got ${actualType}`);
176
+ }
177
+ }
178
+ }
179
+ }
180
+ return errors.length === 0 ? { valid: true } : {
181
+ valid: false,
182
+ errors
183
+ };
184
+ }
185
+ //#endregion
186
+ //#region src/events/subscribe-helpers.ts
187
+ /**
188
+ * Subscribe-side helpers — close the symmetry that arc's publish-side
189
+ * already has via [`eventPlugin({ registry, validateMode: 'reject' })`](./eventPlugin.ts).
190
+ *
191
+ * Two wrapper pairs, both transport-agnostic:
192
+ *
193
+ * - `wrapWithSchema` / `subscribeWithSchema` — read the schema from a
194
+ * typed `EventDefinitionOutput<T>` and validate `event.payload` before
195
+ * the handler runs. Single source of truth for event shape: declare
196
+ * once at `defineEvent`, enforced on BOTH sides without parallel Zod
197
+ * schemas in subscriber files.
198
+ *
199
+ * - `wrapWithBoundary` / `subscribeWithBoundary` — catch + log + swallow
200
+ * handler errors, for projection / cache-invalidation / fire-and-forget
201
+ * handlers where retry would just delay the next-event resync. Lighter
202
+ * than `withRetry` (no DLQ, no exponential backoff) and avoids the
203
+ * "single bad event poisons the bus" hazard.
204
+ *
205
+ * Both pairs compose with `withRetry` and with each other:
206
+ *
207
+ * ```ts
208
+ * await subscribeWithSchema(
209
+ * fastify,
210
+ * OrderPaid,
211
+ * withRetry(handler, { maxRetries: 3 }),
212
+ * );
213
+ * ```
214
+ *
215
+ * @see [retry.ts](./retry.ts) for the retry + DLQ wrapper.
216
+ * @see [defineEvent.ts](./defineEvent.ts) for `defineEvent` / `EventDefinitionOutput`.
217
+ */
218
+ /**
219
+ * Pure handler wrapper — returns a new `EventHandler` that validates
220
+ * `event.payload` against the definition's schema before invoking the handler.
221
+ *
222
+ * The returned handler's input is `DomainEvent<unknown>` (since the transport
223
+ * delivers untyped events) but the inner `handler` receives `DomainEvent<T>`.
224
+ * No cast at the call site.
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * await fastify.events.subscribe(
229
+ * OrderPaid.name,
230
+ * wrapWithSchema(OrderPaid, async (event) => {
231
+ * // event.payload is typed via the registered schema — no cast.
232
+ * await postSalesEntry(event.payload.orderId, event.payload.total);
233
+ * }),
234
+ * );
235
+ * ```
236
+ */
237
+ function wrapWithSchema(definition, handler, options = {}) {
238
+ const { validate, registry, onInvalid, logger = console, name } = options;
239
+ const label = name ?? definition.name;
240
+ return async (event) => {
241
+ const eventVersion = typeof event.meta?.schemaVersion === "number" ? event.meta.schemaVersion : definition.version;
242
+ let result;
243
+ if (validate && definition.schema) result = validate(definition.schema, event.payload);
244
+ else if (registry) result = registry.validate(definition.name, event.payload, eventVersion);
245
+ else if (definition.schema) {
246
+ const adhoc = createEventRegistry();
247
+ adhoc.register(definition);
248
+ result = adhoc.validate(definition.name, event.payload);
249
+ } else result = { valid: true };
250
+ if (!result.valid) {
251
+ const errors = result.errors ?? ["payload failed validation"];
252
+ if (onInvalid) try {
253
+ await onInvalid(event, errors);
254
+ } catch (cbErr) {
255
+ logger.error(`[Arc Events] '${label}' onInvalid callback threw:`, cbErr);
256
+ }
257
+ else logger.warn(`[Arc Events] '${label}' skipped event ${event.meta?.id ?? "<no-id>"} — payload failed validation: ${errors.join("; ")}`);
258
+ return;
259
+ }
260
+ await handler(event);
261
+ };
262
+ }
263
+ /**
264
+ * Convenience: validate + subscribe in one call. Equivalent to
265
+ * `fastify.events.subscribe(definition.name, wrapWithSchema(definition, handler, options))`.
266
+ *
267
+ * Returns the unsubscribe function from the underlying transport.
268
+ *
269
+ * @example
270
+ * ```ts
271
+ * await subscribeWithSchema(fastify, OrderPaid, async (event) => {
272
+ * await postSalesEntry(event.payload.orderId, event.payload.total);
273
+ * });
274
+ *
275
+ * // Compose with withRetry — schema validation runs FIRST, then retry on
276
+ * // handler failure. Invalid payloads skip without burning retry attempts.
277
+ * await subscribeWithSchema(
278
+ * fastify,
279
+ * OrderPaid,
280
+ * withRetry(handler, { maxRetries: 3 }),
281
+ * );
282
+ * ```
283
+ */
284
+ async function subscribeWithSchema(fastify, definition, handler, options) {
285
+ return fastify.events.subscribe(definition.name, wrapWithSchema(definition, handler, options));
286
+ }
287
+ /**
288
+ * Pure handler wrapper — returns a new `EventHandler` that catches handler
289
+ * exceptions and routes them to `onError` (or logs and swallows). For
290
+ * projection / cache-invalidation / fire-and-forget handlers where retry
291
+ * would just delay the next-event resync, and where one bad event must NOT
292
+ * stop processing of subsequent events.
293
+ *
294
+ * Lighter than `withRetry`: no exponential backoff, no DLQ. Composes with
295
+ * `withRetry` if you want both ("retry, then log if exhausted, never throw").
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * await fastify.events.subscribe(
300
+ * 'product:variants.changed',
301
+ * wrapWithBoundary(async (event) => {
302
+ * cache.invalidate(event.payload.productId);
303
+ * }),
304
+ * );
305
+ * ```
306
+ */
307
+ function wrapWithBoundary(handler, options = {}) {
308
+ const { onError, logger = console, name } = options;
309
+ const label = name ?? handler.name ?? "anonymous";
310
+ return async (event) => {
311
+ try {
312
+ await handler(event);
313
+ } catch (err) {
314
+ const error = err instanceof Error ? err : new Error(String(err));
315
+ if (onError) try {
316
+ await onError(error, event);
317
+ } catch (cbErr) {
318
+ logger.error(`[Arc Events] '${label}' onError callback threw:`, cbErr);
319
+ }
320
+ else logger.error(`[Arc Events] '${label}' threw on ${event.type} — swallowed (boundary): ${error.message}`, {
321
+ err: error,
322
+ event: event.type,
323
+ eventId: event.meta?.id,
324
+ handler: label
325
+ });
326
+ }
327
+ };
328
+ }
329
+ /**
330
+ * Convenience: subscribe + error-boundary in one call. Equivalent to
331
+ * `fastify.events.subscribe(pattern, wrapWithBoundary(handler, options))`.
332
+ *
333
+ * Returns the unsubscribe function from the underlying transport.
334
+ */
335
+ async function subscribeWithBoundary(fastify, pattern, handler, options) {
336
+ return fastify.events.subscribe(pattern, wrapWithBoundary(handler, options));
337
+ }
338
+ //#endregion
339
+ export { createEventRegistry as a, wrapWithSchema as i, subscribeWithSchema as n, defineEvent as o, wrapWithBoundary as r, subscribeWithBoundary as t };
@@ -1,8 +1,8 @@
1
- import { V as ResourceDefinition } from "../index-DPRH0Cme.mjs";
2
- import { c as AnyRecord } from "../types-Dmw-6Qeo.mjs";
3
- import { n as ArcModuleInput } from "../types-Cu6vVJmh.mjs";
4
- import "../index-CZY4EGga.mjs";
5
- import { n as preloadResourcesAsync, r as CreateAppOptions, t as preloadResources } from "../preloadResources-CM4uUaFv.mjs";
1
+ import { V as ResourceDefinition } from "../index-Q5gzEIWY.mjs";
2
+ import { l as AnyRecord, r as PermissionCheck } from "../types-ChvvVNP8.mjs";
3
+ import { n as ArcModuleInput } from "../types-D_n8L6VY.mjs";
4
+ import "../index-CCzVR-N3.mjs";
5
+ import { n as preloadResourcesAsync, r as CreateAppOptions, t as preloadResources } from "../preloadResources-DCfa2egz.mjs";
6
6
  import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
7
7
  import { FastifyInstance, FastifyServerOptions } from "fastify";
8
8
  import { Mock } from "vitest";
@@ -72,6 +72,34 @@ interface ArcAssertion {
72
72
  }
73
73
  declare function expectArc(response: ArcResponseLike): ArcAssertion;
74
74
  //#endregion
75
+ //#region src/testing/authorizationConformance.d.ts
76
+ /** One surface's observed enforcement: the HTTP status + the filter arc passed the repo. */
77
+ interface SurfaceObservation {
78
+ /** HTTP status the surface returned (200 = allowed, 401/403 = denied). */
79
+ status: number;
80
+ /** The filter arc handed the repository for this surface (undefined if never reached). */
81
+ filter: AnyRecord | undefined;
82
+ }
83
+ /** Result of {@link runAuthorizationConformance} — one observation per surface. */
84
+ interface AuthorizationConformance {
85
+ /** `GET /confs` — the CRUD list surface. */
86
+ list: SurfaceObservation;
87
+ /** `GET /confs/aggregations/tally` — the aggregation surface. */
88
+ aggregation: SurfaceObservation;
89
+ /** Close the throwaway app. Always call (e.g. in `finally`). */
90
+ close(): Promise<void>;
91
+ }
92
+ /**
93
+ * Boot a one-resource app gated by `permission` on both list + an aggregation,
94
+ * hit both surfaces anonymously, and report what arc enforced on each.
95
+ */
96
+ declare function runAuthorizationConformance(opts: {
97
+ /** The permission under test — applied to `list` and the aggregation alike. */
98
+ permission: PermissionCheck;
99
+ /** Rows the mock repo returns for list (aggregation returns a count). */
100
+ rows?: AnyRecord[];
101
+ }): Promise<AuthorizationConformance>;
102
+ //#endregion
75
103
  //#region src/testing/authSession.d.ts
76
104
  /**
77
105
  * A concrete auth session — headers ready to drop into `app.inject`.
@@ -622,4 +650,4 @@ declare function createTestApp(options?: CreateTestAppOptions): Promise<TestAppC
622
650
  */
623
651
  declare function createMinimalTestApp(options?: FastifyServerOptions): FastifyInstance;
624
652
  //#endregion
625
- 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 };
653
+ export { type ArcAssertion, type ArcResponseLike, type AuthMode, type AuthResponse, type AuthorizationConformance, 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 SurfaceObservation, 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, runAuthorizationConformance, runStorageContract, safeParseBody, setupBetterAuthTestApp, waitFor };