@futdevpro/fsm-dynamo 1.20.23 → 1.20.24

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.
@@ -0,0 +1,56 @@
1
+ import { DyFM_RequestSafetyPolicy_Interface, DyFM_RequestSafetyResult_Interface } from '../_models/request-safety.interface';
2
+ /**
3
+ * BFR-CTM-034 — cross-runtime, content-free request safety inspector.
4
+ *
5
+ * ⚠️ **What this is for:** a value is about to cross a boundary (browser → transport, or transport →
6
+ * state mutation / provider dispatch). Once it has crossed, masking it afterwards is too late — the
7
+ * value has already been serialized, stored or sent. This inspector runs BEFORE that, and answers a
8
+ * single question: *may this cross?* — without ever repeating what it saw.
9
+ *
10
+ * ⛔ **No side effects, by construction.** No logging, no network, no storage, no timers, no `Math.random`,
11
+ * no environment access. That is not stylistic: the inspector runs on hostile input, so anything it
12
+ * touched would become an attack surface, and anything it logged would re-leak the value it rejected.
13
+ * The same source therefore runs unchanged in a browser, a Worker and Node.
14
+ */
15
+ export declare class DyFM_RequestSafetyInspector_Util {
16
+ /**
17
+ * Format/invisible characters that hide a value from a naive matcher while remaining meaningful to a
18
+ * human reader or a downstream parser: zero-width space/non-joiner/joiner, word joiner, BOM, the
19
+ * bidirectional overrides, and the soft hyphen.
20
+ *
21
+ * ⭐ These are removed AFTER NFKC. NFKC alone does not drop them, so a `p​assword` key would
22
+ * still slip past a forbidden-key set that only normalizes.
23
+ */
24
+ private static readonly formatObfuscators;
25
+ /**
26
+ * Normalizes a string for matching: NFKC, then format-obfuscator removal, then case folding.
27
+ *
28
+ * ⚠️ The order matters. NFKC first folds the full-width and compatibility forms (`password`,
29
+ * `𝐩𝐚𝐬𝐬𝐰𝐨𝐫𝐝`) onto their ASCII equivalents; only then can the invisible-character strip and the
30
+ * case fold see a plain string. Reversing the steps leaves obfuscated forms unmatched.
31
+ */
32
+ static normalize(value: string): string;
33
+ /**
34
+ * Inspects `input` against a caller-owned policy.
35
+ *
36
+ * Fail-closed everywhere: an invalid policy, an unsupported value type, a hostile prototype, an
37
+ * accessor or a blown budget all DECLINE. There is no path that returns `accepted: true` because the
38
+ * inspector could not decide.
39
+ *
40
+ * @returns a content-free outcome; the input itself is never echoed in any form.
41
+ */
42
+ static inspect(input: unknown, policy: DyFM_RequestSafetyPolicy_Interface): DyFM_RequestSafetyResult_Interface;
43
+ /** A string vizsgalata: budget, kanari, tiltott ertek-mintak, nem tamogatott kepessegek. */
44
+ private static inspectString;
45
+ /**
46
+ * Egy minta-csoport illesztese, csoportonként LEGFELJEBB EGY leletet szamolva.
47
+ *
48
+ * ⚠️ A `lastIndex` szandekosan nullazva: egy `/g` flag-es minta allapotot visz magaval, es a hivo
49
+ * altal atadott, ujrahasznalt RegExp kulonben a MASODIK hivasnal mast talalna, mint az elson —
50
+ * ugyanarra a bemenetre. Ez a fajta nem-determinizmus egy biztonsagi kapunal elfogadhatatlan.
51
+ */
52
+ private static recordPatternHit;
53
+ /** A policy strukturalis ervenyessege. Barmelyik hianyzo budget = ervenytelen. */
54
+ private static isPolicyValid;
55
+ }
56
+ //# sourceMappingURL=request-safety-inspector.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-safety-inspector.util.d.ts","sourceRoot":"","sources":["../../../../src/_modules/request-safety/_collections/request-safety-inspector.util.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kCAAkC,EAAE,kCAAkC,EACvE,MAAM,qCAAqC,CAAC;AAE7C;;;;;;;;;;;;GAYG;AACH,qBAAa,gCAAgC;IAE3C;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CACkB;IAE3D;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAOvC;;;;;;;;OAQG;IACH,MAAM,CAAC,OAAO,CACZ,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,kCAAkC,GACzC,kCAAkC;IA6HrC,4FAA4F;IAC5F,OAAO,CAAC,MAAM,CAAC,aAAa;IA8B5B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAuB/B,kFAAkF;IAClF,OAAO,CAAC,MAAM,CAAC,aAAa;CAY7B"}
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyFM_RequestSafetyInspector_Util = void 0;
4
+ const request_safety_finding_type_enum_1 = require("../_enums/request-safety-finding.type-enum");
5
+ /**
6
+ * BFR-CTM-034 — cross-runtime, content-free request safety inspector.
7
+ *
8
+ * ⚠️ **What this is for:** a value is about to cross a boundary (browser → transport, or transport →
9
+ * state mutation / provider dispatch). Once it has crossed, masking it afterwards is too late — the
10
+ * value has already been serialized, stored or sent. This inspector runs BEFORE that, and answers a
11
+ * single question: *may this cross?* — without ever repeating what it saw.
12
+ *
13
+ * ⛔ **No side effects, by construction.** No logging, no network, no storage, no timers, no `Math.random`,
14
+ * no environment access. That is not stylistic: the inspector runs on hostile input, so anything it
15
+ * touched would become an attack surface, and anything it logged would re-leak the value it rejected.
16
+ * The same source therefore runs unchanged in a browser, a Worker and Node.
17
+ */
18
+ class DyFM_RequestSafetyInspector_Util {
19
+ /**
20
+ * Format/invisible characters that hide a value from a naive matcher while remaining meaningful to a
21
+ * human reader or a downstream parser: zero-width space/non-joiner/joiner, word joiner, BOM, the
22
+ * bidirectional overrides, and the soft hyphen.
23
+ *
24
+ * ⭐ These are removed AFTER NFKC. NFKC alone does not drop them, so a `p​assword` key would
25
+ * still slip past a forbidden-key set that only normalizes.
26
+ */
27
+ static formatObfuscators = /[\u00ad\u200b-\u200f\u202a-\u202e\u2060-\u2064\ufeff]/g;
28
+ /**
29
+ * Normalizes a string for matching: NFKC, then format-obfuscator removal, then case folding.
30
+ *
31
+ * ⚠️ The order matters. NFKC first folds the full-width and compatibility forms (`password`,
32
+ * `𝐩𝐚𝐬𝐬𝐰𝐨𝐫𝐝`) onto their ASCII equivalents; only then can the invisible-character strip and the
33
+ * case fold see a plain string. Reversing the steps leaves obfuscated forms unmatched.
34
+ */
35
+ static normalize(value) {
36
+ return `${value ?? ''}`
37
+ .normalize('NFKC')
38
+ .replace(DyFM_RequestSafetyInspector_Util.formatObfuscators, '')
39
+ .toLowerCase();
40
+ }
41
+ /**
42
+ * Inspects `input` against a caller-owned policy.
43
+ *
44
+ * Fail-closed everywhere: an invalid policy, an unsupported value type, a hostile prototype, an
45
+ * accessor or a blown budget all DECLINE. There is no path that returns `accepted: true` because the
46
+ * inspector could not decide.
47
+ *
48
+ * @returns a content-free outcome; the input itself is never echoed in any form.
49
+ */
50
+ static inspect(input, policy) {
51
+ const counts = {};
52
+ let inspectedNodes = 0;
53
+ const namespace = typeof policy?.namespace === 'string' ? policy.namespace.trim() : '';
54
+ const record = (finding) => {
55
+ const code = `${namespace}:${finding}`;
56
+ counts[code] = (counts[code] ?? 0) + 1;
57
+ };
58
+ if (!DyFM_RequestSafetyInspector_Util.isPolicyValid(policy)) {
59
+ // A hibas policy NEM "nincs szabaly, tehat mehet" — az a leghangosabb fail-open lenne.
60
+ const code = `${namespace || 'unknown'}:${request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.invalidPolicy}`;
61
+ return {
62
+ contractVersion: 'dyfm-request-safety/1',
63
+ accepted: false,
64
+ findingCodes: [code],
65
+ findingCounts: { [code]: 1 },
66
+ inspectedNodes: 0,
67
+ };
68
+ }
69
+ const forbiddenKeys = new Set((policy.forbiddenKeys ?? []).map((key) => DyFM_RequestSafetyInspector_Util.normalize(key)));
70
+ const canaries = (policy.canaries ?? []).map((canary) => DyFM_RequestSafetyInspector_Util.normalize(canary));
71
+ // ⚠️ A ciklus-vedelem a MEGLATOGATOTT objektumok halmaza, nem melyseg-szamlalo: egy `a.b.a`
72
+ // onhivatkozas veges melysegben is vegtelen bejarast okozna.
73
+ const seen = new Set();
74
+ const walk = (value, depth) => {
75
+ if (inspectedNodes >= policy.maxNodes) {
76
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.nodeBudget);
77
+ return;
78
+ }
79
+ inspectedNodes++;
80
+ if (depth > policy.maxDepth) {
81
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.depthBudget);
82
+ return;
83
+ }
84
+ if (value === null || typeof value === 'boolean' || typeof value === 'number') {
85
+ return;
86
+ }
87
+ if (typeof value === 'string') {
88
+ DyFM_RequestSafetyInspector_Util.inspectString(value, policy, canaries, record);
89
+ return;
90
+ }
91
+ if (typeof value === 'undefined') {
92
+ return;
93
+ }
94
+ if (typeof value !== 'object') {
95
+ // fuggveny, symbol, bigint — a kontraktus nem hordozza oket
96
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.unsupportedValueType);
97
+ return;
98
+ }
99
+ if (seen.has(value)) {
100
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.cycle);
101
+ return;
102
+ }
103
+ seen.add(value);
104
+ if (Array.isArray(value)) {
105
+ for (const item of value) {
106
+ walk(item, depth + 1);
107
+ }
108
+ return;
109
+ }
110
+ const prototype = Object.getPrototypeOf(value);
111
+ if (prototype !== Object.prototype && prototype !== null) {
112
+ // Date, Map, class-peldany, `__proto__`-val megmergezett objektum: a szerializalt alak nem
113
+ // egyezne azzal, amit itt lattunk — tehat az ellenorzes ertelmet vesztene.
114
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.unsupportedPrototype);
115
+ return;
116
+ }
117
+ for (const key of Object.getOwnPropertyNames(value)) {
118
+ if (forbiddenKeys.has(DyFM_RequestSafetyInspector_Util.normalize(key))) {
119
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.forbiddenKey);
120
+ }
121
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
122
+ if (descriptor && (descriptor.get || descriptor.set)) {
123
+ // ⛔ SOHA nem olvassuk ki: egy getter a hivo kodjat futtatna le a mi vizsgalatunk kozben.
124
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.accessor);
125
+ continue;
126
+ }
127
+ walk(descriptor?.value, depth + 1);
128
+ }
129
+ };
130
+ walk(input, 0);
131
+ const findingCodes = Object.keys(counts).sort();
132
+ return {
133
+ contractVersion: 'dyfm-request-safety/1',
134
+ accepted: findingCodes.length === 0,
135
+ findingCodes: findingCodes,
136
+ findingCounts: counts,
137
+ inspectedNodes: inspectedNodes,
138
+ };
139
+ }
140
+ /** A string vizsgalata: budget, kanari, tiltott ertek-mintak, nem tamogatott kepessegek. */
141
+ static inspectString(value, policy, canaries, record) {
142
+ const normalized = DyFM_RequestSafetyInspector_Util.normalize(value);
143
+ if (normalized.length > policy.maxStringLength) {
144
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.stringBudget);
145
+ }
146
+ for (const canary of canaries) {
147
+ if (canary.length > 0 && normalized.includes(canary)) {
148
+ record(request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.canary);
149
+ break;
150
+ }
151
+ }
152
+ DyFM_RequestSafetyInspector_Util.recordPatternHit(normalized, policy.sensitiveValuePatterns, request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.sensitiveValue, record);
153
+ DyFM_RequestSafetyInspector_Util.recordPatternHit(normalized, policy.unsupportedCapabilityPatterns, request_safety_finding_type_enum_1.DyFM_RequestSafetyFinding_Type.unsupportedCapability, record);
154
+ }
155
+ /**
156
+ * Egy minta-csoport illesztese, csoportonként LEGFELJEBB EGY leletet szamolva.
157
+ *
158
+ * ⚠️ A `lastIndex` szandekosan nullazva: egy `/g` flag-es minta allapotot visz magaval, es a hivo
159
+ * altal atadott, ujrahasznalt RegExp kulonben a MASODIK hivasnal mast talalna, mint az elson —
160
+ * ugyanarra a bemenetre. Ez a fajta nem-determinizmus egy biztonsagi kapunal elfogadhatatlan.
161
+ */
162
+ static recordPatternHit(normalized, patterns, finding, record) {
163
+ for (const pattern of patterns ?? []) {
164
+ pattern.lastIndex = 0;
165
+ const matched = pattern.test(normalized);
166
+ // ⚠️ UTANA is nullazunk: a `/g` minta a sikeres `test()` utan a talalat vegen hagyja a
167
+ // `lastIndex`-et. A hivo UGYANAZT a RegExp-peldanyt hasznalhatja mashol is — ha elmozdulva
168
+ // adnank vissza, a sajat kovetkezo `test()`-je mast talalna. A vizsgalonak a hivo allapotat
169
+ // pontosan ugy kell hagynia, ahogy kapta. (Merve: `lastIndex` 6 maradt a nullazas nelkul.)
170
+ pattern.lastIndex = 0;
171
+ if (matched) {
172
+ record(finding);
173
+ return;
174
+ }
175
+ }
176
+ }
177
+ /** A policy strukturalis ervenyessege. Barmelyik hianyzo budget = ervenytelen. */
178
+ static isPolicyValid(policy) {
179
+ if (!policy || typeof policy !== 'object') {
180
+ return false;
181
+ }
182
+ if (typeof policy.namespace !== 'string' || policy.namespace.trim().length === 0) {
183
+ return false;
184
+ }
185
+ return [policy.maxDepth, policy.maxNodes, policy.maxStringLength].every((budget) => Number.isSafeInteger(budget) && budget > 0);
186
+ }
187
+ }
188
+ exports.DyFM_RequestSafetyInspector_Util = DyFM_RequestSafetyInspector_Util;
189
+ //# sourceMappingURL=request-safety-inspector.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-safety-inspector.util.js","sourceRoot":"","sources":["../../../../src/_modules/request-safety/_collections/request-safety-inspector.util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * BFR-CTM-034 — the closed, content-free finding vocabulary.
3
+ *
4
+ * ⛔ These codes are the ONLY thing an inspection may say about *why* it declined. They deliberately
5
+ * describe the **class** of problem, never the offending value, key, path or pattern: a finding that
6
+ * echoes what it found turns a safety check into the very leak it was meant to prevent.
7
+ *
8
+ * The caller prefixes them with its own namespace, so two products can never confuse each other's
9
+ * findings while still sharing this vocabulary.
10
+ */
11
+ export declare enum DyFM_RequestSafetyFinding_Type {
12
+ /** A key matched the caller's forbidden-key set (after normalization). */
13
+ forbiddenKey = "forbidden-key",
14
+ /** A string value matched one of the caller's sensitive-value patterns. */
15
+ sensitiveValue = "sensitive-value",
16
+ /** A string value matched one of the caller's unsupported-capability patterns. */
17
+ unsupportedCapability = "unsupported-capability",
18
+ /** A caller-planted canary was found — proof that a rejected value reached the boundary. */
19
+ canary = "canary",
20
+ /** The graph contains a cycle. */
21
+ cycle = "cycle",
22
+ /** Nesting exceeded the caller's depth budget. */
23
+ depthBudget = "depth-budget",
24
+ /** The node count exceeded the caller's budget. */
25
+ nodeBudget = "node-budget",
26
+ /** A string exceeded the caller's length budget. */
27
+ stringBudget = "string-budget",
28
+ /** A property is defined by an accessor (getter/setter) — reading it could execute caller code. */
29
+ accessor = "accessor",
30
+ /** An object's prototype is neither `Object.prototype` nor `null`. */
31
+ unsupportedPrototype = "unsupported-prototype",
32
+ /** A value is of a type the contract does not carry (function, symbol, bigint, class instance…). */
33
+ unsupportedValueType = "unsupported-value-type",
34
+ /** The policy itself is invalid — fail-closed, the input is never inspected. */
35
+ invalidPolicy = "invalid-policy"
36
+ }
37
+ //# sourceMappingURL=request-safety-finding.type-enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-safety-finding.type-enum.d.ts","sourceRoot":"","sources":["../../../../src/_modules/request-safety/_enums/request-safety-finding.type-enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,oBAAY,8BAA8B;IACxC,0EAA0E;IAC1E,YAAY,kBAAkB;IAC9B,2EAA2E;IAC3E,cAAc,oBAAoB;IAClC,kFAAkF;IAClF,qBAAqB,2BAA2B;IAChD,4FAA4F;IAC5F,MAAM,WAAW;IACjB,kCAAkC;IAClC,KAAK,UAAU;IACf,kDAAkD;IAClD,WAAW,iBAAiB;IAC5B,mDAAmD;IACnD,UAAU,gBAAgB;IAC1B,oDAAoD;IACpD,YAAY,kBAAkB;IAC9B,mGAAmG;IACnG,QAAQ,aAAa;IACrB,sEAAsE;IACtE,oBAAoB,0BAA0B;IAC9C,oGAAoG;IACpG,oBAAoB,2BAA2B;IAC/C,gFAAgF;IAChF,aAAa,mBAAmB;CACjC"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyFM_RequestSafetyFinding_Type = void 0;
4
+ /**
5
+ * BFR-CTM-034 — the closed, content-free finding vocabulary.
6
+ *
7
+ * ⛔ These codes are the ONLY thing an inspection may say about *why* it declined. They deliberately
8
+ * describe the **class** of problem, never the offending value, key, path or pattern: a finding that
9
+ * echoes what it found turns a safety check into the very leak it was meant to prevent.
10
+ *
11
+ * The caller prefixes them with its own namespace, so two products can never confuse each other's
12
+ * findings while still sharing this vocabulary.
13
+ */
14
+ var DyFM_RequestSafetyFinding_Type;
15
+ (function (DyFM_RequestSafetyFinding_Type) {
16
+ /** A key matched the caller's forbidden-key set (after normalization). */
17
+ DyFM_RequestSafetyFinding_Type["forbiddenKey"] = "forbidden-key";
18
+ /** A string value matched one of the caller's sensitive-value patterns. */
19
+ DyFM_RequestSafetyFinding_Type["sensitiveValue"] = "sensitive-value";
20
+ /** A string value matched one of the caller's unsupported-capability patterns. */
21
+ DyFM_RequestSafetyFinding_Type["unsupportedCapability"] = "unsupported-capability";
22
+ /** A caller-planted canary was found — proof that a rejected value reached the boundary. */
23
+ DyFM_RequestSafetyFinding_Type["canary"] = "canary";
24
+ /** The graph contains a cycle. */
25
+ DyFM_RequestSafetyFinding_Type["cycle"] = "cycle";
26
+ /** Nesting exceeded the caller's depth budget. */
27
+ DyFM_RequestSafetyFinding_Type["depthBudget"] = "depth-budget";
28
+ /** The node count exceeded the caller's budget. */
29
+ DyFM_RequestSafetyFinding_Type["nodeBudget"] = "node-budget";
30
+ /** A string exceeded the caller's length budget. */
31
+ DyFM_RequestSafetyFinding_Type["stringBudget"] = "string-budget";
32
+ /** A property is defined by an accessor (getter/setter) — reading it could execute caller code. */
33
+ DyFM_RequestSafetyFinding_Type["accessor"] = "accessor";
34
+ /** An object's prototype is neither `Object.prototype` nor `null`. */
35
+ DyFM_RequestSafetyFinding_Type["unsupportedPrototype"] = "unsupported-prototype";
36
+ /** A value is of a type the contract does not carry (function, symbol, bigint, class instance…). */
37
+ DyFM_RequestSafetyFinding_Type["unsupportedValueType"] = "unsupported-value-type";
38
+ /** The policy itself is invalid — fail-closed, the input is never inspected. */
39
+ DyFM_RequestSafetyFinding_Type["invalidPolicy"] = "invalid-policy";
40
+ })(DyFM_RequestSafetyFinding_Type || (exports.DyFM_RequestSafetyFinding_Type = DyFM_RequestSafetyFinding_Type = {}));
41
+ //# sourceMappingURL=request-safety-finding.type-enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-safety-finding.type-enum.js","sourceRoot":"","sources":["../../../../src/_modules/request-safety/_enums/request-safety-finding.type-enum.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;GASG;AACH,IAAY,8BAyBX;AAzBD,WAAY,8BAA8B;IACxC,0EAA0E;IAC1E,gEAA8B,CAAA;IAC9B,2EAA2E;IAC3E,oEAAkC,CAAA;IAClC,kFAAkF;IAClF,kFAAgD,CAAA;IAChD,4FAA4F;IAC5F,mDAAiB,CAAA;IACjB,kCAAkC;IAClC,iDAAe,CAAA;IACf,kDAAkD;IAClD,8DAA4B,CAAA;IAC5B,mDAAmD;IACnD,4DAA0B,CAAA;IAC1B,oDAAoD;IACpD,gEAA8B,CAAA;IAC9B,mGAAmG;IACnG,uDAAqB,CAAA;IACrB,sEAAsE;IACtE,gFAA8C,CAAA;IAC9C,oGAAoG;IACpG,iFAA+C,CAAA;IAC/C,gFAAgF;IAChF,kEAAgC,CAAA;AAClC,CAAC,EAzBW,8BAA8B,8CAA9B,8BAA8B,QAyBzC"}
@@ -0,0 +1,67 @@
1
+ import { DyFM_RequestSafetyFinding_Type } from '../_enums/request-safety-finding.type-enum';
2
+ /**
3
+ * BFR-CTM-034 — the caller-owned inspection policy.
4
+ *
5
+ * ⚠️ **Every product rule lives here, not in the framework.** The bedrock deliberately does NOT decide
6
+ * that an API mention, a URL or a credential-looking string is invalid — one product forbids external
7
+ * network access, another is built on it. Hard-coding that judgement would make this primitive
8
+ * unusable for half the fleet and would silently impose one product's contract on the others.
9
+ *
10
+ * What the framework owns is the *mechanics*: normalization, cycle-safe traversal, budgets and the
11
+ * content-free outcome. What the caller owns is *what counts as unsafe*.
12
+ */
13
+ export interface DyFM_RequestSafetyPolicy_Interface {
14
+ /**
15
+ * Stable caller namespace, prefixed onto every finding code (e.g. `ctm-r5`).
16
+ *
17
+ * Two products can then share this vocabulary without their findings becoming ambiguous in a shared
18
+ * log or dashboard.
19
+ */
20
+ readonly namespace: string;
21
+ /**
22
+ * Keys the caller refuses to transport. Matched against the **normalized** key, so a key hidden with
23
+ * zero-width joiners or full-width characters is still caught.
24
+ */
25
+ readonly forbiddenKeys?: readonly string[];
26
+ /** Patterns for values the caller treats as secret/PII. Matched against the normalized string. */
27
+ readonly sensitiveValuePatterns?: readonly RegExp[];
28
+ /** Patterns for capabilities the caller's product contract does not support. */
29
+ readonly unsupportedCapabilityPatterns?: readonly RegExp[];
30
+ /**
31
+ * Exact canary strings the caller planted upstream.
32
+ *
33
+ * ⭐ A canary hit is qualitatively different from the other findings: it proves a value the caller
34
+ * already rejected **reached this boundary anyway**, i.e. an earlier guard leaked.
35
+ */
36
+ readonly canaries?: readonly string[];
37
+ /** Maximum nesting depth. The root is depth 0. */
38
+ readonly maxDepth: number;
39
+ /** Maximum number of inspected nodes (values), including the root. */
40
+ readonly maxNodes: number;
41
+ /** Maximum length of any single string, measured AFTER normalization. */
42
+ readonly maxStringLength: number;
43
+ }
44
+ /**
45
+ * BFR-CTM-034 — the content-free inspection outcome.
46
+ *
47
+ * ⛔ **There is deliberately no field that could carry the offending data.** No matched text, no key,
48
+ * no pattern source, no object path, no payload fragment, no stack. Only: which classes of problem
49
+ * occurred, and how many times. A reviewer can act on this; an attacker learns nothing from it, and a
50
+ * log that captures it cannot become a secondary leak.
51
+ */
52
+ export interface DyFM_RequestSafetyResult_Interface {
53
+ readonly contractVersion: 'dyfm-request-safety/1';
54
+ /** `false` if ANY finding occurred — the inspection is deny-only and fail-closed. */
55
+ readonly accepted: boolean;
56
+ /** Namespaced, de-duplicated finding codes, e.g. `ctm-r5:forbidden-key`. Sorted for stability. */
57
+ readonly findingCodes: readonly string[];
58
+ /** How many times each finding class occurred. Aggregate only — never per-occurrence detail. */
59
+ readonly findingCounts: Readonly<Record<string, number>>;
60
+ /** How many nodes were actually inspected (bounded by `maxNodes`). */
61
+ readonly inspectedNodes: number;
62
+ }
63
+ /** BFR-CTM-034 — an internal, per-run finding tally. Never leaves the module in this shape. */
64
+ export interface DyFM_RequestSafetyTally_Interface {
65
+ readonly finding: DyFM_RequestSafetyFinding_Type;
66
+ }
67
+ //# sourceMappingURL=request-safety.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-safety.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/request-safety/_models/request-safety.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,4CAA4C,CAAC;AAE5F;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kCAAkC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,kGAAkG;IAClG,QAAQ,CAAC,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpD,gFAAgF;IAChF,QAAQ,CAAC,6BAA6B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3D;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,eAAe,EAAE,uBAAuB,CAAC;IAClD,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,kGAAkG;IAClG,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,gGAAgG;IAChG,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzD,sEAAsE;IACtE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,+FAA+F;AAC/F,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,OAAO,EAAE,8BAA8B,CAAC;CAClD"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=request-safety.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-safety.interface.js","sourceRoot":"","sources":["../../../../src/_modules/request-safety/_models/request-safety.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export * from './_collections/request-safety-inspector.util';
2
+ export * from './_enums/request-safety-finding.type-enum';
3
+ export * from './_models/request-safety.interface';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/request-safety/index.ts"],"names":[],"mappings":"AAAA,cAAc,8CAA8C,CAAC;AAC7D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,oCAAoC,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./_collections/request-safety-inspector.util"), exports);
5
+ tslib_1.__exportStar(require("./_enums/request-safety-finding.type-enum"), exports);
6
+ tslib_1.__exportStar(require("./_models/request-safety.interface"), exports);
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/request-safety/index.ts"],"names":[],"mappings":";;;AAAA,uFAA6D;AAC7D,oFAA0D;AAC1D,6EAAmD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@futdevpro/fsm-dynamo",
3
- "version": "1.20.23",
3
+ "version": "1.20.24",
4
4
  "description": "Full Stack Model Collection for Dynamic (NodeJS-Typescript) Framework called Dynamo, by Future Development Ltd.",
5
5
  "DyBu_settings": {
6
6
  "packageType": "full-stack-package",
@@ -131,6 +131,12 @@
131
131
  "types": "./build/_modules/crypto/index.d.ts",
132
132
  "typings": "./build/_modules/crypto/index.d.ts"
133
133
  },
134
+ "./request-safety": {
135
+ "default": "./build/_modules/request-safety/index.js",
136
+ "module": "./build/_modules/request-safety/index.js",
137
+ "types": "./build/_modules/request-safety/index.d.ts",
138
+ "typings": "./build/_modules/request-safety/index.d.ts"
139
+ },
134
140
  "./deployment": {
135
141
  "default": "./build/_modules/deployment/index.js",
136
142
  "module": "./build/_modules/deployment/index.js",
@@ -257,6 +263,9 @@
257
263
  "crypto": [
258
264
  "build/_modules/crypto/index.d.ts"
259
265
  ],
266
+ "request-safety": [
267
+ "build/_modules/request-safety/index.d.ts"
268
+ ],
260
269
  "deployment": [
261
270
  "build/_modules/deployment/index.d.ts"
262
271
  ],