@ya-accelerators/web-backend-framework 0.0.110 → 0.0.112

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,4 @@
1
+ export declare const DSR_RESPONSE_DEADLINE_DAYS: {
2
+ readonly eu: 30;
3
+ };
4
+ export declare const dsrDueAt: (jurisdiction: keyof typeof DSR_RESPONSE_DEADLINE_DAYS, from: Date) => Date;
@@ -0,0 +1,6 @@
1
+ import { MS_PER_DAY } from './retention.js';
2
+ export const DSR_RESPONSE_DEADLINE_DAYS = {
3
+ eu: 30,
4
+ };
5
+ export const dsrDueAt = (jurisdiction, from) => new Date(from.getTime() + DSR_RESPONSE_DEADLINE_DAYS[jurisdiction] * MS_PER_DAY);
6
+ //# sourceMappingURL=dsr-deadline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsr-deadline.js","sourceRoot":"","sources":["../../../src/.generated/policy/dsr-deadline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAE3C,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,EAAE,EAAE,EAAE;CACE,CAAA;AAEV,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,YAAqD,EAAE,IAAU,EAAE,EAAE,CAC5F,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,0BAA0B,CAAC,YAAY,CAAC,GAAG,UAAU,CAAC,CAAA"}
@@ -0,0 +1,50 @@
1
+ declare const PII_CATEGORIES: readonly ['direct identifier', 'quasi-identifier', 'subject reference', 'external identifier', 'payload', 'sensitive'];
2
+ export type PiiCategory = (typeof PII_CATEGORIES)[number];
3
+ declare const ERASE_STRATEGIES: readonly ['delete-row', 'anonymize', 'none'];
4
+ export type EraseStrategy = (typeof ERASE_STRATEGIES)[number];
5
+ export type RetentionMarker = {
6
+ kind: 'category';
7
+ category: string;
8
+ } | {
9
+ kind: 'override';
10
+ constant: string;
11
+ };
12
+ export type FieldMarkers = {
13
+ pii?: string;
14
+ retentionAnchor?: boolean;
15
+ type: string;
16
+ optional: boolean;
17
+ };
18
+ export type ModelMarkers = {
19
+ name: string;
20
+ isEvent: boolean;
21
+ erase?: EraseStrategy;
22
+ retention?: RetentionMarker;
23
+ fields: Record<string, FieldMarkers>;
24
+ };
25
+ export type MarkerRegistry = Record<string, ModelMarkers>;
26
+ export type SchemaField = {
27
+ name: string;
28
+ documentation?: string;
29
+ type: string;
30
+ isRequired: boolean;
31
+ };
32
+ export type SchemaModel = {
33
+ name: string;
34
+ documentation?: string;
35
+ fields: readonly SchemaField[];
36
+ };
37
+ export declare const parseMarkers: (models: readonly SchemaModel[]) => MarkerRegistry;
38
+ export type Finding = {
39
+ model: string;
40
+ field?: string;
41
+ severity: 'HIGH' | 'MEDIUM';
42
+ rule: string;
43
+ message: string;
44
+ };
45
+ export declare const validateCoverage: (registry: MarkerRegistry, policy: {
46
+ categories: ReadonlySet<string>;
47
+ eventCategory: string;
48
+ constants: ReadonlySet<string>;
49
+ }) => Finding[];
50
+ export {};
@@ -0,0 +1,145 @@
1
+ const PII_CATEGORIES = [
2
+ 'direct identifier',
3
+ 'quasi-identifier',
4
+ 'subject reference',
5
+ 'external identifier',
6
+ 'payload',
7
+ 'sensitive',
8
+ ];
9
+ // Runtime tuple (not just a union type) so parse narrows a regex capture to a member via `.find` rather than
10
+ // an unchecked `as` cast, mirroring PII_CATEGORIES.
11
+ const ERASE_STRATEGIES = ['delete-row', 'anonymize', 'none'];
12
+ // The erase pattern is built from the vocabulary so an out-of-vocabulary strategy simply does not match.
13
+ // The PII marker deliberately captures the raw token instead (see
14
+ // parseFieldDoc): its unknown values MUST reach validateCoverage's `unknown-pii-category` rule, exactly like
15
+ // the retention marker's lazy-validate — eager narrowing here would silently drop a typo'd category and make
16
+ // the fail-closed coverage gate pass (db-schema.md § Personal data classification).
17
+ const eraseMarkerPattern = new RegExp(`^erase:\\s*(${ERASE_STRATEGIES.join('|')})\\b`);
18
+ const parseModelDoc = (doc) => {
19
+ const result = {};
20
+ for (const raw of (doc ?? '').split('\n')) {
21
+ const line = raw.trim();
22
+ const erase = eraseMarkerPattern.exec(line);
23
+ if (erase) {
24
+ const strategy = ERASE_STRATEGIES.find((value) => value === erase[1]);
25
+ if (strategy !== undefined) {
26
+ result.erase = strategy;
27
+ }
28
+ }
29
+ const retention = /^retention:\s*(.+)$/.exec(line);
30
+ if (retention) {
31
+ const override = /^override\s+(\S+)/.exec(retention[1].trim());
32
+ result.retention = override
33
+ ? { kind: 'override', constant: override[1] }
34
+ : { kind: 'category', category: retention[1].trim().split(/\s/)[0] };
35
+ }
36
+ }
37
+ return result;
38
+ };
39
+ const parseFieldDoc = (doc) => {
40
+ const result = {};
41
+ for (const raw of (doc ?? '').split('\n')) {
42
+ const line = raw.trim();
43
+ const pii = /^PII:\s*(.+)$/.exec(line);
44
+ if (pii) {
45
+ result.pii = pii[1].trim();
46
+ }
47
+ if (/^retention-anchor\b/.test(line)) {
48
+ result.retentionAnchor = true;
49
+ }
50
+ }
51
+ return result;
52
+ };
53
+ export const parseMarkers = (models) => {
54
+ const registry = {};
55
+ for (const model of models) {
56
+ const fields = {};
57
+ for (const field of model.fields) {
58
+ const parsed = parseFieldDoc(field.documentation);
59
+ if (parsed.pii || parsed.retentionAnchor) {
60
+ fields[field.name] = { ...parsed, type: field.type, optional: !field.isRequired };
61
+ }
62
+ }
63
+ registry[model.name] = {
64
+ name: model.name,
65
+ isEvent: model.name.startsWith('Event'),
66
+ ...parseModelDoc(model.documentation),
67
+ fields,
68
+ };
69
+ }
70
+ return registry;
71
+ };
72
+ // Fail-closed coverage validation. The retention `policy` is injected by the caller:
73
+ // - `categories`: the valid `/// retention: <category>` names (keys of RETENTION_CATEGORY_DAYS).
74
+ // - `eventCategory`: the category every `Event*` table must use (audit evidence).
75
+ // - `constants`: the `RETENTION_<TABLE>_DAYS` names exported by the service's own constants.ts
76
+ // (so `/// retention: override <CONST>` markers resolve to a real source).
77
+ export const validateCoverage = (registry, policy) => {
78
+ const findings = [];
79
+ for (const model of Object.values(registry)) {
80
+ if (Object.values(model.fields).some((field) => field.pii === 'subject reference') && !model.erase) {
81
+ findings.push({
82
+ model: model.name,
83
+ severity: 'HIGH',
84
+ rule: 'erase-coverage',
85
+ message: 'has a `/// PII: subject reference` field but no `/// erase:` marker (delete-row | anonymize | none)',
86
+ });
87
+ }
88
+ if (!model.retention) {
89
+ findings.push({
90
+ model: model.name,
91
+ severity: 'HIGH',
92
+ rule: 'retention-coverage',
93
+ message: 'has no `/// retention:` marker',
94
+ });
95
+ }
96
+ else if (model.retention.kind === 'override') {
97
+ if (!policy.constants.has(model.retention.constant)) {
98
+ findings.push({
99
+ model: model.name,
100
+ severity: 'HIGH',
101
+ rule: 'override-constant',
102
+ message: `\`/// retention: override ${model.retention.constant}\` but that constant is not exported from constants.ts`,
103
+ });
104
+ }
105
+ }
106
+ else if (!policy.categories.has(model.retention.category)) {
107
+ findings.push({
108
+ model: model.name,
109
+ severity: 'HIGH',
110
+ rule: 'unknown-category',
111
+ message: `\`/// retention: ${model.retention.category}\` is not a known retention category`,
112
+ });
113
+ }
114
+ else if (model.isEvent && model.retention.category !== policy.eventCategory) {
115
+ findings.push({
116
+ model: model.name,
117
+ severity: 'HIGH',
118
+ rule: 'event-retention',
119
+ message: `Event* tables must be \`/// retention: ${policy.eventCategory}\`, found \`${model.retention.category}\``,
120
+ });
121
+ }
122
+ for (const [name, field] of Object.entries(model.fields)) {
123
+ if (field.pii !== undefined && !PII_CATEGORIES.some((category) => category === field.pii)) {
124
+ findings.push({
125
+ model: model.name,
126
+ field: name,
127
+ severity: 'HIGH',
128
+ rule: 'unknown-pii-category',
129
+ message: `\`/// PII: ${field.pii}\` is not a known PII category`,
130
+ });
131
+ }
132
+ if (field.retentionAnchor && !(field.type === 'DateTime' && field.optional)) {
133
+ findings.push({
134
+ model: model.name,
135
+ field: name,
136
+ severity: 'MEDIUM',
137
+ rule: 'anchor-type',
138
+ message: '`/// retention-anchor` must be on a nullable `DateTime?` column',
139
+ });
140
+ }
141
+ }
142
+ }
143
+ return findings;
144
+ };
145
+ //# sourceMappingURL=markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markers.js","sourceRoot":"","sources":["../../../src/.generated/policy/markers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export declare const RETENTION_CATEGORY_DAYS: {
2
+ readonly 'tax-accounting': 2555;
3
+ readonly 'security-audit': 730;
4
+ readonly 'operational-logs': 180;
5
+ readonly 'webhook-payloads': 90;
6
+ readonly 'consent-evidence': 1095;
7
+ readonly 'legal-hold': 730;
8
+ readonly 'audit-trail': 4745;
9
+ readonly suppression: 'indefinite';
10
+ readonly 'account-active': 'indefinite';
11
+ readonly governance: 'indefinite';
12
+ readonly configuration: 'indefinite';
13
+ };
14
+ export declare const EVENT_RETENTION_CATEGORY = "security-audit";
15
+ export type RetentionCategory = keyof typeof RETENTION_CATEGORY_DAYS;
16
+ export declare const MS_PER_DAY: number;
17
+ export declare const retentionDays: (category: RetentionCategory) => 90 | 180 | 730 | 1095 | 2555 | 4745 | undefined;
18
+ export declare const purgeCutoff: (category: RetentionCategory, now: Date) => Date | undefined;
19
+ export declare const retainUntil: (category: RetentionCategory, sealedAt: Date) => Date | undefined;
@@ -0,0 +1,45 @@
1
+ export const RETENTION_CATEGORY_DAYS = {
2
+ 'tax-accounting': 2555, // 7y — fiscal-year-aligned purge and WORM retention (Estonia Accounting Act §12)
3
+ 'security-audit': 730, // 2y — security forensics
4
+ 'operational-logs': 180, // 6mo — incident investigation
5
+ 'webhook-payloads': 90,
6
+ 'consent-evidence': 1095, // 3y rolling from occurredAt
7
+ 'legal-hold': 730, // 2y rolling from releasedAt
8
+ 'audit-trail': 4745,
9
+ suppression: 'indefinite',
10
+ 'account-active': 'indefinite',
11
+ governance: 'indefinite',
12
+ configuration: 'indefinite',
13
+ };
14
+ export const EVENT_RETENTION_CATEGORY = 'security-audit';
15
+ export const MS_PER_DAY = 24 * 60 * 60 * 1000;
16
+ const fiscalYearEnd = (year) => new Date(`${year}-12-31T23:59:59.999Z`);
17
+ export const retentionDays = (category) => {
18
+ const days = RETENTION_CATEGORY_DAYS[category];
19
+ return days === 'indefinite' ? undefined : days;
20
+ };
21
+ // Rows whose retention anchor is before this cutoff are purged. `undefined` = never time-purged. Tax /
22
+ // accounting is fiscal-year aligned (kept until the end of FY + window); the rest roll from the anchor.
23
+ export const purgeCutoff = (category, now) => {
24
+ const days = RETENTION_CATEGORY_DAYS[category];
25
+ if (days === 'indefinite') {
26
+ return undefined;
27
+ }
28
+ if (category === 'tax-accounting') {
29
+ return fiscalYearEnd(now.getUTCFullYear() - Math.floor(days / 365) - 1);
30
+ }
31
+ return new Date(now.getTime() - days * MS_PER_DAY);
32
+ };
33
+ // Object-lock retain-until for a sealed object (WORM). Tax / accounting is fiscal-year aligned;
34
+ // the rest roll from the seal time. `undefined` = no WORM expiry for indefinite categories.
35
+ export const retainUntil = (category, sealedAt) => {
36
+ const days = RETENTION_CATEGORY_DAYS[category];
37
+ if (days === 'indefinite') {
38
+ return undefined;
39
+ }
40
+ if (category === 'tax-accounting') {
41
+ return fiscalYearEnd(sealedAt.getUTCFullYear() + Math.floor(days / 365));
42
+ }
43
+ return new Date(sealedAt.getTime() + days * MS_PER_DAY);
44
+ };
45
+ //# sourceMappingURL=retention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../../src/.generated/policy/retention.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,gBAAgB,EAAE,IAAI,EAAE,iFAAiF;IACzG,gBAAgB,EAAE,GAAG,EAAE,0BAA0B;IACjD,kBAAkB,EAAE,GAAG,EAAE,+BAA+B;IACxD,kBAAkB,EAAE,EAAE;IACtB,kBAAkB,EAAE,IAAI,EAAE,6BAA6B;IACvD,YAAY,EAAE,GAAG,EAAE,6BAA6B;IAChD,aAAa,EAAE,IAAI;IACnB,WAAW,EAAE,YAAY;IACzB,gBAAgB,EAAE,YAAY;IAC9B,UAAU,EAAE,YAAY;IACxB,aAAa,EAAE,YAAY;CACnB,CAAA;AAEV,MAAM,CAAC,MAAM,wBAAwB,GAAG,gBAAgB,CAAA;AAIxD,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;AAE7C,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,sBAAsB,CAAC,CAAA;AAE/E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAA2B,EAAE,EAAE;IAC3D,MAAM,IAAI,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAA;IAC9C,OAAO,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;AACjD,CAAC,CAAA;AAED,uGAAuG;AACvG,wGAAwG;AACxG,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAA2B,EAAE,GAAS,EAAE,EAAE;IACpE,MAAM,IAAI,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAA;IAC9C,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;QAClC,OAAO,aAAa,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,UAAU,CAAC,CAAA;AACpD,CAAC,CAAA;AAED,gGAAgG;AAChG,4FAA4F;AAC5F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAA2B,EAAE,QAAc,EAAE,EAAE;IACzE,MAAM,IAAI,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAA;IAC9C,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;QAClC,OAAO,aAAa,CAAC,QAAQ,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAA;IAC1E,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,UAAU,CAAC,CAAA;AACzD,CAAC,CAAA"}
@@ -0,0 +1,5 @@
1
+ export declare const sanitizeKeys: {
2
+ SANITIZE_KEYWORDS: readonly ['authorization', 'proxy-authorization', 'cookie', 'set-cookie', 'x-api-key', 'apikey', 'api_key', 'api-key', 'token', 'secret', 'password', 'passwd', 'signature', 'private', 'session', 'jwt', 'bearer', 'email', 'fullname', 'isikukood', 'dateofbirth', 'phone', 'wage', 'screenedname', 'familyname', 'givenname', 'middlename', 'holdername', 'namekana', 'nickname', 'fax', 'workplaceaddress', 'complainantcontact', 'affiliatedorganization', 'nationalid', 'zipcode', 'taxnumber', 'corporateid', 'useragent', 'hostcountry', 'residencycountry', 'jobtitle', 'department', 'authenticationkey'];
3
+ SANITIZE_EXACT_KEYS: readonly ['ip'];
4
+ SANITIZE_EXACT_KEYS_EXCEPT_ERRORS: readonly ['name'];
5
+ };
@@ -0,0 +1,63 @@
1
+ // The key sets `Util.sanitize` redacts by. They live here rather than in the framework's constants.ts
2
+ // because the sanitize-coverage gate reads them too, and a gate that reached into a package would break
3
+ // when that package moved a file. The framework spreads this bundle into its own `constants` object, so
4
+ // every runtime caller still reads `constants.SANITIZE_*`.
5
+ export const sanitizeKeys = {
6
+ // The keys `Util.sanitize` redacts by substring match. Every entry must stay low-false-positive: a
7
+ // substring here masks any key containing it, so a generic word would gut incident investigation. Bare
8
+ // 'name' (a direct identifier, db-schema.md) belongs in SANITIZE_EXACT_KEYS_EXCEPT_ERRORS instead — a
9
+ // substring entry would mask serviceName / fileName / ….
10
+ SANITIZE_KEYWORDS: [
11
+ 'authorization',
12
+ 'proxy-authorization',
13
+ 'cookie',
14
+ 'set-cookie',
15
+ 'x-api-key',
16
+ 'apikey',
17
+ 'api_key',
18
+ 'api-key',
19
+ 'token',
20
+ 'secret',
21
+ 'password',
22
+ 'passwd',
23
+ 'signature',
24
+ 'private',
25
+ 'session',
26
+ 'jwt',
27
+ 'bearer',
28
+ 'email',
29
+ 'fullname',
30
+ 'isikukood',
31
+ 'dateofbirth',
32
+ 'phone',
33
+ 'wage',
34
+ 'screenedname',
35
+ 'familyname',
36
+ 'givenname',
37
+ 'middlename',
38
+ 'holdername',
39
+ 'namekana',
40
+ 'nickname',
41
+ 'fax',
42
+ 'workplaceaddress',
43
+ 'complainantcontact',
44
+ 'affiliatedorganization',
45
+ 'nationalid',
46
+ 'zipcode',
47
+ 'taxnumber',
48
+ 'corporateid',
49
+ 'useragent',
50
+ 'hostcountry',
51
+ 'residencycountry',
52
+ 'jobtitle',
53
+ 'department',
54
+ 'authenticationkey',
55
+ ],
56
+ // Exact-match-only PII keys. A substring entry would be catastrophic here — 'ip' matches recipient /
57
+ // description / zip / script — so these are compared whole.
58
+ SANITIZE_EXACT_KEYS: ['ip'],
59
+ // Exact-match PII keys that an object produced from an Error is exempt from: its `name` is the error
60
+ // class, not a person's.
61
+ SANITIZE_EXACT_KEYS_EXCEPT_ERRORS: ['name'],
62
+ };
63
+ //# sourceMappingURL=sanitize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../../src/.generated/policy/sanitize.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,wGAAwG;AACxG,wGAAwG;AACxG,2DAA2D;AAC3D,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,mGAAmG;IACnG,uGAAuG;IACvG,sGAAsG;IACtG,yDAAyD;IACzD,iBAAiB,EAAE;QACjB,eAAe;QACf,qBAAqB;QACrB,QAAQ;QACR,YAAY;QACZ,WAAW;QACX,QAAQ;QACR,SAAS;QACT,SAAS;QACT,OAAO;QACP,QAAQ;QACR,UAAU;QACV,QAAQ;QACR,WAAW;QACX,SAAS;QACT,SAAS;QACT,KAAK;QACL,QAAQ;QACR,OAAO;QACP,UAAU;QACV,WAAW;QACX,aAAa;QACb,OAAO;QACP,MAAM;QACN,cAAc;QACd,YAAY;QACZ,WAAW;QACX,YAAY;QACZ,YAAY;QACZ,UAAU;QACV,UAAU;QACV,KAAK;QACL,kBAAkB;QAClB,oBAAoB;QACpB,wBAAwB;QACxB,YAAY;QACZ,SAAS;QACT,WAAW;QACX,aAAa;QACb,WAAW;QACX,aAAa;QACb,kBAAkB;QAClB,UAAU;QACV,YAAY;QACZ,mBAAmB;KACX;IAEV,qGAAqG;IACrG,4DAA4D;IAC5D,mBAAmB,EAAE,CAAC,IAAI,CAAU;IAEpC,qGAAqG;IACrG,yBAAyB;IACzB,iCAAiC,EAAE,CAAC,MAAM,CAAU;CACrD,CAAA"}
@@ -0,0 +1,2 @@
1
+ import type { SchemaModel } from './markers.ts';
2
+ export declare const readSchemaModels: (schemaText: string) => SchemaModel[];
@@ -0,0 +1,51 @@
1
+ // Reads a Prisma schema's text into the model/field slice the marker reader consumes. Pure string
2
+ // parse — no `@prisma/internals` / `getDMMF` — so the same function runs in the CI marker check
3
+ // (backend/bin/check-marker-coverage.ts) and in the runtime erase / retention-purge batch callers.
4
+ // The Prisma 7 `prisma-client` generator strips `///` documentation from its `runtimeDataModel`,
5
+ // so the generated client is not a usable source at runtime — the schema text is.
6
+ // Mirrors Prisma's own `///` association rule: only the run of `///` doc-comment lines directly
7
+ // above a `model` or field declaration becomes its documentation. A blank line or a plain `//`
8
+ // line breaks the run (so layout headers like `// ---- Foo ----` never leak into a marker), and
9
+ // the next declaration consumes the accumulated lines.
10
+ export const readSchemaModels = (schemaText) => {
11
+ const models = [];
12
+ let pendingDoc = [];
13
+ let current = null;
14
+ for (const raw of schemaText.split('\n')) {
15
+ const line = raw.trim();
16
+ if (line.startsWith('///')) {
17
+ pendingDoc.push(line.replace(/^\/\/\/\s?/, ''));
18
+ continue;
19
+ }
20
+ const modelMatch = /^model\s+(\w+)\s*\{/.exec(line);
21
+ if (modelMatch) {
22
+ current = {
23
+ name: modelMatch[1],
24
+ documentation: pendingDoc.length ? pendingDoc.join('\n') : undefined,
25
+ fields: [],
26
+ };
27
+ models.push(current);
28
+ pendingDoc = [];
29
+ continue;
30
+ }
31
+ if (current && line === '}') {
32
+ current = null;
33
+ pendingDoc = [];
34
+ continue;
35
+ }
36
+ if (current && !line.startsWith('@')) {
37
+ const fieldMatch = /^(\w+)\s+([A-Za-z0-9_]+)(\?)?/.exec(line);
38
+ if (fieldMatch) {
39
+ current.fields.push({
40
+ name: fieldMatch[1],
41
+ documentation: pendingDoc.length ? pendingDoc.join('\n') : undefined,
42
+ type: fieldMatch[2],
43
+ isRequired: !fieldMatch[3],
44
+ });
45
+ }
46
+ }
47
+ pendingDoc = [];
48
+ }
49
+ return models;
50
+ };
51
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/.generated/policy/schema.ts"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,gGAAgG;AAChG,mGAAmG;AACnG,iGAAiG;AACjG,kFAAkF;AAClF,gGAAgG;AAChG,+FAA+F;AAC/F,gGAAgG;AAChG,uDAAuD;AACvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,UAAkB,EAAE,EAAE;IACrD,MAAM,MAAM,GAAkB,EAAE,CAAA;IAChC,IAAI,UAAU,GAAa,EAAE,CAAA;IAC7B,IAAI,OAAO,GAA2E,IAAI,CAAA;IAE1F,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;QAEvB,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAA;YAC/C,SAAQ;QACV,CAAC;QAED,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACnD,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,GAAG;gBACR,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;gBACnB,aAAa,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;gBACpE,MAAM,EAAE,EAAE;aACX,CAAA;YACD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACpB,UAAU,GAAG,EAAE,CAAA;YACf,SAAQ;QACV,CAAC;QAED,IAAI,OAAO,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,GAAG,IAAI,CAAA;YACd,UAAU,GAAG,EAAE,CAAA;YACf,SAAQ;QACV,CAAC;QAED,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,UAAU,GAAG,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC7D,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;oBAClB,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;oBACnB,aAAa,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;oBACpE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;oBACnB,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;iBAC3B,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QACD,UAAU,GAAG,EAAE,CAAA;IACjB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA"}
@@ -1,4 +1,7 @@
1
1
  export declare const constants: {
2
+ SANITIZE_KEYWORDS: readonly ['authorization', 'proxy-authorization', 'cookie', 'set-cookie', 'x-api-key', 'apikey', 'api_key', 'api-key', 'token', 'secret', 'password', 'passwd', 'signature', 'private', 'session', 'jwt', 'bearer', 'email', 'fullname', 'isikukood', 'dateofbirth', 'phone', 'wage', 'screenedname', 'familyname', 'givenname', 'middlename', 'holdername', 'namekana', 'nickname', 'fax', 'workplaceaddress', 'complainantcontact', 'affiliatedorganization', 'nationalid', 'zipcode', 'taxnumber', 'corporateid', 'useragent', 'hostcountry', 'residencycountry', 'jobtitle', 'department', 'authenticationkey'];
3
+ SANITIZE_EXACT_KEYS: readonly ['ip'];
4
+ SANITIZE_EXACT_KEYS_EXCEPT_ERRORS: readonly ['name'];
2
5
  OAUTH_DEV_REDIRECTOR_URL: string;
3
6
  UPLOADS_PREFIX: string;
4
7
  UPLOADS_EXPIRE_DAYS: number;
@@ -7,7 +10,4 @@ export declare const constants: {
7
10
  UPLOAD_CONTENT_TYPE_MAX_LENGTH: number;
8
11
  UPLOAD_STORED_CONTENT_TYPE: string;
9
12
  PII_ALLOWED_AWS_REGIONS: readonly ['eu-north-1', 'eu-west-1', 'eu-west-3', 'eu-central-1', 'eu-south-1', 'eu-south-2'];
10
- SANITIZE_KEYWORDS: readonly ['authorization', 'proxy-authorization', 'cookie', 'set-cookie', 'x-api-key', 'apikey', 'api_key', 'api-key', 'token', 'secret', 'password', 'passwd', 'signature', 'private', 'session', 'jwt', 'bearer', 'email', 'fullname', 'isikukood', 'dateofbirth', 'phone', 'wage', 'screenedname', 'familyname', 'givenname', 'middlename', 'holdername', 'namekana', 'nickname', 'fax', 'workplaceaddress', 'complainantcontact', 'affiliatedorganization', 'nationalid', 'zipcode', 'taxnumber', 'corporateid', 'useragent', 'hostcountry', 'residencycountry', 'jobtitle', 'department', 'authenticationkey'];
11
- SANITIZE_EXACT_KEYS: readonly ['ip'];
12
- SANITIZE_EXACT_KEYS_EXCEPT_ERRORS: readonly ['name'];
13
13
  };
package/dist/constants.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { sanitizeKeys } from './.generated/policy/sanitize.js';
1
2
  export const constants = {
2
3
  OAUTH_DEV_REDIRECTOR_URL: 'https://jbilvarnjxcewv7spngtoaowia0krqmu.lambda-url.eu-north-1.on.aws/',
3
4
  UPLOADS_PREFIX: '_uploads/',
@@ -18,61 +19,6 @@ export const constants = {
18
19
  'eu-south-1',
19
20
  'eu-south-2',
20
21
  ],
21
- // The keys `Util.sanitize` redacts by substring match. Every entry must stay low-false-positive: a
22
- // substring here masks any key containing it, so a generic word would gut incident investigation. Bare
23
- // 'name' (a direct identifier, db-schema.md) belongs in SANITIZE_EXACT_KEYS_EXCEPT_ERRORS instead — a
24
- // substring entry would mask serviceName / fileName / ….
25
- SANITIZE_KEYWORDS: [
26
- 'authorization',
27
- 'proxy-authorization',
28
- 'cookie',
29
- 'set-cookie',
30
- 'x-api-key',
31
- 'apikey',
32
- 'api_key',
33
- 'api-key',
34
- 'token',
35
- 'secret',
36
- 'password',
37
- 'passwd',
38
- 'signature',
39
- 'private',
40
- 'session',
41
- 'jwt',
42
- 'bearer',
43
- 'email',
44
- 'fullname',
45
- 'isikukood',
46
- 'dateofbirth',
47
- 'phone',
48
- 'wage',
49
- 'screenedname',
50
- 'familyname',
51
- 'givenname',
52
- 'middlename',
53
- 'holdername',
54
- 'namekana',
55
- 'nickname',
56
- 'fax',
57
- 'workplaceaddress',
58
- 'complainantcontact',
59
- 'affiliatedorganization',
60
- 'nationalid',
61
- 'zipcode',
62
- 'taxnumber',
63
- 'corporateid',
64
- 'useragent',
65
- 'hostcountry',
66
- 'residencycountry',
67
- 'jobtitle',
68
- 'department',
69
- 'authenticationkey',
70
- ],
71
- // Exact-match-only PII keys. A substring entry would be catastrophic here — 'ip' matches recipient /
72
- // description / zip / script — so these are compared whole.
73
- SANITIZE_EXACT_KEYS: ['ip'],
74
- // Exact-match PII keys that an object produced from an Error is exempt from: its `name` is the error
75
- // class, not a person's.
76
- SANITIZE_EXACT_KEYS_EXCEPT_ERRORS: ['name'],
22
+ ...sanitizeKeys,
77
23
  };
78
24
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,wBAAwB,EAAE,wEAAwE;IAClG,cAAc,EAAE,WAAW;IAC3B,mBAAmB,EAAE,CAAC;IACtB,mBAAmB,EAAE,EAAE;IACvB,0BAA0B,EAAE,GAAG;IAC/B,8BAA8B,EAAE,GAAG;IACnC,0BAA0B,EAAE,0BAA0B;IAEtD,4GAA4G;IAC5G,6GAA6G;IAC7G,4GAA4G;IAC5G,+CAA+C;IAC/C,uBAAuB,EAAE;QACvB,YAAY;QACZ,WAAW;QACX,WAAW;QACX,cAAc;QACd,YAAY;QACZ,YAAY;KACJ;IAEV,mGAAmG;IACnG,uGAAuG;IACvG,sGAAsG;IACtG,yDAAyD;IACzD,iBAAiB,EAAE;QACjB,eAAe;QACf,qBAAqB;QACrB,QAAQ;QACR,YAAY;QACZ,WAAW;QACX,QAAQ;QACR,SAAS;QACT,SAAS;QACT,OAAO;QACP,QAAQ;QACR,UAAU;QACV,QAAQ;QACR,WAAW;QACX,SAAS;QACT,SAAS;QACT,KAAK;QACL,QAAQ;QACR,OAAO;QACP,UAAU;QACV,WAAW;QACX,aAAa;QACb,OAAO;QACP,MAAM;QACN,cAAc;QACd,YAAY;QACZ,WAAW;QACX,YAAY;QACZ,YAAY;QACZ,UAAU;QACV,UAAU;QACV,KAAK;QACL,kBAAkB;QAClB,oBAAoB;QACpB,wBAAwB;QACxB,YAAY;QACZ,SAAS;QACT,WAAW;QACX,aAAa;QACb,WAAW;QACX,aAAa;QACb,kBAAkB;QAClB,UAAU;QACV,YAAY;QACZ,mBAAmB;KACX;IAEV,qGAAqG;IACrG,4DAA4D;IAC5D,mBAAmB,EAAE,CAAC,IAAI,CAAU;IAEpC,qGAAqG;IACrG,yBAAyB;IACzB,iCAAiC,EAAE,CAAC,MAAM,CAAU;CACrD,CAAA"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAA;AAE9D,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,wBAAwB,EAAE,wEAAwE;IAClG,cAAc,EAAE,WAAW;IAC3B,mBAAmB,EAAE,CAAC;IACtB,mBAAmB,EAAE,EAAE;IACvB,0BAA0B,EAAE,GAAG;IAC/B,8BAA8B,EAAE,GAAG;IACnC,0BAA0B,EAAE,0BAA0B;IAEtD,4GAA4G;IAC5G,6GAA6G;IAC7G,4GAA4G;IAC5G,+CAA+C;IAC/C,uBAAuB,EAAE;QACvB,YAAY;QACZ,WAAW;QACX,WAAW;QACX,cAAc;QACd,YAAY;QACZ,YAAY;KACJ;IAEV,GAAG,YAAY;CAChB,CAAA"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from './context/index.ts';
4
4
  export * from './coordination/index.ts';
5
5
  export * from './env.ts';
6
6
  export * from './logger/index.ts';
7
+ export * as Policy from './policy.ts';
7
8
  export * from './repository/index.ts';
8
9
  export * from './server/index.ts';
9
10
  export * from './usecase/index.ts';
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export * from './context/index.js';
4
4
  export * from './coordination/index.js';
5
5
  export * from './env.js';
6
6
  export * from './logger/index.js';
7
+ export * as Policy from './policy.js';
7
8
  export * from './repository/index.js';
8
9
  export * from './server/index.js';
9
10
  export * from './usecase/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,mBAAmB,CAAA;AACjC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,4 @@
1
+ export * from './.generated/policy/dsr-deadline.ts';
2
+ export * from './.generated/policy/markers.ts';
3
+ export * from './.generated/policy/retention.ts';
4
+ export * from './.generated/policy/schema.ts';
package/dist/policy.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './.generated/policy/dsr-deadline.js';
2
+ export * from './.generated/policy/markers.js';
3
+ export * from './.generated/policy/retention.js';
4
+ export * from './.generated/policy/schema.js';
5
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAA;AACnD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,+BAA+B,CAAA"}
@@ -25,6 +25,10 @@ export declare namespace Ropa {
25
25
  readonly kind: 'ropa-none';
26
26
  readonly reason: Reason;
27
27
  };
28
+ type Unimplemented<Reason extends string> = {
29
+ readonly kind: 'ropa-unimplemented';
30
+ readonly reason: Reason;
31
+ };
28
32
  }
