@classytic/arc 2.30.0 → 2.31.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/LICENSE +1 -1
- package/README.md +7 -0
- package/TRADEMARK.md +22 -0
- package/dist/{BaseController-B5DwufbB.mjs → BaseController-De7GqHck.mjs} +16 -17
- package/dist/{EventTransport-QmY7A258.d.mts → EventTransport-2uVV34WU.d.mts} +1 -0
- package/dist/{EventTransport-C6YA8xY9.mjs → EventTransport-9mlTgqzE.mjs} +1 -0
- package/dist/{HookSystem-WkIougo6.mjs → HookSystem-BcmPyq5I.mjs} +2 -1
- package/dist/{QueryCache-DOMT_iq7.d.mts → QueryCache-DFA-QrU9.d.mts} +2 -1
- package/dist/{ResourceRegistry-y9Hnypus.mjs → ResourceRegistry-qq0mn2s9.mjs} +3 -2
- package/dist/{actionPermissions-CAphcmUG.mjs → actionPermissions-BE5NwaQk.mjs} +1 -0
- package/dist/audit/index.d.mts +3 -2
- package/dist/audit/index.mjs +2 -1
- package/dist/auth/audit.d.mts +1 -0
- package/dist/auth/audit.mjs +1 -0
- package/dist/auth/index.d.mts +5 -4
- package/dist/auth/index.mjs +6 -5
- package/dist/auth/redis-session.d.mts +2 -1
- package/dist/auth/redis-session.mjs +1 -0
- package/dist/{applyPermissionResult-Cf6zUCvb.mjs → authorizationDecision-ChvUQGG1.mjs} +19 -10
- package/dist/{buildHandler-BYS3Vkfz.mjs → buildHandler-CDrCJzmB.mjs} +4 -3
- package/dist/cache/index.d.mts +4 -3
- package/dist/cache/index.mjs +4 -3
- package/dist/{caching-_NJeDd1_.mjs → caching-BFHA6Scf.mjs} +2 -1
- package/dist/cleanup/index.d.mts +4 -3
- package/dist/cleanup/index.mjs +9 -13
- package/dist/cli/commands/describe.d.mts +2 -1
- package/dist/cli/commands/describe.mjs +3 -2
- package/dist/cli/commands/docs.d.mts +1 -0
- package/dist/cli/commands/docs.mjs +3 -2
- package/dist/cli/commands/doctor.d.mts +1 -0
- package/dist/cli/commands/doctor.mjs +1 -0
- package/dist/cli/commands/generate.d.mts +2 -1
- package/dist/cli/commands/generate.mjs +2 -1
- package/dist/cli/commands/init.d.mts +2 -1
- package/dist/cli/commands/init.mjs +2 -1
- package/dist/cli/commands/introspect.d.mts +1 -0
- package/dist/cli/commands/introspect.mjs +2 -1
- package/dist/cli/index.d.mts +3 -2
- package/dist/cli/index.mjs +3 -2
- package/dist/{constants-DNre0wRg.mjs → constants-D3Dv4LAV.mjs} +1 -0
- package/dist/context/index.d.mts +1 -0
- package/dist/context/index.mjs +3 -2
- package/dist/core/index.d.mts +3 -2
- package/dist/core/index.mjs +7 -6
- package/dist/{core-poalJLvp.mjs → core-BGpIxINN.mjs} +3 -2
- package/dist/{createActionRouter-BxuywVRB.mjs → createActionRouter-CDXEdasl.mjs} +8 -7
- package/dist/{createAggregationRouter-BiY-lGdY.mjs → createAggregationRouter-KrQDzx-k.mjs} +7 -6
- package/dist/{createApp-CXrKFciH.mjs → createApp-Df89BEni.mjs} +484 -209
- package/dist/{defineAggregation-ufWjUwml.mjs → defineAggregation-DbPPS8RI.mjs} +1 -0
- package/dist/{defineResource-CxWqDCAy.mjs → defineResource-Bv6EtN1x.mjs} +63 -38
- package/dist/discovery/index.d.mts +1 -0
- package/dist/discovery/index.mjs +1 -0
- package/dist/docs/index.d.mts +3 -2
- package/dist/docs/index.mjs +3 -2
- package/dist/{elevation-C9s5hFP_.d.mts → elevation-BXCfVcNG.d.mts} +1 -0
- package/dist/{elevation-CIz1GjGm.mjs → elevation-D2l1mh4g.mjs} +4 -3
- package/dist/encryption/index.d.mts +2 -1
- package/dist/encryption/index.mjs +3 -2
- package/dist/{errorHandler-Bq2OeEQL.mjs → errorHandler-C5NeD6bT.mjs} +3 -2
- package/dist/{errorHandler-C6yv4ZTW.d.mts → errorHandler-CpYUJmPA.d.mts} +1 -0
- package/dist/{errors-DHcHVAgk.d.mts → errors-BGdVwP25.d.mts} +1 -0
- package/dist/{errors-DkO8Nk6-.mjs → errors-Cj42AntO.mjs} +1 -0
- package/dist/{eventPlugin-D2NNR4py.mjs → eventPlugin-CkffEihm.mjs} +5 -4
- package/dist/{eventPlugin-Bg3cP2_u.d.mts → eventPlugin-GF5nnBIq.d.mts} +2 -1
- package/dist/events/index.d.mts +4 -3
- package/dist/events/index.mjs +16 -4
- package/dist/events/transports/redis-stream-entry.d.mts +2 -1
- package/dist/events/transports/redis-stream-entry.mjs +1 -0
- package/dist/events/transports/redis.d.mts +2 -1
- package/dist/events/transports/redis.mjs +1 -0
- package/dist/{externalPaths-BE6wFpYv.d.mts → externalPaths-CmGOxOtD.d.mts} +1 -0
- package/dist/factory/index.d.mts +9 -5
- package/dist/factory/index.mjs +7 -6
- package/dist/{fastify-augmentation-0WhPnUH7.d.mts → fastify-augmentation-zh0_AYHa.d.mts} +13 -4
- package/dist/{fields-CQ_7KQWw.mjs → fields-CB5Cuzk9.mjs} +1 -0
- package/dist/{fields-D3lhgzhD.d.mts → fields-I_EeRWND.d.mts} +1 -0
- package/dist/{generate-BnsL9GBm.d.mts → generate-DCGuEbqI.d.mts} +1 -0
- package/dist/{generate-D0wZupBg.mjs → generate-EcA6ui4i.mjs} +2 -1
- package/dist/{headers-BvlQSDMB.mjs → headers-3zvE0rM3.mjs} +2 -1
- package/dist/{health-CB_m4S32.mjs → health-DjZYjM7H.mjs} +1 -0
- package/dist/hooks/index.d.mts +2 -1
- package/dist/hooks/index.mjs +2 -1
- package/dist/idempotency/index.d.mts +3 -2
- package/dist/idempotency/index.mjs +4 -3
- package/dist/idempotency/redis.d.mts +2 -1
- package/dist/idempotency/redis.mjs +1 -0
- package/dist/{index-Cx7bro4R.d.mts → index-Bc2ox8_U.d.mts} +5 -4
- package/dist/{index-CG4yqMDB.d.mts → index-C-481Zf2.d.mts} +74 -18
- package/dist/{index-Ch16aAah.d.mts → index-CEJNZFtX.d.mts} +53 -15
- package/dist/index-CFThn1K9.d.mts +224 -0
- package/dist/{index-Q5gzEIWY.d.mts → index-CpzxqePp.d.mts} +107 -32
- package/dist/index.d.mts +9 -8
- package/dist/index.mjs +11 -10
- package/dist/{init-tlRSt667.mjs → init-BEiNZBsJ.mjs} +19 -23
- package/dist/{init-BPEu8cs-.d.mts → init-Cscs4lab.d.mts} +1 -0
- package/dist/integrations/event-gateway.d.mts +3 -2
- package/dist/integrations/event-gateway.mjs +2 -1
- package/dist/integrations/index.d.mts +4 -3
- package/dist/integrations/index.mjs +1 -0
- package/dist/integrations/jobs/index.d.mts +2 -1
- package/dist/integrations/jobs/index.mjs +108 -32
- package/dist/integrations/mcp/index.d.mts +6 -6
- package/dist/integrations/mcp/index.mjs +2 -1
- package/dist/integrations/mcp/testing.d.mts +3 -2
- package/dist/integrations/mcp/testing.mjs +2 -2
- package/dist/integrations/streamline.d.mts +1 -0
- package/dist/integrations/streamline.mjs +3 -2
- package/dist/integrations/webhooks.d.mts +1 -0
- package/dist/integrations/webhooks.mjs +1 -0
- package/dist/integrations/websocket-pushref-redis.d.mts +2 -1
- package/dist/integrations/websocket-pushref-redis.mjs +1 -0
- package/dist/integrations/websocket-redis.d.mts +2 -1
- package/dist/integrations/websocket-redis.mjs +1 -0
- package/dist/integrations/websocket.d.mts +3 -2
- package/dist/integrations/websocket.mjs +1 -0
- package/dist/{interface-BGZCzOGL.d.mts → interface-BOk3YnTz.d.mts} +1 -0
- package/dist/{interface-Uk8ONJv7.d.mts → interface-DEWNOMza.d.mts} +1 -0
- package/dist/{interface-n5hpKg1d.mjs → interface-DYzM0q-u.mjs} +1 -0
- package/dist/{jsonBody-BlzAoGCe.mjs → jsonBody-BYbLDi5D.mjs} +2 -1
- package/dist/{keys-Cd316u_y.mjs → keys-C0_pa1tY.mjs} +1 -0
- package/dist/{loadResources-DpU8pfjV.mjs → loadResources-yawi9tAE.mjs} +2 -1
- package/dist/{loadResourcesFromEntry-kvGT6EcO.mjs → loadResourcesFromEntry-BAjYZonx.mjs} +2 -1
- package/dist/logger/index.d.mts +1 -0
- package/dist/logger/index.mjs +1 -0
- package/dist/{mcpPlugin-nRzm5g2s.mjs → mcpPlugin-B_es0hiF.mjs} +22 -23
- package/dist/{memory-CmnzXE5Z.mjs → memory-DR6wpa9F.mjs} +2 -1
- package/dist/{metrics-fdxI5mn_.mjs → metrics-CUdw_wLB.mjs} +2 -1
- package/dist/middleware/index.d.mts +2 -1
- package/dist/middleware/index.mjs +3 -2
- package/dist/migrations/index.d.mts +1 -0
- package/dist/migrations/index.mjs +2 -1
- package/dist/module-0pFJA6YW.mjs +78 -0
- package/dist/{multipartBody-D0eBvkeq.mjs → multipartBody-wOgj_fnj.mjs} +1 -0
- package/dist/{openapi-B8Vkbxbn.mjs → openapi-B2L4js1v.mjs} +6 -5
- package/dist/permissions/index.d.mts +5 -4
- package/dist/permissions/index.mjs +6 -5
- package/dist/{permissions-Bfu_8y1U.mjs → permissions-L--QDAir.mjs} +214 -41
- package/dist/{pipe-BOLmGIxa.mjs → pipe-DRDNsI2T.mjs} +2 -1
- package/dist/pipeline/index.d.mts +2 -1
- package/dist/pipeline/index.mjs +2 -1
- package/dist/{pipeline-BJnpkY9i.mjs → pipeline-UPQFatit.mjs} +6 -5
- package/dist/plugins/index.d.mts +8 -7
- package/dist/plugins/index.mjs +16 -15
- package/dist/plugins/response-cache.d.mts +1 -0
- package/dist/plugins/response-cache.mjs +2 -1
- package/dist/plugins/tracing-entry.d.mts +2 -1
- package/dist/plugins/tracing-entry.mjs +2 -1
- package/dist/{pluralize-BhrgwZb9.mjs → pluralize-O0FZgESl.mjs} +1 -0
- package/dist/{preloadResources-DCfa2egz.d.mts → preloadResources-CyoJMSiO.d.mts} +117 -12
- package/dist/{preloadResources-DSY5HGpS.mjs → preloadResources-Dz6BjzM6.mjs} +1 -0
- package/dist/presets/filesUpload.d.mts +6 -5
- package/dist/presets/filesUpload.mjs +9 -11
- package/dist/presets/index.d.mts +3 -2
- package/dist/presets/index.mjs +2 -1
- package/dist/presets/multiTenant.d.mts +2 -1
- package/dist/presets/multiTenant.mjs +3 -2
- package/dist/presets/search.d.mts +3 -2
- package/dist/presets/search.mjs +2 -1
- package/dist/{presets-CJOEXLuk.mjs → presets-C4-g4_4P.mjs} +4 -3
- package/dist/{projection-UBDgfMwu.mjs → projection-BHw6xlOQ.mjs} +2 -1
- package/dist/{pushref-registry-BbcnpNTm.d.mts → pushref-registry-Dov9l4qE.d.mts} +1 -0
- package/dist/{queryCachePlugin-DSGuSVLW.mjs → queryCachePlugin-BZr8v46E.mjs} +5 -4
- package/dist/{queryCachePlugin-br4otiqF.d.mts → queryCachePlugin-BzqxconG.d.mts} +3 -2
- package/dist/{rateLimit-DrED-C4v.mjs → rateLimit-CMPY5Qms.mjs} +7 -3
- package/dist/{rateLimitKey-BoWRH3e7.mjs → rateLimitKey-Dn5JNmkj.mjs} +1 -0
- package/dist/{realtime-B9nmIY5V.mjs → realtime-C5NoxWFY.mjs} +20 -9
- package/dist/{redis-UDtLaNj6.d.mts → redis-CduhKsJi.d.mts} +2 -1
- package/dist/{redis-stream-uIaauNpZ.d.mts → redis-stream-qN6A-RFv.d.mts} +2 -1
- package/dist/{registerRoute-JkxIEBJq.mjs → registerRoute-CBN84fc7.mjs} +4 -3
- package/dist/registry/index.d.mts +3 -2
- package/dist/registry/index.mjs +3 -2
- package/dist/{registry-BYXUUg21.mjs → registry-4213U4zb.mjs} +2 -1
- package/dist/{renewingLease-3cuQH7h8.mjs → renewingLease-Dll8mGgc.mjs} +1 -0
- package/dist/{replyHelpers-67tRawQZ.mjs → replyHelpers-DIiZKGUt.mjs} +2 -1
- package/dist/{repositoryFilter-Dz8k3S4P.mjs → repositoryFilter-f9eAfq_l.mjs} +1 -0
- package/dist/{requestContext-MrlJwECf.mjs → requestContext-2TxXOJ7T.mjs} +1 -0
- package/dist/{rolldown-runtime-8H4AJuhK.mjs → rolldown-runtime-CUsjNX9R.mjs} +1 -0
- package/dist/{schedules-CjOd2MG9.mjs → schedules-DdtlICTf.mjs} +3 -2
- package/dist/{schemaConverter-DJvodiHj.mjs → schemaConverter-D--wdJM-.mjs} +70 -17
- package/dist/{schemaIR-Ca7ySNPx.mjs → schemaIR-Bm2enbnh.mjs} +2 -1
- package/dist/schemas/index.d.mts +1 -0
- package/dist/schemas/index.mjs +1 -0
- package/dist/scim/index.d.mts +1 -0
- package/dist/scim/index.mjs +2 -1
- package/dist/scope/index.d.mts +3 -2
- package/dist/scope/index.mjs +5 -4
- package/dist/{scope-DfaPntpo.mjs → scope-DHx5Fous.mjs} +4 -3
- package/dist/{sessionManager-BHOM3N_0.d.mts → sessionManager-qimlKV0P.d.mts} +1 -0
- package/dist/{simpleEqualityMatcher-Cg05HPsn.mjs → simpleEqualityMatcher-DjQJ7FKA.mjs} +1 -0
- package/dist/{sse-BQ1w0dfl.mjs → sse-CUTo9y0X.mjs} +5 -4
- package/dist/{sseStream-BQ7Qaynp.mjs → sseStream-B_5XcVVd.mjs} +2 -1
- package/dist/{storage-DLUZ04kK.d.mts → storage-Cx9Sz3Ou.d.mts} +1 -0
- package/dist/{store-helpers-DY6xq4sM.mjs → store-helpers-D1MP_gRG.mjs} +1 -0
- package/dist/{streaming-BQcW6_Kq.mjs → streaming-PSZwi8JV.mjs} +1 -0
- package/dist/{subscribe-helpers-DfzsivM6.mjs → subscribe-helpers-C0Tb2aUp.mjs} +2 -1
- package/dist/sync/changelog.d.mts +1 -0
- package/dist/sync/changelog.mjs +1 -0
- package/dist/testing/cleanupStoreContract.d.mts +2 -1
- package/dist/testing/cleanupStoreContract.mjs +1 -0
- package/dist/testing/index.d.mts +139 -12
- package/dist/testing/index.mjs +230 -16
- package/dist/testing/outboxStoreContract.d.mts +1 -0
- package/dist/testing/outboxStoreContract.mjs +1 -0
- package/dist/testing/storageContract.d.mts +2 -1
- package/dist/testing/storageContract.mjs +1 -0
- package/dist/{tracing-CsGKQJGg.d.mts → tracing-Dro5eH6j.d.mts} +1 -0
- package/dist/{transactionContext-PNdoyLLm.mjs → transactionContext-dAfBVUrk.mjs} +1 -0
- package/dist/{typeGuards-C9KXUly6.mjs → typeGuards-B0ryPo3I.mjs} +1 -0
- package/dist/types/index.d.mts +6 -5
- package/dist/types/index.mjs +1 -0
- package/dist/types/storage.d.mts +2 -1
- package/dist/types/storage.mjs +1 -0
- package/dist/{types-ChvvVNP8.d.mts → types-B7XeLEgK.d.mts} +34 -2
- package/dist/{types-Cc91nXuA.d.mts → types-ByHn9rEO.d.mts} +1 -0
- package/dist/{types-C_ZZRcD6.d.mts → types-C4QE8qnm.d.mts} +1 -0
- package/dist/{types-D_n8L6VY.d.mts → types-CBgvkp8O.d.mts} +51 -12
- package/dist/{types-DjC-KUCz.d.mts → types-ChuShpCP.d.mts} +1 -0
- package/dist/{types-Bmmn-fO0.d.mts → types-CwcUQ610.d.mts} +2 -6
- package/dist/{types-CSyCxl2V.mjs → types-Cys0ko9Z.mjs} +4 -3
- package/dist/usage/index.d.mts +3 -2
- package/dist/usage/index.mjs +0 -0
- package/dist/{userHelpers-Cg_y3fBz.mjs → userHelpers-ChYJ6CdK.mjs} +1 -0
- package/dist/utils/index.d.mts +16 -7
- package/dist/utils/index.mjs +10 -9
- package/dist/{utils-taUVD4p3.mjs → utils-vL8BrDE2.mjs} +3 -2
- package/dist/{validate-Bk44F2yT.mjs → validate-_KbifpHF.mjs} +2 -1
- package/dist/{versioning-gKWyryT3.mjs → versioning-CHDTor3P.mjs} +3 -2
- package/dist/{versioning-DXgY5BUm.d.mts → versioning-D_rhHfZm.d.mts} +5 -2
- package/dist/{websocket-_Pd0CgR0.d.mts → websocket-BOXVggMf.d.mts} +2 -1
- package/package.json +547 -539
- package/skills/arc/SKILL.md +22 -8
- package/skills/arc/references/api-reference.md +4 -0
- package/skills/arc/references/auth.md +3 -0
- package/skills/arc/references/integrations.md +33 -0
- package/skills/arc/references/mcp.md +6 -7
- package/skills/arc/references/production.md +24 -25
- package/skills/arc-code-review/references/anti-patterns.md +3 -3
- package/dist/index-CCzVR-N3.d.mts +0 -107
- package/dist/module-_-M7C5ES.mjs +0 -29
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import "./
|
|
1
|
+
|
|
2
|
+
import { C as RequestContext, Et as ActionDefinition, F as FastifyWithDecorators, H as CrudController, L as RequestWithExtras, Lt as IController, Rt as IControllerResponse, T as CrudRouterOptions, U as ResourceConfig, V as ResourceDefinition, et as RouteSchemaOptions, jt as RouteMcpConfig, tt as ArcFieldRule, ut as AggregationConfig, zt as IRequestContext } from "./index-CpzxqePp.mjs";
|
|
3
|
+
import { i as RequestScope } from "./types-ChuShpCP.mjs";
|
|
4
|
+
import { l as AnyRecord, r as PermissionCheck } from "./types-B7XeLEgK.mjs";
|
|
5
|
+
import "./fastify-augmentation-zh0_AYHa.mjs";
|
|
5
6
|
import { FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
|
|
6
7
|
import { z } from "zod";
|
|
7
8
|
import { DataAdapter } from "@classytic/repo-core/adapter";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
|
|
2
|
+
import { r as PermissionCheck } from "./types-B7XeLEgK.mjs";
|
|
1
3
|
import { FastifyPluginAsync } from "fastify";
|
|
2
4
|
//#region src/integrations/jobs/execution.d.ts
|
|
3
5
|
/**
|
|
@@ -43,18 +45,6 @@ interface ExecuteTimedHandlerOptions<T> {
|
|
|
43
45
|
declare function executeTimedHandler<T>(options: ExecuteTimedHandlerOptions<T>): Promise<T>;
|
|
44
46
|
//#endregion
|
|
45
47
|
//#region src/integrations/jobs/types.d.ts
|
|
46
|
-
/**
|
|
47
|
-
* Job queue integration — public contract (definitions, meta, dispatcher).
|
|
48
|
-
*
|
|
49
|
-
* Directory map (mechanical split of the former single file):
|
|
50
|
-
* types.ts — this contract + `defineJob`
|
|
51
|
-
* execution.ts — `executeTimedHandler` (timeout / cancellation / bulkhead)
|
|
52
|
-
* repeat.ts — repeatable-schedule reconciliation (boot hygiene)
|
|
53
|
-
* plugin.ts — BullMQ wiring (queues, workers, DLQ, routes, shutdown)
|
|
54
|
-
* index.ts — public barrel; `src/integrations/jobs.ts` re-exports it
|
|
55
|
-
* so the package subpath is unchanged
|
|
56
|
-
*/
|
|
57
|
-
/** Repeat schedule — cron pattern or fixed interval. Explicit timezone is required. */
|
|
58
48
|
interface JobRepeatOptions {
|
|
59
49
|
/** Cron pattern (e.g. '0 9 * * *' = every day 09:00). Mutually exclusive with `every`. */
|
|
60
50
|
pattern?: string;
|
|
@@ -177,6 +167,61 @@ interface JobsPluginOptions {
|
|
|
177
167
|
jobs: JobDefinition[];
|
|
178
168
|
/** URL prefix for job management endpoints (default: '/jobs') */
|
|
179
169
|
prefix?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Job management HTTP endpoints (`GET <prefix>/stats`,
|
|
172
|
+
* `GET <prefix>/:queue/:id/status`).
|
|
173
|
+
*
|
|
174
|
+
* **Disabled by default.** A job status carries `returnValue` and
|
|
175
|
+
* `failedReason` — the handler's own output and error text, which routinely
|
|
176
|
+
* hold export URLs, billing results, model output, recipient addresses, or
|
|
177
|
+
* internal stack detail. Serving that unauthenticated turns a job id into a
|
|
178
|
+
* read primitive over other tenants' work.
|
|
179
|
+
*
|
|
180
|
+
* Enable it deliberately, with a permission check:
|
|
181
|
+
*
|
|
182
|
+
* ```ts
|
|
183
|
+
* managementRoutes: { operatorPermission: requireRoles(["platform-ops"]) }
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* Queue-level counts are also available through the metrics/health
|
|
187
|
+
* integration, which does not expose individual jobs.
|
|
188
|
+
*/
|
|
189
|
+
managementRoutes?: false | {
|
|
190
|
+
/**
|
|
191
|
+
* REQUIRED — arc will not mount an unguarded management surface.
|
|
192
|
+
*
|
|
193
|
+
* **This is an OPERATOR surface, not a tenant-facing one.** A BullMQ job
|
|
194
|
+
* carries no framework-level tenant identity, and `getStatus` fetches
|
|
195
|
+
* straight by queue + id, so a row-level `policy` on the decision has
|
|
196
|
+
* nothing to filter: `requireOrgRole("manager")` would let a manager in
|
|
197
|
+
* org A read a known job handle from org B. `/stats` is inherently
|
|
198
|
+
* global for the same reason.
|
|
199
|
+
*
|
|
200
|
+
* Gate it on an operator role — `requireRoles(["platform-ops"])` — and
|
|
201
|
+
* keep tenant-facing job status in a resource that owns its own row
|
|
202
|
+
* policy. Arc REFUSES a request whose decision carries a `policy`
|
|
203
|
+
* rather than silently ignoring it.
|
|
204
|
+
*/
|
|
205
|
+
operatorPermission: PermissionCheck;
|
|
206
|
+
/**
|
|
207
|
+
* Accept an `operatorPermission` that arc cannot prove is platform-only.
|
|
208
|
+
*
|
|
209
|
+
* By default the gate must carry `_platformOnly` (i.e. come from
|
|
210
|
+
* `requirePlatformRole`), because that property is unprovable from
|
|
211
|
+
* outside: `requireOrgRole("manager")` and the default
|
|
212
|
+
* `requireRoles(["ops"])` both return a bare allow with no policy, so a
|
|
213
|
+
* manager in org A passes and reads a known handle from org B. Boot fails
|
|
214
|
+
* rather than serving a surface whose guard reads as tenant-scoped.
|
|
215
|
+
*
|
|
216
|
+
* Set this only for a custom check you have verified consults platform
|
|
217
|
+
* identity alone.
|
|
218
|
+
*/
|
|
219
|
+
allowUnverifiedOperatorPermission?: boolean;
|
|
220
|
+
/** Include the handler's return value in a status response. Default `false`. */
|
|
221
|
+
exposeResult?: boolean;
|
|
222
|
+
/** Include `failedReason` in a status response. Default `false`. */
|
|
223
|
+
exposeFailureReason?: boolean;
|
|
224
|
+
};
|
|
180
225
|
/** Bridge job events to Arc's event bus (default: true) */
|
|
181
226
|
bridgeEvents?: boolean;
|
|
182
227
|
/** Default job options applied to all jobs */
|
|
@@ -192,19 +237,30 @@ interface JobsPluginOptions {
|
|
|
192
237
|
};
|
|
193
238
|
}
|
|
194
239
|
interface JobDispatcher {
|
|
195
|
-
dispatch<TData = unknown>(name: string, data: TData, options?: JobDispatchOptions): Promise<
|
|
196
|
-
jobId: string;
|
|
197
|
-
}>;
|
|
240
|
+
dispatch<TData = unknown>(name: string, data: TData, options?: JobDispatchOptions): Promise<JobHandle>;
|
|
198
241
|
getQueue(name: string): unknown | null;
|
|
199
242
|
getStats(): Promise<Record<string, QueueStats>>;
|
|
200
243
|
/**
|
|
201
244
|
* Fetch a point-in-time status snapshot for a job by its ID.
|
|
202
|
-
*
|
|
203
|
-
*
|
|
245
|
+
* QUEUE-QUALIFIED: BullMQ job ids are local to their queue, so an id alone
|
|
246
|
+
* cannot identify a job. `dispatch()` returns the queue name alongside the id
|
|
247
|
+
* for exactly this reason.
|
|
248
|
+
*
|
|
249
|
+
* Returns `null` if the queue is not registered, or the job doesn't exist /
|
|
250
|
+
* has been removed by retention policy.
|
|
204
251
|
*/
|
|
205
|
-
getStatus(jobId: string): Promise<JobStatus | null>;
|
|
252
|
+
getStatus(queue: string, jobId: string): Promise<JobStatus | null>;
|
|
206
253
|
close(): Promise<void>;
|
|
207
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* A dispatched job's address. The queue is part of the identity because BullMQ
|
|
257
|
+
* ids are queue-local — two queues can both hold `"123"`.
|
|
258
|
+
*/
|
|
259
|
+
interface JobHandle {
|
|
260
|
+
/** Registered job name (= queue name). */
|
|
261
|
+
queue: string;
|
|
262
|
+
jobId: string;
|
|
263
|
+
}
|
|
208
264
|
interface QueueStats {
|
|
209
265
|
waiting: number;
|
|
210
266
|
active: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { i as
|
|
1
|
+
|
|
2
|
+
import { r as CacheStore, t as CacheLogger } from "./interface-BOk3YnTz.mjs";
|
|
3
|
+
import { i as RequestScope, n as Mandate } from "./types-ChuShpCP.mjs";
|
|
4
|
+
import { i as PermissionContext, r as PermissionCheck, t as AuthorizationDecision } from "./types-B7XeLEgK.mjs";
|
|
4
5
|
import { FastifyReply, FastifyRequest } from "fastify";
|
|
5
6
|
//#region src/permissions/agent.d.ts
|
|
6
7
|
/**
|
|
@@ -162,7 +163,7 @@ interface RequireAgentScopeOptions<TDoc = Record<string, unknown>> extends Requi
|
|
|
162
163
|
*/
|
|
163
164
|
declare function requireAgentScope<TDoc = Record<string, unknown>>(opts: RequireAgentScopeOptions<TDoc>): PermissionCheck<TDoc>;
|
|
164
165
|
//#endregion
|
|
165
|
-
//#region src/permissions/
|
|
166
|
+
//#region src/permissions/authorizationDecision.d.ts
|
|
166
167
|
/**
|
|
167
168
|
* A permission check returns either a bare boolean (terse allow/deny sugar) or
|
|
168
169
|
* a full {@link AuthorizationDecision}. There is no legacy `PermissionResult` —
|
|
@@ -222,12 +223,6 @@ type RequestSink = FastifyRequest & {
|
|
|
222
223
|
* installed (and the obligation seam lives).
|
|
223
224
|
*/
|
|
224
225
|
declare function applyAuthorizationDecision(decision: AuthorizationDecision, request: RequestSink): void;
|
|
225
|
-
/**
|
|
226
|
-
* @deprecated Renamed to {@link applyAuthorizationDecision} — the contract is an
|
|
227
|
-
* `AuthorizationDecision`, not a `PermissionResult`. This alias is kept for
|
|
228
|
-
* back-compat and will be removed in a future major.
|
|
229
|
-
*/
|
|
230
|
-
declare const applyPermissionResult: typeof applyAuthorizationDecision;
|
|
231
226
|
//#endregion
|
|
232
227
|
//#region src/permissions/context.d.ts
|
|
233
228
|
/**
|
|
@@ -307,6 +302,24 @@ declare function requireRoles(roles: readonly string[], options?: {
|
|
|
307
302
|
*/
|
|
308
303
|
includeOrgRoles?: boolean;
|
|
309
304
|
}): PermissionCheck;
|
|
305
|
+
/**
|
|
306
|
+
* Require a PLATFORM role — global roles only. An organization role can never
|
|
307
|
+
* satisfy this gate.
|
|
308
|
+
*
|
|
309
|
+
* `requireRoles(["ops"])` also accepts an ORG role named `ops` (that is its
|
|
310
|
+
* documented default), and `requireOrgRole("manager")` grants ANY organization's
|
|
311
|
+
* manager. Both return a bare allow with no policy, so a surface that is global
|
|
312
|
+
* by construction — a queue dashboard, a cluster-wide operations endpoint —
|
|
313
|
+
* cannot distinguish them from a real operator gate by looking at the decision.
|
|
314
|
+
* That makes "platform-only" a property the check has to DECLARE, which is what
|
|
315
|
+
* `_platformOnly` records and what such a surface can then require.
|
|
316
|
+
*
|
|
317
|
+
* Elevated scope passes: platform admin is the identity this gate is for.
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* permissions: { list: requirePlatformRole("platform-ops") }
|
|
321
|
+
*/
|
|
322
|
+
declare function requirePlatformRole(...args: string[] | [readonly string[]]): PermissionCheck;
|
|
310
323
|
/**
|
|
311
324
|
* Short-form alias of `requireRoles()`. Identical behavior — checks both
|
|
312
325
|
* platform roles AND org roles. Prefer `requireRoles` for new code; this
|
|
@@ -522,22 +535,45 @@ declare function createDynamicPermissionMatrix(config: DynamicPermissionMatrixCo
|
|
|
522
535
|
* - `public` — `allowPublic()`; anyone passes.
|
|
523
536
|
* - `roles` — grants if the caller holds ANY of these (platform OR org roles,
|
|
524
537
|
* unioned — matches how `requireRoles`/`requireOrgRole`/`anyOf` compose).
|
|
538
|
+
* - `scoped` — grants only within a caller SCOPE dimension (`_scopeContext`,
|
|
539
|
+
* e.g. `{ branchRole: "head_office" }`), optionally combined with `roles`. The
|
|
540
|
+
* scope dimensions are known statically even though their per-request VALUES
|
|
541
|
+
* aren't, so a consumer that holds the caller's scope (a FE that knows the
|
|
542
|
+
* active branch's role) can decide it client-side — the piece a flat `roles`
|
|
543
|
+
* requirement could not express.
|
|
525
544
|
* - `authenticated` — the check reads request-time facts (custom auth, service
|
|
526
|
-
* scope, ownership,
|
|
527
|
-
*
|
|
545
|
+
* scope, ownership, grants) that no static analysis can decide; the definitive
|
|
546
|
+
* answer is computed per request. Treat as "server decides".
|
|
528
547
|
*/
|
|
529
548
|
type PermissionRequirement = {
|
|
530
549
|
readonly kind: "public";
|
|
531
550
|
} | {
|
|
532
551
|
readonly kind: "roles";
|
|
533
552
|
readonly roles: readonly string[];
|
|
553
|
+
/**
|
|
554
|
+
* `true` when these roles are NECESSARY but not SUFFICIENT — the gate is an
|
|
555
|
+
* `allOf(...)` that also carries an opaque runtime branch (ownership /
|
|
556
|
+
* custom / dynamic / flow-mode …). A role MATCH is then `conditional`, not a
|
|
557
|
+
* definitive `allow`; a MISMATCH is still a definitive `deny`.
|
|
558
|
+
*/
|
|
559
|
+
readonly conditional?: boolean;
|
|
560
|
+
} | {
|
|
561
|
+
readonly kind: "scoped";
|
|
562
|
+
/** Required scope dimensions: `value` string = must equal; `undefined` = must be present. */
|
|
563
|
+
readonly scope: Readonly<Record<string, string | undefined>>;
|
|
564
|
+
/** Roles ALSO required alongside the scope (union of platform + org roles), if any. */
|
|
565
|
+
readonly roles?: readonly string[];
|
|
566
|
+
/** See `roles.conditional` — the composite also has an opaque/contradictory branch. */
|
|
567
|
+
readonly conditional?: boolean;
|
|
534
568
|
} | {
|
|
535
569
|
readonly kind: "authenticated";
|
|
536
570
|
};
|
|
537
571
|
/**
|
|
538
572
|
* Extract a check's static requirement from its `PermissionCheckMeta`. Public
|
|
539
|
-
* wins; then
|
|
540
|
-
*
|
|
573
|
+
* wins; then a scope-context gate (optionally with roles); then the union of
|
|
574
|
+
* platform + org roles a role gate declares; otherwise "authenticated"
|
|
575
|
+
* (auth-required / custom / request-time checks). An `allOf` that couldn't be
|
|
576
|
+
* fully captured statically carries `conditional: true` (see `_conditional`).
|
|
541
577
|
*/
|
|
542
578
|
declare function describePermission(check: PermissionCheck): PermissionRequirement;
|
|
543
579
|
/** Result of {@link explainAccess}. */
|
|
@@ -566,6 +602,8 @@ interface AccessExplanation {
|
|
|
566
602
|
declare function explainAccess(check: PermissionCheck, principal?: {
|
|
567
603
|
roles?: readonly string[];
|
|
568
604
|
orgRoles?: readonly string[];
|
|
605
|
+
/** The caller's scope-context values (e.g. `{ branchRole: "head_office" }`) — supply to decide a `scoped` gate. */
|
|
606
|
+
scope?: Readonly<Record<string, string | undefined>>;
|
|
569
607
|
}): AccessExplanation;
|
|
570
608
|
/**
|
|
571
609
|
* Introspect a whole permission map (`{ list, get, create, ... }` or any
|
|
@@ -952,4 +990,4 @@ declare function fullPublic<TDoc = Record<string, unknown>>(overrides?: Permissi
|
|
|
952
990
|
*/
|
|
953
991
|
declare function readOnly<TDoc = Record<string, unknown>>(overrides?: PermissionOverrides<TDoc>): ResourcePermissions<TDoc>;
|
|
954
992
|
//#endregion
|
|
955
|
-
export { evaluatePermissionDecision as $, explainAccess as A, anyOf as B, requireGrant as C, collectPublicSurface as D, PermissionRequirement as E, createDynamicPermissionMatrix as F, requireOwnership as G, denyAll as H, createOrgPermissions as I,
|
|
993
|
+
export { evaluatePermissionDecision as $, explainAccess as A, anyOf as B, requireGrant as C, collectPublicSurface as D, PermissionRequirement as E, createDynamicPermissionMatrix as F, requireOwnership as G, denyAll as H, createOrgPermissions as I, roles as J, requirePlatformRole as K, allOf as L, DynamicPermissionMatrix as M, DynamicPermissionMatrixConfig as N, describePermission as O, PermissionEventBus as P, applyAuthorizationDecision as Q, allow as R, modeSatisfies as S, AccessExplanation as T, not as U, deny as V, requireAuth as W, scopeOf as X, when as Y, PermissionCheckReturn as Z, createRoleHierarchy as _, permissionMatrix as a, requireMandate as at, GrantResolution as b, publicReadAdminWrite as c, requireOrgMembership as d, normalizeToDecision as et, requireOrgRole as f, RoleHierarchy as g, requireTeamMembership as h, ownerWithAdminBypass as i, requireDPoP as it, ConnectEventsOptions as j, describePermissionMap as k, readOnly as l, requireServiceScope as m, authenticated as n, RequireMandateOptions as nt, presets_d_exports as o, requireScopeContext as p, requireRoles as q, fullPublic as r, requireAgentScope as rt, publicRead as s, adminOnly as t, RequireAgentScopeOptions as tt, requireOrgInScope as u, GRANT_MODES as v, conjoinPolicyFilters as w, RequireGrantOptions as x, GrantMode as y, allowPublic as z };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
|
|
2
|
+
import { a as ModuleContribution, h as HealthCheck, n as ArcModuleInput, r as ArcModuleRegistry, t as ArcModule, u as ScheduleDefinition } from "./types-CBgvkp8O.mjs";
|
|
3
|
+
import { FastifyInstance } from "fastify";
|
|
4
|
+
//#region src/factory/module/contributions.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Collect every module's `healthChecks` in the caller's order. Fails at boot
|
|
7
|
+
* on a duplicate check `name` across modules, naming BOTH owning modules.
|
|
8
|
+
* The host's app-level checks are appended AFTER this (modules-first,
|
|
9
|
+
* host-last) by the caller.
|
|
10
|
+
*/
|
|
11
|
+
declare function collectModuleHealthChecks(modules: readonly ArcModule[]): HealthCheck[];
|
|
12
|
+
/**
|
|
13
|
+
* Collect every module's `workflows`. Resolves factory contributions (so a
|
|
14
|
+
* factory can close over a container the caller has already decorated on
|
|
15
|
+
* `fastify`) and flattens to a single opaque array. Arc core deliberately
|
|
16
|
+
* does NOT validate or interpret the values — the streamline integration
|
|
17
|
+
* owns name/shape checks and registration. Called by the integration at init
|
|
18
|
+
* time, not by arc's boot pipeline (workflows depend on the integration's
|
|
19
|
+
* container).
|
|
20
|
+
*/
|
|
21
|
+
declare function collectModuleWorkflows(fastify: FastifyInstance, modules: readonly ArcModule[]): Promise<unknown[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Collect every module's `scheduledJobs`. Resolves factory contributions
|
|
24
|
+
* (after bootstraps) and fails at boot on a duplicate job `name` across
|
|
25
|
+
* modules. The caller passes the returned definitions to the canonical
|
|
26
|
+
* schedules plugin; factories must therefore be resolved only once.
|
|
27
|
+
*/
|
|
28
|
+
declare function collectModuleScheduledJobs(fastify: FastifyInstance, modules: readonly ArcModule[]): Promise<ScheduleDefinition[]>;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/factory/module/lifecycle.d.ts
|
|
31
|
+
/**
|
|
32
|
+
* Subscribe every module's `eventHandlers` in dependency order (pass the
|
|
33
|
+
* `orderModules`-sorted list). Returns the ordered list of unsubscribe
|
|
34
|
+
* functions so the caller can tear them down at shutdown BEFORE module
|
|
35
|
+
* `onClose` (while module deps are still alive). Fails at boot on:
|
|
36
|
+
* - a duplicate NAMED handler across modules (attributing both owners);
|
|
37
|
+
* - a module declaring handlers while the event subsystem is unavailable.
|
|
38
|
+
* Resolves factory contributions (after bootstraps) so a handler can close over
|
|
39
|
+
* booted engines rather than a global getter.
|
|
40
|
+
*/
|
|
41
|
+
declare function subscribeModuleEventHandlers(fastify: FastifyInstance, modules: readonly ArcModule[]): Promise<Array<() => void | Promise<void>>>;
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/factory/module/order.d.ts
|
|
44
|
+
/**
|
|
45
|
+
* Order modules for composition by their `dependsOn` edges — a STABLE
|
|
46
|
+
* topological sort. Called once at the start of the bootstrap phase; every
|
|
47
|
+
* subsequent phase (bootstrap, resources, afterResources, and reverse-order
|
|
48
|
+
* onClose) iterates the returned list, so a module's declared dependencies are
|
|
49
|
+
* always composed before it.
|
|
50
|
+
*
|
|
51
|
+
* "Stable" = modules with no edge between them keep their original list order,
|
|
52
|
+
* so declaring `dependsOn` on one module never silently reorders an unrelated
|
|
53
|
+
* one. Backward compatible: a `modules` array with NO `dependsOn` anywhere is
|
|
54
|
+
* returned unchanged.
|
|
55
|
+
*
|
|
56
|
+
* Fail-fast — throws (never reorders past a broken contract) on:
|
|
57
|
+
* - duplicate module names (the name is the graph key)
|
|
58
|
+
* - a `dependsOn` name not present in the composed set
|
|
59
|
+
* - a self-reference (`dependsOn` includes the module's own name)
|
|
60
|
+
* - a dependency cycle (reports the concrete `a → b → … → a` path)
|
|
61
|
+
*/
|
|
62
|
+
declare function orderModules(modules: readonly ArcModule[]): ArcModule[];
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/factory/module/resolve.d.ts
|
|
65
|
+
/**
|
|
66
|
+
* Resolve any module-input form to a concrete `ArcModule`. A thunk is invoked
|
|
67
|
+
* (this is where a dynamic `import()` fires); a promise (or plain module) is
|
|
68
|
+
* awaited. Called once per module at the start of the bootstrap phase.
|
|
69
|
+
*/
|
|
70
|
+
declare function resolveModule(input: ArcModuleInput): Promise<ArcModule>;
|
|
71
|
+
/** Resolve a `ModuleContribution` to a concrete array (array passthrough or factory call). */
|
|
72
|
+
declare function resolveContribution<T>(contribution: ModuleContribution<T> | undefined, fastify: FastifyInstance): Promise<readonly T[]>;
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/factory/module/state.d.ts
|
|
75
|
+
type ModuleState = "resolved" | "bootstrapping" | "ready" | "closing" | "closed" | "failed";
|
|
76
|
+
/**
|
|
77
|
+
* Is `name` in the composed module graph? TRUE for resource-only modules and
|
|
78
|
+
* modules that exported nothing — the question `hasModuleExports()` cannot
|
|
79
|
+
* answer. FALSE before registerResources runs (no graph yet) and for
|
|
80
|
+
* uncomposed names.
|
|
81
|
+
*/
|
|
82
|
+
declare function hasModule(fastify: FastifyInstance, name: string): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* The module's current lifecycle state, or `undefined` when the module is not
|
|
85
|
+
* composed (or no graph has been composed on this instance). See the state
|
|
86
|
+
* machine in the file header.
|
|
87
|
+
*/
|
|
88
|
+
declare function getModuleState(fastify: FastifyInstance, name: string): ModuleState | undefined;
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/factory/module/index.d.ts
|
|
91
|
+
/**
|
|
92
|
+
* Identity helper for authoring a typed module — mirrors `defineResource`.
|
|
93
|
+
* Gives inference + a single obvious construction site; does no work.
|
|
94
|
+
*
|
|
95
|
+
* `TExports` is inferred from the `bootstrap` return value, so a module
|
|
96
|
+
* author gets a typed public export for free:
|
|
97
|
+
*
|
|
98
|
+
* ```ts
|
|
99
|
+
* export const accountingModule = (deps: Deps) =>
|
|
100
|
+
* defineModule({
|
|
101
|
+
* name: "accounting",
|
|
102
|
+
* bootstrap: async () => createAccountingEngine(deps), // TExports inferred
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
declare function defineModule<TExports = unknown>(module: ArcModule<TExports>): ArcModule<TExports>;
|
|
107
|
+
/**
|
|
108
|
+
* Typed accessor for a module's public export (its `bootstrap` return value),
|
|
109
|
+
* recorded at `fastify.arc.modules[name]`.
|
|
110
|
+
*
|
|
111
|
+
* Throwing, in line with the fail-fast contract (and `requireOrgId`-style
|
|
112
|
+
* accessors): a missing entry means the module either isn't composed, is
|
|
113
|
+
* composed AFTER the caller (list order = init order), or returned nothing —
|
|
114
|
+
* all wiring bugs that must surface at boot, not as `undefined` downstream.
|
|
115
|
+
*
|
|
116
|
+
* The type parameter is an assertion, not a proof. Two ways to type it:
|
|
117
|
+
* - augment `ArcModuleRegistry` once — then the name alone infers the type:
|
|
118
|
+
* `getModuleExports(f, "accounting")` → `AccountingEngine`.
|
|
119
|
+
* - or pass it inline: `getModuleExports<AccountingEngine>(f, "accounting")`.
|
|
120
|
+
*
|
|
121
|
+
* Siblings, for the two shapes this one is wrong for:
|
|
122
|
+
* - `getOptionalModuleExports` — the module is genuinely OPTIONAL.
|
|
123
|
+
* - `lazyModuleExports` / `lazyRequiredModuleExports` — the read happens at
|
|
124
|
+
* composition time, where boot order decides the answer.
|
|
125
|
+
*/
|
|
126
|
+
declare function getModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K];
|
|
127
|
+
declare function getModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports;
|
|
128
|
+
/**
|
|
129
|
+
* Non-throwing sibling of `getModuleExports`: `undefined` when the module is
|
|
130
|
+
* not composed (or has not bootstrapped yet).
|
|
131
|
+
*
|
|
132
|
+
* Exists because OPTIONAL sibling modules are a first-class composition shape —
|
|
133
|
+
* a deployment that turns `inventory` off still sells services, so its POS
|
|
134
|
+
* module must ask "is inventory here?" rather than fail-fast. Hosts were
|
|
135
|
+
* spelling that question as
|
|
136
|
+
*
|
|
137
|
+
* ```ts
|
|
138
|
+
* (fastify as unknown as { arc?: { modules?: Record<string, unknown> } })
|
|
139
|
+
* .arc?.modules?.inventory;
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* — a double cast that (a) defeats `ArcModuleRegistry` inference, (b) silently
|
|
143
|
+
* survives a typo in the module name, and (c) is impossible to grep for. Use
|
|
144
|
+
* `getModuleExports` when the dependency is REQUIRED (boot must fail), this
|
|
145
|
+
* when it is genuinely optional.
|
|
146
|
+
*
|
|
147
|
+
* Prefer `lazyModuleExports` whenever the read happens at COMPOSITION time —
|
|
148
|
+
* see its doc for why a value read once can latch `undefined` forever.
|
|
149
|
+
*/
|
|
150
|
+
declare function getOptionalModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K] | undefined;
|
|
151
|
+
declare function getOptionalModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Is a module's public export recorded yet? The predicate form of
|
|
154
|
+
* `getOptionalModuleExports`, for readiness gates (`ready: () => ...`) that
|
|
155
|
+
* should not have to reason about falsy-but-present exports.
|
|
156
|
+
*/
|
|
157
|
+
declare function hasModuleExports(fastify: FastifyInstance, name: string): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* A DEFERRED reader of a sibling module's export: returns a getter that reads
|
|
160
|
+
* the registry at CALL time, not now.
|
|
161
|
+
*
|
|
162
|
+
* ── Why this exists (the bug it removes) ─────────────────────────────────────
|
|
163
|
+
*
|
|
164
|
+
* Module composition runs bootstraps in dependency/list order, but a lot of
|
|
165
|
+
* wiring is *registered* earlier than it *runs*: an `eventHandlers` factory, a
|
|
166
|
+
* bridge accessor handed to another module, a hook added during bootstrap and
|
|
167
|
+
* fired per request. Such a factory can execute BEFORE the sibling it needs has
|
|
168
|
+
* bootstrapped — so a sibling engine captured into a local at that moment is
|
|
169
|
+
* `undefined`, and stays `undefined` for the life of the process even though the
|
|
170
|
+
* sibling came up milliseconds later.
|
|
171
|
+
*
|
|
172
|
+
* That failure is SILENT by construction: the consumer sees a null bridge and
|
|
173
|
+
* treats it as "this deployment has no inventory / no revenue engine", which is
|
|
174
|
+
* a legitimate configuration. Real cost in this codebase: orders were created
|
|
175
|
+
* and never payment-confirmed (no entitlement, no card, no door) and nothing
|
|
176
|
+
* errored anywhere.
|
|
177
|
+
*
|
|
178
|
+
* The getter therefore:
|
|
179
|
+
* - re-reads while the module is ABSENT, so boot order cannot matter;
|
|
180
|
+
* - memoizes the FIRST resolved value, so the steady-state read is a closure
|
|
181
|
+
* variable rather than a registry lookup per request;
|
|
182
|
+
* - never memoizes absence — that is precisely the latch this replaces.
|
|
183
|
+
*
|
|
184
|
+
* ```ts
|
|
185
|
+
* const inventory = lazyModuleExports<FlowEngine>(fastify, "inventory");
|
|
186
|
+
* return {
|
|
187
|
+
* flowBridge: () => (inventory() ? createFlowEngineBridge({ getFlowEngine: () => inventory()! }) : null),
|
|
188
|
+
* ready: () => inventory() !== undefined,
|
|
189
|
+
* };
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
declare function lazyModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): () => ArcModuleRegistry[K] | undefined;
|
|
193
|
+
declare function lazyModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): () => TExports | undefined;
|
|
194
|
+
/**
|
|
195
|
+
* Required counterpart of `lazyModuleExports`: defers the read, then throws
|
|
196
|
+
* `getModuleExports`' error if the module is still absent at first use.
|
|
197
|
+
*
|
|
198
|
+
* The pair matters because "required" and "readable now" are different
|
|
199
|
+
* questions. A hook registered at bootstrap that needs the `order` engine at
|
|
200
|
+
* REQUEST time is a hard dependency, but reading it eagerly turns a correct
|
|
201
|
+
* composition into a boot crash purely because of list order. Deferring keeps
|
|
202
|
+
* the fail-fast guarantee and moves it to the first moment the answer is
|
|
203
|
+
* actually needed.
|
|
204
|
+
*
|
|
205
|
+
* Deferred does NOT mean unvalidated: a lazily-required module is still a
|
|
206
|
+
* HARD dependency, so PRESENCE is checked eagerly. When the composed module
|
|
207
|
+
* graph is known (any `createApp`/`registerResources` boot — the normal
|
|
208
|
+
* case), a name that is not in the graph throws HERE, at composition time,
|
|
209
|
+
* instead of surviving startup and failing on the first request or event.
|
|
210
|
+
* Only the EXPORT read (does bootstrap's return value exist yet?) is
|
|
211
|
+
* deferred to first call.
|
|
212
|
+
*
|
|
213
|
+
* Convention for hard sibling access: also declare the target in the
|
|
214
|
+
* consumer's `dependsOn`. That orders composition (the sibling's bootstrap
|
|
215
|
+
* runs first), while this accessor merely defers the read — the two are
|
|
216
|
+
* complementary, not alternatives:
|
|
217
|
+
* - hard dependency, read during bootstrap → `dependsOn` + `getModuleExports`
|
|
218
|
+
* - hard dependency, read at request/event time → `dependsOn` + this
|
|
219
|
+
* - optional integration → `lazyModuleExports` (no `dependsOn` needed)
|
|
220
|
+
*/
|
|
221
|
+
declare function lazyRequiredModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): () => ArcModuleRegistry[K];
|
|
222
|
+
declare function lazyRequiredModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): () => TExports;
|
|
223
|
+
//#endregion
|
|
224
|
+
export { lazyModuleExports as a, getModuleState as c, resolveModule as d, orderModules as f, collectModuleWorkflows as g, collectModuleScheduledJobs as h, hasModuleExports as i, hasModule as l, collectModuleHealthChecks as m, getModuleExports as n, lazyRequiredModuleExports as o, subscribeModuleEventHandlers as p, getOptionalModuleExports as r, ModuleState as s, defineModule as t, resolveContribution as u };
|