@classytic/arc 2.31.0 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BaseController-De7GqHck.mjs → BaseController-Dk34dxhI.mjs} +16 -13
- package/dist/{EventTransport-9mlTgqzE.mjs → EventTransport-BV10D0oG.mjs} +1 -1
- package/dist/{HookSystem-BcmPyq5I.mjs → HookSystem-vimw5D7Z.mjs} +2 -2
- package/dist/{ResourceRegistry-qq0mn2s9.mjs → ResourceRegistry-BVr7PgA0.mjs} +17 -15
- package/dist/{actionPermissions-BE5NwaQk.mjs → actionPermissions-Dti7ebyv.mjs} +1 -1
- package/dist/audit/index.mjs +2 -2
- package/dist/auth/audit.mjs +1 -1
- package/dist/auth/index.mjs +11 -10
- package/dist/auth/redis-session.mjs +1 -1
- package/dist/{authorizationDecision-ChvUQGG1.mjs → authorizationDecision-__T3EJDA.mjs} +2 -2
- package/dist/{buildHandler-CDrCJzmB.mjs → buildHandler-Dn7rzUJo.mjs} +6 -5
- package/dist/cache/index.mjs +4 -4
- package/dist/{caching-BFHA6Scf.mjs → caching-DFJqHyFs.mjs} +2 -2
- package/dist/cleanup/index.d.mts +36 -14
- package/dist/cleanup/index.mjs +45 -29
- package/dist/cli/commands/describe.mjs +4 -6
- package/dist/cli/commands/docs.mjs +3 -3
- package/dist/cli/commands/doctor.mjs +1 -1
- package/dist/cli/commands/generate.mjs +2 -2
- package/dist/cli/commands/init.mjs +2 -2
- package/dist/cli/commands/introspect.mjs +2 -2
- package/dist/cli/index.mjs +3 -3
- package/dist/{constants-D3Dv4LAV.mjs → constants-J99LGTJI.mjs} +1 -1
- package/dist/context/index.mjs +3 -3
- package/dist/core/index.d.mts +1 -1
- package/dist/core/index.mjs +7 -7
- package/dist/{core-BGpIxINN.mjs → core-BwwmNSp7.mjs} +3 -3
- package/dist/{createActionRouter-CDXEdasl.mjs → createActionRouter-DkJZWo0m.mjs} +14 -11
- package/dist/{createAggregationRouter-KrQDzx-k.mjs → createAggregationRouter-B1exOVD8.mjs} +10 -8
- package/dist/{createApp-Df89BEni.mjs → createApp-Bv0m-Q6_.mjs} +182 -61
- package/dist/{defineAggregation-DbPPS8RI.mjs → defineAggregation-gX4No1gt.mjs} +1 -1
- package/dist/{defineResource-Bv6EtN1x.mjs → defineResource-XFPPUu2c.mjs} +41 -32
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.mjs +3 -3
- package/dist/{elevation-D2l1mh4g.mjs → elevation-DNXXxgjl.mjs} +4 -4
- package/dist/encryption/index.mjs +5 -4
- package/dist/{errorHandler-C5NeD6bT.mjs → errorHandler-B2AZUJUj.mjs} +3 -3
- package/dist/{errors-Cj42AntO.mjs → errors-Bh1KK5ps.mjs} +1 -1
- package/dist/{eventPlugin-CkffEihm.mjs → eventPlugin-Dk_TyXeE.mjs} +8 -7
- package/dist/events/index.d.mts +108 -41
- package/dist/events/index.mjs +166 -142
- package/dist/events/transports/redis-stream-entry.mjs +14 -10
- package/dist/events/transports/redis.mjs +1 -1
- package/dist/factory/index.d.mts +5 -5
- package/dist/factory/index.mjs +131 -8
- package/dist/fastify-augmentation-BppG5bMT.d.mts +179 -0
- package/dist/{fields-CB5Cuzk9.mjs → fields-DEi65pGj.mjs} +6 -11
- package/dist/{generate-EcA6ui4i.mjs → generate-CRSG0jTv.mjs} +2 -2
- package/dist/{headers-3zvE0rM3.mjs → headers-BXjQYbeC.mjs} +2 -2
- package/dist/{health-DjZYjM7H.mjs → health-5XnTa2uo.mjs} +1 -1
- package/dist/hooks/index.mjs +2 -2
- package/dist/idempotency/index.mjs +8 -6
- package/dist/idempotency/redis.mjs +1 -1
- package/dist/{index-Bc2ox8_U.d.mts → index-DXlHwvuE.d.mts} +1 -1
- package/dist/{index-CFThn1K9.d.mts → index-ZWhLTp_s.d.mts} +70 -4
- package/dist/{index-CEJNZFtX.d.mts → index-zq6VrjaB.d.mts} +70 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +11 -11
- package/dist/{init-BEiNZBsJ.mjs → init-BbfP8aky.mjs} +7 -5
- package/dist/integrations/event-gateway.mjs +2 -2
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs/index.mjs +3 -3
- package/dist/integrations/mcp/index.mjs +2 -2
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.mjs +3 -3
- package/dist/integrations/webhooks.mjs +1 -1
- package/dist/integrations/websocket-pushref-redis.mjs +1 -1
- package/dist/integrations/websocket-redis.mjs +1 -1
- package/dist/integrations/websocket.mjs +38 -35
- package/dist/{interface-DYzM0q-u.mjs → interface-BP4IJCBO.mjs} +1 -1
- package/dist/{jsonBody-BYbLDi5D.mjs → jsonBody-DDSR2HFl.mjs} +2 -2
- package/dist/{keys-C0_pa1tY.mjs → keys-B-HBTGXl.mjs} +1 -1
- package/dist/{loadResources-yawi9tAE.mjs → loadResources-DisEAmkm.mjs} +4 -3
- package/dist/{loadResourcesFromEntry-BAjYZonx.mjs → loadResourcesFromEntry-D1MJp13f.mjs} +2 -2
- package/dist/logger/index.mjs +1 -1
- package/dist/{mcpPlugin-B_es0hiF.mjs → mcpPlugin-CpfVpKHE.mjs} +32 -31
- package/dist/{memory-DR6wpa9F.mjs → memory-DsuWnj4T.mjs} +5 -5
- package/dist/{metrics-CUdw_wLB.mjs → metrics-DdQL8syd.mjs} +2 -2
- package/dist/middleware/index.mjs +3 -3
- package/dist/migrations/index.mjs +3 -3
- package/dist/{module-0pFJA6YW.mjs → module-Br81am6m.mjs} +1 -1
- package/dist/{multipartBody-wOgj_fnj.mjs → multipartBody-BnkBLN7v.mjs} +3 -3
- package/dist/{openapi-B2L4js1v.mjs → openapi-DIRzvxC0.mjs} +6 -6
- package/dist/outbox-admin/index.d.mts +85 -0
- package/dist/outbox-admin/index.mjs +115 -0
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +6 -6
- package/dist/{permissions-L--QDAir.mjs → permissions-Dl_m0NCe.mjs} +101 -8
- package/dist/{pipe-DRDNsI2T.mjs → pipe-ELHCP3zj.mjs} +3 -5
- package/dist/pipeline/index.mjs +2 -2
- package/dist/{pipeline-UPQFatit.mjs → pipeline-CPA-jx0M.mjs} +17 -15
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/index.mjs +16 -16
- package/dist/plugins/response-cache.mjs +2 -2
- package/dist/plugins/tracing-entry.mjs +2 -2
- package/dist/{pluralize-O0FZgESl.mjs → pluralize-C2ZkKbsn.mjs} +1 -1
- package/dist/{preloadResources-Dz6BjzM6.mjs → preloadResources-CDs87fTw.mjs} +1 -1
- package/dist/{preloadResources-CyoJMSiO.d.mts → preloadResources-T1hmlTEZ.d.mts} +2 -2
- package/dist/presets/filesUpload.mjs +6 -6
- package/dist/presets/index.mjs +2 -2
- package/dist/presets/multiTenant.mjs +3 -3
- package/dist/presets/search.mjs +2 -2
- package/dist/{presets-C4-g4_4P.mjs → presets-Dntd_pUO.mjs} +6 -5
- package/dist/{projection-BHw6xlOQ.mjs → projection-CjHhM5W1.mjs} +2 -2
- package/dist/{queryCachePlugin-BZr8v46E.mjs → queryCachePlugin-Dhps-Ldt.mjs} +6 -6
- package/dist/{rateLimit-CMPY5Qms.mjs → rateLimit-C7mmAGs3.mjs} +2 -2
- package/dist/{rateLimitKey-Dn5JNmkj.mjs → rateLimitKey-CccEFBfk.mjs} +1 -1
- package/dist/{realtime-C5NoxWFY.mjs → realtime-DVvVZZFz.mjs} +10 -10
- package/dist/{registerRoute-CBN84fc7.mjs → registerRoute-B_QrjYZS.mjs} +10 -8
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +3 -3
- package/dist/{registry-4213U4zb.mjs → registry-DqUmzA9W.mjs} +2 -2
- package/dist/{renewingLease-Dll8mGgc.mjs → renewingLease-BpP9wwj7.mjs} +1 -1
- package/dist/{replyHelpers-DIiZKGUt.mjs → replyHelpers-DS-P0b32.mjs} +2 -2
- package/dist/{repositoryFilter-f9eAfq_l.mjs → repositoryFilter-DotlxG3L.mjs} +1 -1
- package/dist/{requestContext-2TxXOJ7T.mjs → requestContext-B6vQF-sy.mjs} +1 -1
- package/dist/{rolldown-runtime-CUsjNX9R.mjs → rolldown-runtime-BhflRrBs.mjs} +1 -1
- package/dist/{schedules-DdtlICTf.mjs → schedules-C2Q3uv2d.mjs} +3 -3
- package/dist/{schemaConverter-D--wdJM-.mjs → schemaConverter-Crjvczi_.mjs} +1 -1
- package/dist/{schemaIR-Bm2enbnh.mjs → schemaIR-CnyKK_1j.mjs} +2 -2
- package/dist/schemas/index.mjs +1 -1
- package/dist/scim/index.mjs +2 -2
- package/dist/scope/index.mjs +5 -5
- package/dist/{scope-DHx5Fous.mjs → scope-afz_Ieek.mjs} +4 -4
- package/dist/{simpleEqualityMatcher-DjQJ7FKA.mjs → simpleEqualityMatcher-C4KiMWUa.mjs} +1 -1
- package/dist/{sse-CUTo9y0X.mjs → sse-B9P4Y-UI.mjs} +7 -6
- package/dist/{sseStream-B_5XcVVd.mjs → sseStream-B3zb_d1h.mjs} +2 -2
- package/dist/{store-helpers-D1MP_gRG.mjs → store-helpers-DmEMHlPQ.mjs} +1 -1
- package/dist/{streaming-PSZwi8JV.mjs → streaming-DPZdQmDz.mjs} +1 -1
- package/dist/{subscribe-helpers-C0Tb2aUp.mjs → subscribe-helpers-sp5xTDVA.mjs} +2 -2
- package/dist/sync/changelog.mjs +1 -1
- package/dist/testing/cleanupStoreContract.mjs +10 -6
- package/dist/testing/index.d.mts +31 -4
- package/dist/testing/index.mjs +97 -39
- package/dist/testing/outboxStoreContract.d.mts +11 -2
- package/dist/testing/outboxStoreContract.mjs +110 -21
- package/dist/testing/storageContract.mjs +11 -6
- package/dist/{transactionContext-dAfBVUrk.mjs → transactionContext-BvLKvOIL.mjs} +1 -1
- package/dist/{typeGuards-B0ryPo3I.mjs → typeGuards-B_5-hKjJ.mjs} +1 -1
- package/dist/types/index.mjs +1 -1
- package/dist/types/storage.mjs +1 -1
- package/dist/{types-CBgvkp8O.d.mts → types-CT5vu6M0.d.mts} +87 -11
- package/dist/{types-Cys0ko9Z.mjs → types-DXYX7dIR.mjs} +4 -4
- package/dist/usage/index.mjs +0 -0
- package/dist/{userHelpers-ChYJ6CdK.mjs → userHelpers-BNsOXzOd.mjs} +1 -1
- package/dist/utils/index.mjs +10 -10
- package/dist/{utils-vL8BrDE2.mjs → utils-BtOha_Sp.mjs} +3 -3
- package/dist/{validate-_KbifpHF.mjs → validate-PMCPR9El.mjs} +2 -2
- package/dist/{versioning-CHDTor3P.mjs → versioning-CKv2jz_U.mjs} +4 -4
- package/package.json +23 -13
- package/dist/fastify-augmentation-zh0_AYHa.d.mts +0 -85
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
3
|
-
import { t as startRenewingLease } from "./renewingLease-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-BhflRrBs.mjs";
|
|
3
|
+
import { t as startRenewingLease } from "./renewingLease-BpP9wwj7.mjs";
|
|
4
4
|
import fp from "fastify-plugin";
|
|
5
5
|
//#region src/plugins/schedules.ts
|
|
6
6
|
var schedules_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { o as toJsonSchema } from "./schemaConverter-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { o as toJsonSchema } from "./schemaConverter-Crjvczi_.mjs";
|
|
3
3
|
//#region src/core/schemaIR.ts
|
|
4
4
|
/**
|
|
5
5
|
* Schema IR — one canonical representation, two adapters.
|
package/dist/schemas/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
2
|
import { errorContractSchema, errorDetailSchema } from "@classytic/repo-core/errors";
|
|
3
3
|
import { Type, Type as Type$1 } from "typebox";
|
|
4
4
|
//#region src/schemas/index.ts
|
package/dist/scim/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as parseJsonBody } from "../jsonBody-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as parseJsonBody } from "../jsonBody-DDSR2HFl.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/scim/errors.ts
|
|
5
5
|
var ScimError = class extends Error {
|
package/dist/scope/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { C as isService, D as requireUserId, E as requireTeamId, O as scopeFirstCtx, S as isOrgInScope, T as requireOrgId, _ as getUserRoles, a as getDPoPJkt, b as isElevated, c as getOrgId, d as getScopeContext, f as getScopeContextMap, g as getUserId, h as getTenantFromRequest, i as getClientId, l as getOrgRoles, m as getTeamId, n as PUBLIC_SCOPE, o as getMandate, p as getServiceScopes, r as getAncestorOrgIds, s as getOrgContext, t as AUTHENTICATED_SCOPE, u as getRequestScope, v as hasOrgAccess, w as requireClientId, x as isMember, y as isAuthenticated } from "../types-
|
|
3
|
-
import { n as elevation_default, t as elevationPlugin } from "../elevation-
|
|
4
|
-
import { t as createTenantKeyGenerator } from "../rateLimitKey-
|
|
5
|
-
import { t as resolveOrgFromHeader } from "../scope-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { C as isService, D as requireUserId, E as requireTeamId, O as scopeFirstCtx, S as isOrgInScope, T as requireOrgId, _ as getUserRoles, a as getDPoPJkt, b as isElevated, c as getOrgId, d as getScopeContext, f as getScopeContextMap, g as getUserId, h as getTenantFromRequest, i as getClientId, l as getOrgRoles, m as getTeamId, n as PUBLIC_SCOPE, o as getMandate, p as getServiceScopes, r as getAncestorOrgIds, s as getOrgContext, t as AUTHENTICATED_SCOPE, u as getRequestScope, v as hasOrgAccess, w as requireClientId, x as isMember, y as isAuthenticated } from "../types-DXYX7dIR.mjs";
|
|
3
|
+
import { n as elevation_default, t as elevationPlugin } from "../elevation-DNXXxgjl.mjs";
|
|
4
|
+
import { t as createTenantKeyGenerator } from "../rateLimitKey-CccEFBfk.mjs";
|
|
5
|
+
import { t as resolveOrgFromHeader } from "../scope-afz_Ieek.mjs";
|
|
6
6
|
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, createTenantKeyGenerator, elevation_default as elevationPlugin, elevationPlugin as elevationPluginFn, getAncestorOrgIds, getClientId, getDPoPJkt, getMandate, getOrgContext, getOrgId, getOrgRoles, getRequestScope, getScopeContext, getScopeContextMap, getServiceScopes, getTeamId, getTenantFromRequest, getUserId, getUserRoles, hasOrgAccess, isAuthenticated, isElevated, isMember, isOrgInScope, isService, requireClientId, requireOrgId, requireTeamId, requireUserId, resolveOrgFromHeader, scopeFirstCtx };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { a as OrgAccessDeniedError, l as UnauthorizedError } from "./errors-
|
|
3
|
-
import { n as requireSingleHeaderValue } from "./headers-
|
|
4
|
-
import { n as getUserRoles } from "./userHelpers-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { a as OrgAccessDeniedError, l as UnauthorizedError } from "./errors-Bh1KK5ps.mjs";
|
|
3
|
+
import { n as requireSingleHeaderValue } from "./headers-BXjQYbeC.mjs";
|
|
4
|
+
import { n as getUserRoles } from "./userHelpers-BNsOXzOd.mjs";
|
|
5
5
|
//#region src/scope/resolveOrgFromHeader.ts
|
|
6
6
|
/**
|
|
7
7
|
* Create a preHandler hook that resolves org scope from a header.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as __exportAll } from "./rolldown-runtime-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-BhflRrBs.mjs";
|
|
3
3
|
import { arcLog } from "./logger/index.mjs";
|
|
4
|
-
import { c as getOrgId, n as PUBLIC_SCOPE } from "./types-
|
|
5
|
-
import { a as promoteStreamTokenToHeader } from "./streaming-
|
|
6
|
-
import { t as openSseStream } from "./sseStream-
|
|
4
|
+
import { c as getOrgId, n as PUBLIC_SCOPE } from "./types-DXYX7dIR.mjs";
|
|
5
|
+
import { a as promoteStreamTokenToHeader } from "./streaming-DPZdQmDz.mjs";
|
|
6
|
+
import { t as openSseStream } from "./sseStream-B3zb_d1h.mjs";
|
|
7
7
|
import fp from "fastify-plugin";
|
|
8
8
|
//#region src/plugins/sse.ts
|
|
9
9
|
var sse_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -33,7 +33,8 @@ const ssePlugin = async (fastify, opts = {}) => {
|
|
|
33
33
|
handler: async (request, reply) => {
|
|
34
34
|
const stream = openSseStream(request, reply, { heartbeatMs: heartbeat });
|
|
35
35
|
stream.onCleanup(() => activeConnections.delete(stream.close));
|
|
36
|
-
const
|
|
36
|
+
const scope = request.scope ?? PUBLIC_SCOPE;
|
|
37
|
+
const requestOrgId = getOrgId(scope);
|
|
37
38
|
const dropOrgEvents = orgScoped && !requestOrgId;
|
|
38
39
|
for (const pattern of patterns) {
|
|
39
40
|
const unsub = await fastify.events.subscribe(pattern, async (event) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { n as forwardedStreamHeaders } from "./streaming-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { n as forwardedStreamHeaders } from "./streaming-DPZdQmDz.mjs";
|
|
3
3
|
//#region src/utils/sseStream.ts
|
|
4
4
|
/**
|
|
5
5
|
* Take over the reply socket and open an SSE stream. Call ONLY after every
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { n as createEvent } from "./EventTransport-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { n as createEvent } from "./EventTransport-BV10D0oG.mjs";
|
|
3
3
|
//#region src/events/defineEvent.ts
|
|
4
4
|
/**
|
|
5
5
|
* defineEvent — Typed Event Definitions with Optional Schema Validation
|
package/dist/sync/changelog.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
2
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
3
3
|
//#region src/testing/cleanupStoreContract.ts
|
|
4
4
|
/**
|
|
@@ -152,10 +152,11 @@ function runCleanupRunStoreContract(name, setup) {
|
|
|
152
152
|
expiresAt: future()
|
|
153
153
|
});
|
|
154
154
|
await store.compareAndTransition(run.id, ["queued"], "running");
|
|
155
|
-
|
|
155
|
+
const stolen = await store.claim(run.id, {
|
|
156
156
|
token: uid("thief"),
|
|
157
157
|
expiresAt: future()
|
|
158
|
-
})
|
|
158
|
+
});
|
|
159
|
+
expect(stolen).toBeNull();
|
|
159
160
|
});
|
|
160
161
|
it("recovers a running run whose lease EXPIRED (crash recovery)", async () => {
|
|
161
162
|
const run = makeRun(uid("crashed"), { concurrencyKey: void 0 });
|
|
@@ -234,9 +235,11 @@ function runCleanupRunStoreContract(name, setup) {
|
|
|
234
235
|
token: live,
|
|
235
236
|
expiresAt: future()
|
|
236
237
|
});
|
|
237
|
-
|
|
238
|
+
const clobbered = await store.compareAndTransition(run.id, ["running"], "completed", { completedAt: /* @__PURE__ */ new Date() }, "a-stale-token");
|
|
239
|
+
expect(clobbered).toBeNull();
|
|
238
240
|
expect((await store.get(run.id))?.status).toBe("running");
|
|
239
|
-
|
|
241
|
+
const ok = await store.compareAndTransition(run.id, ["running"], "completed", void 0, live);
|
|
242
|
+
expect(ok?.status).toBe("completed");
|
|
240
243
|
});
|
|
241
244
|
});
|
|
242
245
|
describe("requestCancel — durable cancellation flag", () => {
|
|
@@ -353,7 +356,8 @@ function runCleanupRunStoreContract(name, setup) {
|
|
|
353
356
|
const run = makeRun(uid("rearm-cancelled"), { concurrencyKey: void 0 });
|
|
354
357
|
await store.createIfPermitted(run);
|
|
355
358
|
await store.compareAndTransition(run.id, ["queued"], "cancelled");
|
|
356
|
-
|
|
359
|
+
const requeued = await store.reArmIfPermitted(run.id, { queuedAt: /* @__PURE__ */ new Date() });
|
|
360
|
+
expect(requeued?.status).toBe("queued");
|
|
357
361
|
});
|
|
358
362
|
it("refuses a run that is not in a terminal status", async () => {
|
|
359
363
|
const run = makeRun(uid("rearm-live"), { concurrencyKey: void 0 });
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { V as ResourceDefinition } from "../index-CpzxqePp.mjs";
|
|
3
3
|
import { i as RequestScope } from "../types-ChuShpCP.mjs";
|
|
4
4
|
import { l as AnyRecord, r as PermissionCheck } from "../types-B7XeLEgK.mjs";
|
|
5
|
-
import { n as ArcModuleInput } from "../types-
|
|
6
|
-
import "../index-
|
|
7
|
-
import { n as preloadResourcesAsync, r as CreateAppOptions, t as preloadResources } from "../preloadResources-
|
|
5
|
+
import { n as ArcModuleInput, o as ModuleDisposer, s as ModuleSetupContext } from "../types-CT5vu6M0.mjs";
|
|
6
|
+
import "../index-ZWhLTp_s.mjs";
|
|
7
|
+
import { n as preloadResourcesAsync, r as CreateAppOptions, t as preloadResources } from "../preloadResources-T1hmlTEZ.mjs";
|
|
8
8
|
import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
|
|
9
9
|
import { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
10
10
|
import { Mock } from "vitest";
|
|
@@ -91,6 +91,11 @@ interface AuthorizationConformance {
|
|
|
91
91
|
* `buildIdFilter` output (route id AND policy AND tenant), so a policy that
|
|
92
92
|
* tried to redirect/widen the target would show here — the surface the
|
|
93
93
|
* filter-overwrite class of bug lives on.
|
|
94
|
+
*
|
|
95
|
+
* `filter` is `undefined` when the permission carries NO policy: `fetchDetailed`
|
|
96
|
+
* only builds a compound filter when there is something to compound, and takes a
|
|
97
|
+
* plain by-id read otherwise. `status` is meaningful on both paths — assert the
|
|
98
|
+
* filter only when the permission under test emits a policy.
|
|
94
99
|
*/
|
|
95
100
|
get: SurfaceObservation;
|
|
96
101
|
/** `GET /confs/aggregations/tally` — the aggregation surface. */
|
|
@@ -675,6 +680,28 @@ declare function createTestTimer(): {
|
|
|
675
680
|
reset: () => void;
|
|
676
681
|
};
|
|
677
682
|
//#endregion
|
|
683
|
+
//#region src/testing/moduleSetup.d.ts
|
|
684
|
+
interface TestModuleSetup {
|
|
685
|
+
/** Pass this as the second argument to `bootstrap` / `plugins` / `afterResources`. */
|
|
686
|
+
readonly context: ModuleSetupContext;
|
|
687
|
+
/**
|
|
688
|
+
* Disposers the module registered, in REGISTRATION order (`dispose()` runs
|
|
689
|
+
* them backwards). Assert on `.length` to prove a phase registered teardown
|
|
690
|
+
* at all — the check a no-op `defer` can never fail.
|
|
691
|
+
*/
|
|
692
|
+
readonly deferred: readonly ModuleDisposer[];
|
|
693
|
+
/**
|
|
694
|
+
* Run every collected disposer LIFO, then clear them.
|
|
695
|
+
*
|
|
696
|
+
* Best-effort like arc's teardown: one throwing disposer never blocks the
|
|
697
|
+
* ones behind it. Any errors are collected and thrown together at the end, so
|
|
698
|
+
* a test still fails loudly instead of a rejection vanishing into a floating
|
|
699
|
+
* promise.
|
|
700
|
+
*/
|
|
701
|
+
dispose(): Promise<void>;
|
|
702
|
+
}
|
|
703
|
+
declare function createTestModuleSetup(): TestModuleSetup;
|
|
704
|
+
//#endregion
|
|
678
705
|
//#region src/testing/scopeRoleGate.d.ts
|
|
679
706
|
/**
|
|
680
707
|
* Grants iff the caller is an org member holding one of `allowed` as an ORG role.
|
|
@@ -777,4 +804,4 @@ declare function createTestApp(options?: CreateTestAppOptions): Promise<TestAppC
|
|
|
777
804
|
*/
|
|
778
805
|
declare function createMinimalTestApp(options?: FastifyServerOptions): FastifyInstance;
|
|
779
806
|
//#endregion
|
|
780
|
-
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, TEST_ACTOR_HEADER, type TestActor, 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, scopeFromTestActor, scopeRoleGate, setupBetterAuthTestApp, testActorAuth, testActorHeaders, waitFor };
|
|
807
|
+
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, TEST_ACTOR_HEADER, type TestActor, type TestAppContext, type TestAuthProvider, type TestAuthSession, type TestDatabase, type TestDatabaseFactory, type TestFixtures, type TestModuleSetup, type TestkitContext, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestModuleSetup, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runAuthorizationConformance, runStorageContract, safeParseBody, scopeFromTestActor, scopeRoleGate, setupBetterAuthTestApp, testActorAuth, testActorHeaders, waitFor };
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
/*! @classytic/arc v2.
|
|
2
|
-
import { t as CRUD_OPERATIONS } from "../constants-
|
|
3
|
-
import { g as getUserId } from "../types-
|
|
4
|
-
import { t as BaseController } from "../BaseController-
|
|
5
|
-
import { t as defineResource } from "../defineResource-
|
|
6
|
-
import { t as defineAggregation } from "../defineAggregation-
|
|
7
|
-
import {
|
|
8
|
-
import { n as createApp } from "../createApp-
|
|
9
|
-
import { n as getModuleExports } from "../module-
|
|
10
|
-
import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-
|
|
1
|
+
/*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
|
|
2
|
+
import { t as CRUD_OPERATIONS } from "../constants-J99LGTJI.mjs";
|
|
3
|
+
import { g as getUserId } from "../types-DXYX7dIR.mjs";
|
|
4
|
+
import { t as BaseController } from "../BaseController-Dk34dxhI.mjs";
|
|
5
|
+
import { t as defineResource } from "../defineResource-XFPPUu2c.mjs";
|
|
6
|
+
import { t as defineAggregation } from "../defineAggregation-gX4No1gt.mjs";
|
|
7
|
+
import { E as requireOrgRole } from "../permissions-Dl_m0NCe.mjs";
|
|
8
|
+
import { n as createApp } from "../createApp-Bv0m-Q6_.mjs";
|
|
9
|
+
import { n as getModuleExports } from "../module-Br81am6m.mjs";
|
|
10
|
+
import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-CDs87fTw.mjs";
|
|
11
11
|
import { runStorageContract } from "./storageContract.mjs";
|
|
12
12
|
import Fastify from "fastify";
|
|
13
13
|
import { afterAll, describe, expect, it, vi } from "vitest";
|
|
@@ -64,7 +64,8 @@ function expectArc(response) {
|
|
|
64
64
|
failed(status) {
|
|
65
65
|
if (status !== void 0) expect(response.statusCode).toBe(status);
|
|
66
66
|
else expect(response.statusCode).toBeGreaterThanOrEqual(400);
|
|
67
|
-
|
|
67
|
+
const body = getBody();
|
|
68
|
+
expect(body.code, "expected ErrorContract.code on failed response").toBeDefined();
|
|
68
69
|
return assertion;
|
|
69
70
|
},
|
|
70
71
|
unauthorized() {
|
|
@@ -84,7 +85,8 @@ function expectArc(response) {
|
|
|
84
85
|
},
|
|
85
86
|
hasData() {
|
|
86
87
|
const body = getBody();
|
|
87
|
-
|
|
88
|
+
const hasContent = Object.keys(body).length > 0;
|
|
89
|
+
expect(hasContent, "expected response body to be defined").toBe(true);
|
|
88
90
|
return assertion;
|
|
89
91
|
},
|
|
90
92
|
hasStatus(status) {
|
|
@@ -92,11 +94,13 @@ function expectArc(response) {
|
|
|
92
94
|
return assertion;
|
|
93
95
|
},
|
|
94
96
|
hidesField(field) {
|
|
95
|
-
|
|
97
|
+
const body = getBody();
|
|
98
|
+
expect(body, `expected field '${field}' to be hidden from response`).not.toHaveProperty(field);
|
|
96
99
|
return assertion;
|
|
97
100
|
},
|
|
98
101
|
showsField(field) {
|
|
99
|
-
|
|
102
|
+
const body = getBody();
|
|
103
|
+
expect(body, `expected field '${field}' on response`).toHaveProperty(field);
|
|
100
104
|
return assertion;
|
|
101
105
|
},
|
|
102
106
|
paginated(expected) {
|
|
@@ -398,6 +402,21 @@ async function runAuthorizationConformance(opts) {
|
|
|
398
402
|
getFilter = filter;
|
|
399
403
|
return rows[0] ?? null;
|
|
400
404
|
}),
|
|
405
|
+
/**
|
|
406
|
+
* The single-record read has TWO paths, and the harness must be able to observe both.
|
|
407
|
+
*
|
|
408
|
+
* `fetchDetailed` only builds a compound filter and calls `getOne` when there is something to
|
|
409
|
+
* compound — a row policy, a tenant field, or a non-default id field. A permission that simply
|
|
410
|
+
* ALLOWS (no policy) leaves `{ _id }` alone and takes the plain `getById` path instead. The base
|
|
411
|
+
* mock stubs that as `null`, so before this stub the `get` surface reported **404 on every
|
|
412
|
+
* policy-free allow** while `list` and `aggregation` reported 200.
|
|
413
|
+
*
|
|
414
|
+
* That reads as partial enforcement and it is not: it is the harness failing to answer. A host
|
|
415
|
+
* asserting `get.status === 200` for its own allow-gate — the obvious falsification case to pair
|
|
416
|
+
* with a deny-parity suite — was told its gate broke the single-record surface. Found from
|
|
417
|
+
* be-prod, whose conformance suite does exactly that.
|
|
418
|
+
*/
|
|
419
|
+
getById: (async () => rows[0] ?? null),
|
|
401
420
|
aggregate: (async (req = {}) => {
|
|
402
421
|
aggFilter = req.filter;
|
|
403
422
|
return { rows: [{ tally: rows.length }] };
|
|
@@ -1166,12 +1185,13 @@ var HttpTestHarness = class {
|
|
|
1166
1185
|
it(`${verb} /:id with non-existent ID should return 404`, async () => {
|
|
1167
1186
|
const { app, fixtures } = this.getOptions();
|
|
1168
1187
|
const payload = fixtures.update ?? fixtures.valid;
|
|
1169
|
-
|
|
1188
|
+
const res = await app.inject({
|
|
1170
1189
|
method: verb,
|
|
1171
1190
|
url: `${this.getBaseUrl()}/000000000000000000000000`,
|
|
1172
1191
|
headers: this.adminHeaders(),
|
|
1173
1192
|
payload
|
|
1174
|
-
})
|
|
1193
|
+
});
|
|
1194
|
+
expect(res.statusCode).toBe(404);
|
|
1175
1195
|
});
|
|
1176
1196
|
}
|
|
1177
1197
|
if (enabledRoutes.has("delete")) {
|
|
@@ -1188,24 +1208,29 @@ var HttpTestHarness = class {
|
|
|
1188
1208
|
deleteId = JSON.parse(createRes.body)._id;
|
|
1189
1209
|
}
|
|
1190
1210
|
if (!deleteId) return;
|
|
1191
|
-
|
|
1211
|
+
const res = await app.inject({
|
|
1192
1212
|
method: "DELETE",
|
|
1193
1213
|
url: `${this.getBaseUrl()}/${deleteId}`,
|
|
1194
1214
|
headers: this.adminHeaders()
|
|
1195
|
-
})
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1215
|
+
});
|
|
1216
|
+
expect(res.statusCode).toBe(200);
|
|
1217
|
+
if (enabledRoutes.has("get")) {
|
|
1218
|
+
const getRes = await app.inject({
|
|
1219
|
+
method: "GET",
|
|
1220
|
+
url: `${this.getBaseUrl()}/${deleteId}`,
|
|
1221
|
+
headers: this.adminHeaders()
|
|
1222
|
+
});
|
|
1223
|
+
expect(getRes.statusCode).toBe(404);
|
|
1224
|
+
}
|
|
1201
1225
|
});
|
|
1202
1226
|
it("DELETE /:id with non-existent ID should return 404", async () => {
|
|
1203
1227
|
const { app } = this.getOptions();
|
|
1204
|
-
|
|
1228
|
+
const res = await app.inject({
|
|
1205
1229
|
method: "DELETE",
|
|
1206
1230
|
url: `${this.getBaseUrl()}/000000000000000000000000`,
|
|
1207
1231
|
headers: this.adminHeaders()
|
|
1208
|
-
})
|
|
1232
|
+
});
|
|
1233
|
+
expect(res.statusCode).toBe(404);
|
|
1209
1234
|
});
|
|
1210
1235
|
}
|
|
1211
1236
|
});
|
|
@@ -1224,49 +1249,55 @@ var HttpTestHarness = class {
|
|
|
1224
1249
|
describe(`${resource.displayName} HTTP Permissions`, () => {
|
|
1225
1250
|
if (enabledRoutes.has("list") && protectedOps.list) it("GET list without auth should return 401", async () => {
|
|
1226
1251
|
const { app } = this.getOptions();
|
|
1227
|
-
|
|
1252
|
+
const res = await app.inject({
|
|
1228
1253
|
method: "GET",
|
|
1229
1254
|
url: this.getBaseUrl()
|
|
1230
|
-
})
|
|
1255
|
+
});
|
|
1256
|
+
expect(res.statusCode).toBe(401);
|
|
1231
1257
|
});
|
|
1232
1258
|
if (enabledRoutes.has("get") && protectedOps.get) it("GET /:id without auth should return 401", async () => {
|
|
1233
1259
|
const { app } = this.getOptions();
|
|
1234
|
-
|
|
1260
|
+
const res = await app.inject({
|
|
1235
1261
|
method: "GET",
|
|
1236
1262
|
url: `${this.getBaseUrl()}/000000000000000000000000`
|
|
1237
|
-
})
|
|
1263
|
+
});
|
|
1264
|
+
expect(res.statusCode).toBe(401);
|
|
1238
1265
|
});
|
|
1239
1266
|
if (enabledRoutes.has("create") && protectedOps.create) it("POST without auth should return 401", async () => {
|
|
1240
1267
|
const { app, fixtures } = this.getOptions();
|
|
1241
|
-
|
|
1268
|
+
const res = await app.inject({
|
|
1242
1269
|
method: "POST",
|
|
1243
1270
|
url: this.getBaseUrl(),
|
|
1244
1271
|
payload: fixtures.valid
|
|
1245
|
-
})
|
|
1272
|
+
});
|
|
1273
|
+
expect(res.statusCode).toBe(401);
|
|
1246
1274
|
});
|
|
1247
1275
|
if (enabledRoutes.has("update") && protectedOps.update) for (const verb of updateMethods) it(`${verb} without auth should return 401`, async () => {
|
|
1248
1276
|
const { app, fixtures } = this.getOptions();
|
|
1249
1277
|
const payload = fixtures.update ?? fixtures.valid;
|
|
1250
|
-
|
|
1278
|
+
const res = await app.inject({
|
|
1251
1279
|
method: verb,
|
|
1252
1280
|
url: `${this.getBaseUrl()}/000000000000000000000000`,
|
|
1253
1281
|
payload
|
|
1254
|
-
})
|
|
1282
|
+
});
|
|
1283
|
+
expect(res.statusCode).toBe(401);
|
|
1255
1284
|
});
|
|
1256
1285
|
if (enabledRoutes.has("delete") && protectedOps.delete) it("DELETE without auth should return 401", async () => {
|
|
1257
1286
|
const { app } = this.getOptions();
|
|
1258
|
-
|
|
1287
|
+
const res = await app.inject({
|
|
1259
1288
|
method: "DELETE",
|
|
1260
1289
|
url: `${this.getBaseUrl()}/000000000000000000000000`
|
|
1261
|
-
})
|
|
1290
|
+
});
|
|
1291
|
+
expect(res.statusCode).toBe(401);
|
|
1262
1292
|
});
|
|
1263
1293
|
if (enabledRoutes.has("list")) it("admin should access list endpoint", async () => {
|
|
1264
1294
|
const { app } = this.getOptions();
|
|
1265
|
-
|
|
1295
|
+
const res = await app.inject({
|
|
1266
1296
|
method: "GET",
|
|
1267
1297
|
url: this.getBaseUrl(),
|
|
1268
1298
|
headers: this.adminHeaders()
|
|
1269
|
-
})
|
|
1299
|
+
});
|
|
1300
|
+
expect(res.statusCode).toBeLessThan(400);
|
|
1270
1301
|
});
|
|
1271
1302
|
if (enabledRoutes.has("create")) it("admin should access create endpoint", async () => {
|
|
1272
1303
|
const { app, fixtures } = this.getOptions();
|
|
@@ -1313,6 +1344,33 @@ function createHttpTestHarness(resource, optionsOrGetter) {
|
|
|
1313
1344
|
return new HttpTestHarness(resource, optionsOrGetter);
|
|
1314
1345
|
}
|
|
1315
1346
|
//#endregion
|
|
1347
|
+
//#region src/testing/moduleSetup.ts
|
|
1348
|
+
function createTestModuleSetup() {
|
|
1349
|
+
const deferred = [];
|
|
1350
|
+
return {
|
|
1351
|
+
context: { defer(disposer) {
|
|
1352
|
+
if (typeof disposer !== "function") throw new TypeError(`[arc/testing] defer() expected a function, received ${typeof disposer}.`);
|
|
1353
|
+
deferred.push(disposer);
|
|
1354
|
+
} },
|
|
1355
|
+
deferred,
|
|
1356
|
+
async dispose() {
|
|
1357
|
+
const errors = [];
|
|
1358
|
+
for (let i = deferred.length - 1; i >= 0; i--) {
|
|
1359
|
+
const dispose = deferred[i];
|
|
1360
|
+
if (!dispose) continue;
|
|
1361
|
+
try {
|
|
1362
|
+
await dispose();
|
|
1363
|
+
} catch (err) {
|
|
1364
|
+
errors.push(err);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
deferred.length = 0;
|
|
1368
|
+
if (errors.length === 1) throw errors[0];
|
|
1369
|
+
if (errors.length > 1) throw new AggregateError(errors, `[arc/testing] ${errors.length} disposers threw`);
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
//#endregion
|
|
1316
1374
|
//#region src/testing/scopeRoleGate.ts
|
|
1317
1375
|
/**
|
|
1318
1376
|
* `scopeRoleGate` — the ONE role gate for package tests.
|
|
@@ -1435,7 +1493,7 @@ function pickDefaultAuth(authMode, callerAuth) {
|
|
|
1435
1493
|
};
|
|
1436
1494
|
}
|
|
1437
1495
|
async function createTestApp(options = {}) {
|
|
1438
|
-
const { createApp } = await import("../createApp-
|
|
1496
|
+
const { createApp } = await import("../createApp-Bv0m-Q6_.mjs").then((n) => n.r);
|
|
1439
1497
|
const { resources = [], db = "in-memory", connectMongoose = false, authMode = "jwt", defaultOrgId, plugins, auth: callerAuth, ...appOptions } = options;
|
|
1440
1498
|
let dbHandle;
|
|
1441
1499
|
let dbUri;
|
|
@@ -1505,4 +1563,4 @@ function createMinimalTestApp(options = {}) {
|
|
|
1505
1563
|
});
|
|
1506
1564
|
}
|
|
1507
1565
|
//#endregion
|
|
1508
|
-
export { HttpTestHarness, TEST_ACTOR_HEADER, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runAuthorizationConformance, runStorageContract, safeParseBody, scopeFromTestActor, scopeRoleGate, setupBetterAuthTestApp, testActorAuth, testActorHeaders, waitFor };
|
|
1566
|
+
export { HttpTestHarness, TEST_ACTOR_HEADER, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestModuleSetup, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runAuthorizationConformance, runStorageContract, safeParseBody, scopeFromTestActor, scopeRoleGate, setupBetterAuthTestApp, testActorAuth, testActorHeaders, waitFor };
|
|
@@ -5,8 +5,17 @@ interface OutboxStoreContractSetupResult {
|
|
|
5
5
|
store: OutboxStore;
|
|
6
6
|
/** Called once after the suite. */
|
|
7
7
|
teardown?: () => Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Empty the store. REQUIRED, and run before every test.
|
|
10
|
+
*
|
|
11
|
+
* Not a recommendation: several assertions are absolute rather than relative —
|
|
12
|
+
* "exactly zero pending", "exactly two", "`oldestPendingAgeMs()` is null on an
|
|
13
|
+
* empty queue". Without a reset those read whatever the previous test left, so the
|
|
14
|
+
* suite passes on ORDER rather than on behaviour, and inserting one unrelated case
|
|
15
|
+
* turns a conforming store red. A store that cannot empty itself cannot be
|
|
16
|
+
* conformance-tested.
|
|
17
|
+
*/
|
|
18
|
+
reset: () => Promise<void>;
|
|
10
19
|
}
|
|
11
20
|
type OutboxStoreContractSetup = () => Promise<OutboxStoreContractSetupResult>;
|
|
12
21
|
declare function runOutboxStoreContract(name: string, setup: OutboxStoreContractSetup): void;
|