29
33
  export type ProcessingDeclaration = {
30
34
  readonly purpose: string;
@@ -51,7 +55,7 @@ export declare const submitProcessingDeclarations: <T extends Record<string, Pro
51
55
  }) => Promise<void>;
52
56
  }) => Promise<void>;
53
57
  export type AuthDeclaration = Auth.Tier<string> | Auth.Upstream<string> | Auth.None<string> | Auth.Unimplemented<string>;
54
- export type RopaDeclaration<Key extends string> = Ropa.Activity<Key> | Ropa.None<string>;
58
+ export type RopaDeclaration<Key extends string> = Ropa.Activity<Key> | Ropa.None<string> | Ropa.Unimplemented<string>;
55
59
  export type DeclarationRequired = {
56
60
  readonly __declarationRequired: never;
57
61
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/trpc/declaration/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AA4BxC,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,YAGG,EACH,EAAE,CAAC,YAAY,CAAA;AAEjB,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,EAAmD,MASnG,EAAE,EAAE;IACH,KAAK,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAqC,EAAE,CAAC;QAC7G,MAAM,MAAM,CAAC,MAAM,CAAC;YAClB,WAAW;YACX,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,OAAO;YACP,cAAc,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,aAAa,IAAI,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SACpG,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/trpc/declaration/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AA6BxC,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,YAGG,EACH,EAAE,CAAC,YAAY,CAAA;AAEjB,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,EAAmD,MASnG,EAAE,EAAE;IACH,KAAK,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAqC,EAAE,CAAC;QAC7G,MAAM,MAAM,CAAC,MAAM,CAAC;YAClB,WAAW;YACX,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,OAAO;YACP,cAAc,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,aAAa,IAAI,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SACpG,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ya-accelerators/web-backend-framework",
3
- "version": "0.0.110",
3
+ "version": "0.0.112",
4
4
  "packageRole": "library",
5
5
  "type": "module",
6
6
  "description": "",
@@ -19,6 +19,10 @@
19
19
  "./constants": {
20
20
  "types": "./dist/constants.d.ts",
21
21
  "default": "./dist/constants.js"
22
+ },
23
+ "./policy": {
24
+ "types": "./dist/policy.d.ts",
25
+ "default": "./dist/policy.js"
22
26
  }
23
27
  },
