@classytic/arc 2.15.3 → 2.16.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/README.md +1 -0
- package/bin/arc.js +12 -0
- package/dist/{BaseController-dx3m2J8V.mjs → BaseController-DlCCTIxJ.mjs} +61 -19
- package/dist/{HookSystem-Iiebom92.mjs → HookSystem-Cmf7-Etp.mjs} +8 -4
- package/dist/{QueryCache-D41bfdBB.d.mts → QueryCache-SvmT_9ti.d.mts} +1 -1
- package/dist/{ResourceRegistry-CTERg_2x.mjs → ResourceRegistry-f48hFk3m.mjs} +52 -9
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +4 -2
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +4 -4
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi--M_i87dQ.mjs → betterAuthOpenApi-ClWxaceA.mjs} +10 -6
- package/dist/buildHandler-BZX6zzDM.mjs +300 -0
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/{caching-SM8gghN6.mjs → caching-TeHE8G-v.mjs} +1 -1
- package/dist/cli/commands/describe.d.mts +35 -1
- package/dist/cli/commands/describe.mjs +52 -12
- package/dist/cli/commands/docs.d.mts +1 -4
- package/dist/cli/commands/docs.mjs +4 -16
- package/dist/cli/commands/generate.d.mts +2 -20
- package/dist/cli/commands/generate.mjs +1 -546
- package/dist/cli/commands/init.d.mts +2 -40
- package/dist/cli/commands/init.mjs +1 -3036
- package/dist/cli/commands/introspect.mjs +53 -64
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/{constants-Cxde4rpC.mjs → constants-TrJVIJl0.mjs} +7 -0
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/{core-CvmOqEms.mjs → core-DBJ_j6rX.mjs} +222 -44
- package/dist/createActionRouter-DUpN3Dd1.mjs +288 -0
- package/dist/{createAggregationRouter-B0bPDf5b.mjs → createAggregationRouter-Dq-TUCuY.mjs} +3 -2
- package/dist/{createApp-PFegs47-.mjs → createApp-DNccuhyI.mjs} +16 -14
- package/dist/{defineEvent-D5h7EvAx.mjs → defineEvent-DRwY0fYm.mjs} +1 -1
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{errorHandler-Bk-AGhkU.mjs → errorHandler-DpoXQHZ9.mjs} +17 -14
- package/dist/errors-C1lX_jlm.d.mts +91 -0
- package/dist/{eventPlugin-CaKTYkYM.mjs → eventPlugin-C2cGqtRO.mjs} +1 -1
- package/dist/{eventPlugin-qXpqTebY.d.mts → eventPlugin-CtHC_av1.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +5 -5
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +2 -2
- package/dist/{fields-COhcH3fk.d.mts → fields-Anj0xdih.d.mts} +1 -1
- package/dist/generate-BWFwgcCM.d.mts +38 -0
- package/dist/generate-CYac-OLv.mjs +654 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +2 -2
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-BTqLEvhu.d.mts → index-3oIimXQn.d.mts} +12 -12
- package/dist/{index-BstGxcc3.d.mts → index-B-ulKx5P.d.mts} +55 -4
- package/dist/{index-BswOSJCE.d.mts → index-CkW0flkU.d.mts} +355 -16
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -8
- package/dist/init-Dv71MsJr.d.mts +71 -0
- package/dist/init-HDvoO9L5.mjs +3098 -0
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/jobs.mjs +3 -3
- package/dist/integrations/mcp/index.d.mts +239 -7
- package/dist/integrations/mcp/index.mjs +2 -528
- package/dist/integrations/mcp/testing.d.mts +2 -2
- package/dist/integrations/mcp/testing.mjs +6 -10
- package/dist/integrations/streamline.d.mts +71 -2
- package/dist/integrations/streamline.mjs +81 -8
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +1 -0
- package/dist/loadResourcesFromEntry-BLMEI2Xa.mjs +51 -0
- package/dist/{resourceToTools-tFYUNmM0.mjs → mcpPlugin-7vGV51ED.mjs} +1021 -318
- package/dist/{memory-UBydS5ku.mjs → memory-QOLe11D5.mjs} +2 -0
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/{openapi-BHXhoX8O.mjs → openapi-34T9yNwd.mjs} +47 -36
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +1 -1
- package/dist/{permissions-ohQyv50e.mjs → permissions-CTxMrreC.mjs} +2 -2
- package/dist/{pipe-Zr0KXjQe.mjs → pipe-DiCyvyPN.mjs} +1 -0
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +5 -5
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +5 -5
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{pluralize-DQgqgifU.mjs → pluralize-B9M8xvy-.mjs} +2 -1
- package/dist/presets/filesUpload.d.mts +4 -4
- package/dist/presets/filesUpload.mjs +2 -2
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +4 -3
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-BbkjdPeH.mjs → presets-C9BE6WaZ.mjs} +2 -2
- package/dist/{queryCachePlugin-m1XsgAIJ.mjs → queryCachePlugin-B4XMSSe7.mjs} +2 -2
- package/dist/{queryCachePlugin-CqMdLI2-.d.mts → queryCachePlugin-Biqzfbi5.d.mts} +2 -2
- package/dist/{redis-DiMkdHEl.d.mts → redis-Cyzrz6SX.d.mts} +1 -1
- package/dist/{redis-stream-D6HzR1Z_.d.mts → redis-stream-DT-YjzrB.d.mts} +1 -1
- package/dist/registry/index.d.mts +319 -2
- package/dist/registry/index.mjs +3 -3
- package/dist/registry-BBE23CDj.mjs +576 -0
- package/dist/{routerShared-DrOa-26E.mjs → routerShared-CZV5aabX.mjs} +3 -3
- package/dist/scope/index.d.mts +3 -3
- package/dist/scope/index.mjs +3 -3
- package/dist/{sse-Bz-5ZeTt.mjs → sse-BY6sTy4P.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +16 -7
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-C_s5moIu.mjs → types-Bi0r0vjG.mjs} +53 -1
- package/dist/{types-BQsjgQzS.d.mts → types-BsJMEQ4D.d.mts} +106 -12
- package/dist/{types-DrBaUwyV.d.mts → types-D-fYtKjb.d.mts} +33 -10
- package/dist/{types-CTYvcwHe.d.mts → types-DVfpSfx2.d.mts} +42 -1
- package/dist/utils/index.d.mts +1286 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/{utils-_h9B3c57.mjs → utils-DC5ycPfr.mjs} +89 -40
- package/dist/{buildHandler-CcFOpJLh.mjs → validate-By96rH0r.mjs} +8 -299
- package/dist/{versioning-hmkPcDlX.d.mts → versioning-ZwX9tmbS.d.mts} +1 -1
- package/package.json +22 -29
- package/skills/arc/SKILL.md +299 -689
- package/skills/arc/references/auth.md +19 -7
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/arc-cheatsheet.md +100 -322
- package/dist/createActionRouter-S3MLVYot.mjs +0 -220
- package/dist/index-bRjYu21O.d.mts +0 -1320
- package/dist/org/index.d.mts +0 -66
- package/dist/org/index.mjs +0 -486
- package/dist/org/types.d.mts +0 -82
- package/dist/org/types.mjs +0 -1
- package/dist/registry-I-ogLgL9.mjs +0 -46
- /package/dist/{EventTransport-CT_52aWU.d.mts → EventTransport-C-2oAHtw.d.mts} +0 -0
- /package/dist/{EventTransport-DLWoUMHy.mjs → EventTransport-Hxvv5QQz.mjs} +0 -0
- /package/dist/{actionPermissions-CyUkQu6O.mjs → actionPermissions-Bjmvn7Eb.mjs} +0 -0
- /package/dist/{elevation-BXOWoGCF.d.mts → elevation-0YBpa663.d.mts} +0 -0
- /package/dist/{elevation-DgoeTyfX.mjs → elevation-Dci0AYLT.mjs} +0 -0
- /package/dist/{errorHandler-DFr45ZG4.d.mts → errorHandler-mHuyWzZE.d.mts} +0 -0
- /package/dist/{externalPaths-BD5nw6St.d.mts → externalPaths-DFg-2KTp.d.mts} +0 -0
- /package/dist/{interface-beEtJyWM.d.mts → interface-CH0OQudo.d.mts} +0 -0
- /package/dist/{interface-DfLGcus7.d.mts → interface-NwJ_qPlY.d.mts} +0 -0
- /package/dist/{keys-CGcCbNyu.mjs → keys-DopsCuyQ.mjs} +0 -0
- /package/dist/{loadResources-DBMQg_Aj.mjs → loadResources-ChQEj8ih.mjs} +0 -0
- /package/dist/{metrics-Qnvwc-LQ.mjs → metrics-TuOmguhi.mjs} +0 -0
- /package/dist/{replyHelpers-CK-FNO8E.mjs → replyHelpers-C-gD32oF.mjs} +0 -0
- /package/dist/{schemaIR-lYhC2gE5.mjs → schemaIR-Ctc89DSn.mjs} +0 -0
- /package/dist/{sessionManager-C4Le_UB3.d.mts → sessionManager-BqFegc0W.d.mts} +0 -0
- /package/dist/{storage-Dfzt4VTl.d.mts → storage-D2KZJAmn.d.mts} +0 -0
- /package/dist/{store-helpers-BkIN9-vu.mjs → store-helpers-B0sunfZZ.mjs} +0 -0
- /package/dist/{tracing-QJVprktp.d.mts → tracing-Dm8n7Cnn.d.mts} +0 -0
- /package/dist/{versioning-BUrT5aP4.mjs → versioning-B6mimogM.mjs} +0 -0
- /package/dist/{websocket-ChC2rqe1.d.mts → websocket-BkjeGZRn.d.mts} +0 -0
|
@@ -1,8 +1,325 @@
|
|
|
1
|
-
import { R as RegisterOptions, k as IntrospectionPluginOptions, z as ResourceRegistry } from "../index-
|
|
1
|
+
import { J as CrudRouteKey, R as RegisterOptions, V as ResourceDefinition, at as ResolvedTenantPurge, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-CkW0flkU.mjs";
|
|
2
2
|
import { FastifyPluginAsync } from "fastify";
|
|
3
|
+
import { TenantPurgeProgress, TenantPurgeStrategy } from "@classytic/repo-core/repository";
|
|
3
4
|
|
|
5
|
+
//#region src/registry/assertNoTenantData.d.ts
|
|
6
|
+
interface AssertNoTenantDataOptions {
|
|
7
|
+
readonly organizationId: string;
|
|
8
|
+
/**
|
|
9
|
+
* Limit the check to a subset of resources. Default: every cascading
|
|
10
|
+
* resource (matches the cascade runner's filter).
|
|
11
|
+
*/
|
|
12
|
+
readonly only?: readonly string[];
|
|
13
|
+
/**
|
|
14
|
+
* Skip resources whose strategy is `anonymize` (the rows legitimately
|
|
15
|
+
* remain). Default `true` — the smoke test focuses on "did data leave?"
|
|
16
|
+
* not "did anonymize keep rows?". Set `false` for a full pass.
|
|
17
|
+
*/
|
|
18
|
+
readonly skipAnonymize?: boolean;
|
|
19
|
+
}
|
|
20
|
+
interface TenantDataLeak {
|
|
21
|
+
readonly resource: string;
|
|
22
|
+
readonly tenantField: string;
|
|
23
|
+
readonly strategy: TenantPurgeStrategy["type"];
|
|
24
|
+
readonly expected: number;
|
|
25
|
+
readonly actual: number;
|
|
26
|
+
readonly reason?: string;
|
|
27
|
+
}
|
|
28
|
+
interface AssertNoTenantDataReport {
|
|
29
|
+
readonly ok: boolean;
|
|
30
|
+
readonly organizationId: string;
|
|
31
|
+
readonly checked: number;
|
|
32
|
+
readonly skipped: readonly {
|
|
33
|
+
resource: string;
|
|
34
|
+
reason: string;
|
|
35
|
+
}[];
|
|
36
|
+
readonly leaks: readonly TenantDataLeak[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Walk every cascading resource, run a tenant-scoped count, compare
|
|
40
|
+
* against the strategy's expected outcome.
|
|
41
|
+
*
|
|
42
|
+
* Designed for use inside compliance tests:
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { assertNoTenantData } from '@classytic/arc/registry';
|
|
46
|
+
*
|
|
47
|
+
* it('after org delete, no tenant data leaks', async () => {
|
|
48
|
+
* await cascadeDeleteForOrganization(arc.registry, { organizationId: 'test-org' });
|
|
49
|
+
* const report = await assertNoTenantData(arc.registry, { organizationId: 'test-org' });
|
|
50
|
+
* expect(report.ok).toBe(true);
|
|
51
|
+
* expect(report.leaks).toHaveLength(0);
|
|
52
|
+
* });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
declare function assertNoTenantData(registry: ResourceRegistry, options: AssertNoTenantDataOptions): Promise<AssertNoTenantDataReport>;
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/registry/purgeResource.d.ts
|
|
58
|
+
/**
|
|
59
|
+
* Outcome for one resource. Wider than `TenantPurgeResult` because it
|
|
60
|
+
* carries the resource name + tenantField for the aggregate report,
|
|
61
|
+
* and a `path` discriminator so audit consumers can tell which code
|
|
62
|
+
* path ran.
|
|
63
|
+
*/
|
|
64
|
+
interface PurgeResourceOutcome {
|
|
65
|
+
readonly resource: string;
|
|
66
|
+
readonly tenantField: string;
|
|
67
|
+
readonly strategy: TenantPurgeStrategy["type"];
|
|
68
|
+
readonly processed: number;
|
|
69
|
+
readonly ok: boolean;
|
|
70
|
+
readonly path: "purgeByField" | "legacy-deleteMany" | "skipped" | "unsupported";
|
|
71
|
+
readonly skipReason?: string;
|
|
72
|
+
readonly error?: {
|
|
73
|
+
code?: string;
|
|
74
|
+
message: string;
|
|
75
|
+
};
|
|
76
|
+
readonly durationMs?: number;
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/registry/cascadeOrgDelete.d.ts
|
|
80
|
+
/**
|
|
81
|
+
* Per-resource result row. One entry for every resource Arc attempted to
|
|
82
|
+
* cascade-delete for the given org. `deletedCount: -1` means the adapter
|
|
83
|
+
* doesn't surface a row count (the delete still ran).
|
|
84
|
+
*/
|
|
85
|
+
interface CascadeResourceReport {
|
|
86
|
+
readonly resource: string;
|
|
87
|
+
readonly tenantField: string;
|
|
88
|
+
/**
|
|
89
|
+
* Rows processed. For `hard` strategy this equals rows that no longer
|
|
90
|
+
* exist; for `soft`/`anonymize` it's rows touched (still present).
|
|
91
|
+
* `-1` only on legacy `deleteMany` adapters that don't surface a count.
|
|
92
|
+
*/
|
|
93
|
+
readonly deletedCount: number;
|
|
94
|
+
/**
|
|
95
|
+
* Strategy that actually ran for this resource — `'hard'` / `'soft'` /
|
|
96
|
+
* `'anonymize'` / `'skip'`. Audit consumers branch on this to answer
|
|
97
|
+
* "did data physically leave the system?".
|
|
98
|
+
*/
|
|
99
|
+
readonly strategy?: TenantPurgeStrategy["type"];
|
|
100
|
+
/**
|
|
101
|
+
* Where the strategy came from — `'declared'` (host wrote
|
|
102
|
+
* `onTenantDelete`) or `'disabled'` (filtered out before reaching
|
|
103
|
+
* this report). Future sources may be added; treat the field as a
|
|
104
|
+
* read-only audit signal.
|
|
105
|
+
*/
|
|
106
|
+
readonly strategySource?: ResolvedTenantPurge["source"];
|
|
107
|
+
/**
|
|
108
|
+
* Code path that executed — `'purgeByField'` (preferred, chunked),
|
|
109
|
+
* `'legacy-deleteMany'` (single-shot fallback for old adapters),
|
|
110
|
+
* `'skipped'` (skip strategy), `'unsupported'` (adapter can't run
|
|
111
|
+
* the declared strategy — surfaces in `failures`).
|
|
112
|
+
*/
|
|
113
|
+
readonly path?: PurgeResourceOutcome["path"];
|
|
114
|
+
/** Echoed for `skip` strategy — the declared reason. */
|
|
115
|
+
readonly skipReason?: string;
|
|
116
|
+
readonly error?: {
|
|
117
|
+
code?: string;
|
|
118
|
+
message: string;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** Aggregate report — splits successful and failed resources for the caller. */
|
|
122
|
+
interface CascadeReport {
|
|
123
|
+
readonly organizationId: string;
|
|
124
|
+
readonly resources: readonly CascadeResourceReport[];
|
|
125
|
+
readonly successes: readonly CascadeResourceReport[];
|
|
126
|
+
readonly failures: readonly CascadeResourceReport[];
|
|
127
|
+
readonly totalDeleted: number;
|
|
128
|
+
readonly durationMs: number;
|
|
129
|
+
}
|
|
130
|
+
/** Lightweight logger shape — `fastify.log`, `pino`, or `console` all fit. */
|
|
131
|
+
interface CascadeLogger {
|
|
132
|
+
info?: (obj: unknown, msg?: string) => void;
|
|
133
|
+
warn?: (obj: unknown, msg?: string) => void;
|
|
134
|
+
error?: (obj: unknown, msg?: string) => void;
|
|
135
|
+
}
|
|
136
|
+
interface CascadeOptions {
|
|
137
|
+
/** Organization id whose tenant-scoped rows should be deleted. */
|
|
138
|
+
readonly organizationId: string;
|
|
139
|
+
/**
|
|
140
|
+
* Skip these resources even if they declare `onTenantDelete`.
|
|
141
|
+
* Useful for stage-gated rollouts ("cascade everything except `audit_log`
|
|
142
|
+
* — we want to keep the trail").
|
|
143
|
+
*/
|
|
144
|
+
readonly skip?: readonly string[];
|
|
145
|
+
/**
|
|
146
|
+
* Resource names to LIMIT cascade to. When set, only these resources
|
|
147
|
+
* cascade — useful for partial-cleanup scripts and the test path that
|
|
148
|
+
* verifies one resource at a time.
|
|
149
|
+
*/
|
|
150
|
+
readonly only?: readonly string[];
|
|
151
|
+
/** Optional logger — info on each resource, warn/error on failures. */
|
|
152
|
+
readonly logger?: CascadeLogger;
|
|
153
|
+
/**
|
|
154
|
+
* Forwarded to each resource's `purgeByField` — emits per-chunk
|
|
155
|
+
* progress. The event includes the resource name so a single
|
|
156
|
+
* progress handler can drive a multi-resource progress UI.
|
|
157
|
+
*/
|
|
158
|
+
readonly onProgress?: (event: TenantPurgeProgress & {
|
|
159
|
+
resource: string;
|
|
160
|
+
}) => void | Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Forwarded to each resource's `purgeByField`. The runner checks
|
|
163
|
+
* between resources too — aborting mid-cascade stops the next
|
|
164
|
+
* resource from starting, in addition to stopping the currently-
|
|
165
|
+
* running purge between chunks.
|
|
166
|
+
*/
|
|
167
|
+
readonly signal?: AbortSignal;
|
|
168
|
+
/**
|
|
169
|
+
* Global override for per-resource batchSize. Per-resource declarations
|
|
170
|
+
* (`onTenantDelete.batchSize`) win when set; this is the fallback.
|
|
171
|
+
*/
|
|
172
|
+
readonly batchSize?: number;
|
|
173
|
+
/**
|
|
174
|
+
* Run up to `concurrency` resources in parallel. **Priority groups
|
|
175
|
+
* remain barriers** — all priority-10 resources finish before any
|
|
176
|
+
* priority-50 resource starts. Within a priority, resources run
|
|
177
|
+
* concurrently up to this cap. Default `1` (sequential, safest).
|
|
178
|
+
*
|
|
179
|
+
* Resources are independent (different collections / tables, no
|
|
180
|
+
* cross-resource constraints), so parallelism is safe — but oplog
|
|
181
|
+
* pressure / connection-pool exhaustion / replication lag scale with
|
|
182
|
+
* concurrency. Tune per environment; `4` is usually fine for cloud
|
|
183
|
+
* Mongo + small connection pools, `8`–`16` for high-throughput tiers.
|
|
184
|
+
*/
|
|
185
|
+
readonly concurrency?: number;
|
|
186
|
+
/**
|
|
187
|
+
* Cascade-level checkpoint — survive a crash mid-cascade and resume
|
|
188
|
+
* from the last completed resource. `read()` returns the last cascade
|
|
189
|
+
* state (or `undefined` for a fresh run); `write()` persists state
|
|
190
|
+
* after each resource completes. Hosts plumb to Redis / a status
|
|
191
|
+
* table / a dedicated checkpoint store.
|
|
192
|
+
*
|
|
193
|
+
* Per-purge checkpointing is intentionally NOT offered — the chunked
|
|
194
|
+
* primitive is already idempotent (re-running a partially-completed
|
|
195
|
+
* cascade is safe because already-deleted rows don't match the next
|
|
196
|
+
* SELECT). The cascade-level checkpoint just skips entire resources
|
|
197
|
+
* known-completed in the prior pass — wasteful round-trips, not
|
|
198
|
+
* wasteful writes.
|
|
199
|
+
*/
|
|
200
|
+
readonly checkpoint?: CascadeCheckpoint;
|
|
201
|
+
}
|
|
202
|
+
/** Cascade resume state. Persist between runs; rehydrate on retry. */
|
|
203
|
+
interface CascadeCheckpointState {
|
|
204
|
+
/** Names of resources fully completed in a prior pass. Skipped on resume. */
|
|
205
|
+
readonly completedResources: readonly string[];
|
|
206
|
+
}
|
|
207
|
+
interface CascadeCheckpoint {
|
|
208
|
+
/** Load the prior cascade state for this org. Return `undefined` for a fresh run. */
|
|
209
|
+
read(): Promise<CascadeCheckpointState | undefined>;
|
|
210
|
+
/** Persist updated state after a resource finishes. */
|
|
211
|
+
write(state: CascadeCheckpointState): Promise<void>;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Names of resources flagged for cascade — used by audit scripts.
|
|
215
|
+
* A resource is cascading when its resolved strategy isn't `disabled`
|
|
216
|
+
* (i.e. the host declared `onTenantDelete`).
|
|
217
|
+
*/
|
|
218
|
+
declare function getCascadingResources(registry: ResourceRegistry): readonly string[];
|
|
219
|
+
/**
|
|
220
|
+
* Rich introspection — returns the resolved strategy + source per
|
|
221
|
+
* cascading resource. Use for audit dashboards that answer "what
|
|
222
|
+
* happens to this resource on org-delete?" without grepping the
|
|
223
|
+
* source.
|
|
224
|
+
*/
|
|
225
|
+
declare function getCascadingResourcesWithMetadata(registry: ResourceRegistry): readonly {
|
|
226
|
+
name: string;
|
|
227
|
+
tenantField: string;
|
|
228
|
+
strategy: TenantPurgeStrategy["type"];
|
|
229
|
+
source: ResolvedTenantPurge["source"];
|
|
230
|
+
priority: number;
|
|
231
|
+
}[];
|
|
232
|
+
/**
|
|
233
|
+
* Cascade-cleanup every tenant-scoped resource for the given organization.
|
|
234
|
+
* Walks the registry in **ascending priority order** (`onTenantDelete.priority`
|
|
235
|
+
* — leaf data first, references last), runs each resource's resolved
|
|
236
|
+
* strategy via `purgeByField` when available (chunked, progress, abort),
|
|
237
|
+
* and returns a structured report.
|
|
238
|
+
*
|
|
239
|
+
* **Strategy resolution** lives in `resolveTenantPurge.ts` — this runner
|
|
240
|
+
* just reads `resource.resolvedTenantPurge` (computed once at boot).
|
|
241
|
+
*
|
|
242
|
+
* **Per-resource execution** lives in `purgeResource.ts` — preferred
|
|
243
|
+
* path is the kit's `purgeByField` (chunked + plugin-composed); falls
|
|
244
|
+
* back to legacy `deleteMany` only for `hard` strategy on adapters that
|
|
245
|
+
* haven't been upgraded.
|
|
246
|
+
*
|
|
247
|
+
* **Failure semantics**: continues on per-resource error, returns the
|
|
248
|
+
* full report. Hosts decide whether a partial cascade is a hard
|
|
249
|
+
* failure (re-throw) or degraded mode (log + alert).
|
|
250
|
+
*
|
|
251
|
+
* @param registry The arc resource registry (`fastify.arc.registry`).
|
|
252
|
+
* @param options Org id + filters + logger + progress + signal.
|
|
253
|
+
*/
|
|
254
|
+
declare function cascadeDeleteForOrganization(registry: ResourceRegistry, options: CascadeOptions): Promise<CascadeReport>;
|
|
255
|
+
//#endregion
|
|
4
256
|
//#region src/registry/introspectionPlugin.d.ts
|
|
5
257
|
declare const introspectionPlugin: FastifyPluginAsync<IntrospectionPluginOptions>;
|
|
6
258
|
declare const _default: FastifyPluginAsync<IntrospectionPluginOptions>;
|
|
7
259
|
//#endregion
|
|
8
|
-
|
|
260
|
+
//#region src/registry/manifest.d.ts
|
|
261
|
+
/** Mount-point string the FE uses to derive the URL for an action call. */
|
|
262
|
+
type ActionMount = "/:id/action" | "/action";
|
|
263
|
+
/**
|
|
264
|
+
* One action entry in a resource manifest. `requiresId` is the boolean
|
|
265
|
+
* the FE checks to decide whether its helper takes `(id, body)` or just
|
|
266
|
+
* `(body)`; `mount` is the URL suffix to append to the resource prefix.
|
|
267
|
+
*/
|
|
268
|
+
interface ActionManifestEntry {
|
|
269
|
+
readonly name: string;
|
|
270
|
+
readonly mount: ActionMount;
|
|
271
|
+
readonly requiresId: boolean;
|
|
272
|
+
readonly description?: string;
|
|
273
|
+
}
|
|
274
|
+
/** Aggregation entry — one per `defineAggregation()` declaration. */
|
|
275
|
+
interface AggregationManifestEntry {
|
|
276
|
+
readonly name: string;
|
|
277
|
+
readonly path: string;
|
|
278
|
+
readonly summary?: string;
|
|
279
|
+
readonly description?: string;
|
|
280
|
+
}
|
|
281
|
+
/** Custom (non-CRUD, non-action) route entry. */
|
|
282
|
+
interface CustomRouteManifestEntry {
|
|
283
|
+
readonly method: string;
|
|
284
|
+
readonly path: string;
|
|
285
|
+
readonly operation?: string;
|
|
286
|
+
readonly summary?: string;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Single resource manifest. Everything an FE codegen needs to wire a
|
|
290
|
+
* typed client over the resource's HTTP surface.
|
|
291
|
+
*/
|
|
292
|
+
interface ResourceManifest {
|
|
293
|
+
readonly name: string;
|
|
294
|
+
readonly displayName: string;
|
|
295
|
+
readonly prefix: string;
|
|
296
|
+
readonly idField: string;
|
|
297
|
+
/** Update method used for `/:id` PATCH / PUT routes. */
|
|
298
|
+
readonly updateMethod: "PUT" | "PATCH" | "both";
|
|
299
|
+
/** Enabled CRUD operations — filtered by `disabledRoutes` and `disableDefaultRoutes`. */
|
|
300
|
+
readonly crudOps: readonly CrudRouteKey[];
|
|
301
|
+
readonly actions: readonly ActionManifestEntry[];
|
|
302
|
+
readonly aggregations: readonly AggregationManifestEntry[];
|
|
303
|
+
readonly customRoutes: readonly CustomRouteManifestEntry[];
|
|
304
|
+
/** Tenant scoping field (when set) — surfaces for FE callers that need to send `x-organization-id`. */
|
|
305
|
+
readonly tenantField?: string | false;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Build a manifest from a `ResourceDefinition` (the value returned by
|
|
309
|
+
* `defineResource(...)`). Use at build time when you have direct access
|
|
310
|
+
* to the resource module — typically the simplest codegen path.
|
|
311
|
+
*/
|
|
312
|
+
declare function buildResourceManifest(resource: ResourceDefinition): ResourceManifest;
|
|
313
|
+
/**
|
|
314
|
+
* Build a manifest from a `RegistryEntry` — use when the resource is
|
|
315
|
+
* already registered (introspection endpoint, runtime audit script).
|
|
316
|
+
*
|
|
317
|
+
* Equivalent to {@link buildResourceManifest} but reads from the projected
|
|
318
|
+
* registry shape, so a host that doesn't have the original `defineResource`
|
|
319
|
+
* value in scope (e.g. an FE-gen sidecar that scrapes a running server's
|
|
320
|
+
* `/_resources` endpoint) gets the same output without dragging the resource
|
|
321
|
+
* module into the codegen path.
|
|
322
|
+
*/
|
|
323
|
+
declare function buildResourceManifestFromRegistry(entry: RegistryEntry): ResourceManifest;
|
|
324
|
+
//#endregion
|
|
325
|
+
export { type ActionManifestEntry, type ActionMount, type AggregationManifestEntry, type AssertNoTenantDataOptions, type AssertNoTenantDataReport, type CascadeCheckpoint, type CascadeCheckpointState, type CascadeOptions, type CascadeReport, type CascadeResourceReport, type CustomRouteManifestEntry, type IntrospectionPluginOptions, type RegisterOptions, type ResourceManifest, ResourceRegistry, type TenantDataLeak, assertNoTenantData, buildResourceManifest, buildResourceManifestFromRegistry, cascadeDeleteForOrganization, getCascadingResources, getCascadingResourcesWithMetadata, _default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
package/dist/registry/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as ResourceRegistry } from "../ResourceRegistry-
|
|
3
|
-
export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|
|
1
|
+
import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-BBE23CDj.mjs";
|
|
2
|
+
import { t as ResourceRegistry } from "../ResourceRegistry-f48hFk3m.mjs";
|
|
3
|
+
export { ResourceRegistry, assertNoTenantData, buildResourceManifest, buildResourceManifestFromRegistry, cascadeDeleteForOrganization, getCascadingResources, getCascadingResourcesWithMetadata, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
|