24
28
  "repository": {
@@ -37,8 +41,8 @@
37
41
  ],
38
42
  "scripts": {
39
43
  "setup": "pnpm run build",
40
- "build": "tsc",
41
- "dev": "tsc --watch --preserveWatchOutput",
44
+ "build": "node ../../bin/copy-policy.mts src/.generated/policy && tsc",
45
+ "dev": "node ../../bin/copy-policy.mts src/.generated/policy && tsc --watch --preserveWatchOutput",
42
46
  "lint": "run-p -l -c lint:*",
43
47
  "lint:tsc": "tsc --pretty --noEmit --incremental false",
44
48
  "lint:biome": "biome check .",
@@ -48,8 +52,8 @@
48
52
  "test:integration": "jest --testPathPatterns=integration"
49
53
  },
50
54
  "dependencies": {
51
- "@aws-sdk/client-s3": "^3.1109.0",
52
- "@aws-sdk/credential-provider-node": "^3.972.79",
55
+ "@aws-sdk/client-s3": "^3.1113.0",
56
+ "@aws-sdk/credential-provider-node": "^3.972.80",
53
57
  "@prisma/adapter-mariadb": "^7.9.1",
54
58
  "@prisma/extension-read-replicas": "^0.5.0",
55
59
  "@valkey/valkey-glide": "^2.5.1",
@@ -57,7 +61,7 @@
57
61
  "express": "^5.2.1",
58
62
  "google-auth-library": "^11.0.2",
59
63
  "http-proxy-middleware": "^4.2.0",
60
- "jose": "^6.2.8",
64
+ "jose": "^6.2.9",
61
65
  "mariadb": "^3.5.3",
62
66
  "ulid": "^3.0.2"
63
67
  },