@derwinjs/db 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-promotion-evaluator.d.ts +63 -0
- package/dist/auto-promotion-evaluator.d.ts.map +1 -0
- package/dist/auto-promotion-evaluator.js +195 -0
- package/dist/auto-promotion-evaluator.js.map +1 -0
- package/dist/contract-baseline-store.d.ts +21 -0
- package/dist/contract-baseline-store.d.ts.map +1 -0
- package/dist/contract-baseline-store.js +103 -0
- package/dist/contract-baseline-store.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/project-mode-store.d.ts +28 -0
- package/dist/project-mode-store.d.ts.map +1 -0
- package/dist/project-mode-store.js +126 -0
- package/dist/project-mode-store.js.map +1 -0
- package/dist/scripts/smoke-auto-fix.js +1 -1
- package/dist/scripts/smoke-auto-fix.js.map +1 -1
- package/dist/tenant-fuzz-config-store.d.ts +28 -0
- package/dist/tenant-fuzz-config-store.d.ts.map +1 -0
- package/dist/tenant-fuzz-config-store.js +173 -0
- package/dist/tenant-fuzz-config-store.js.map +1 -0
- package/dist/visual-baseline-store.d.ts +21 -0
- package/dist/visual-baseline-store.d.ts.map +1 -0
- package/dist/visual-baseline-store.js +87 -0
- package/dist/visual-baseline-store.js.map +1 -0
- package/package.json +3 -3
- package/prisma/migrations/20260501165631_init/migration.sql +407 -0
- package/prisma/migrations/20260503051425_0002_qap018b_qaticket_crosslink_fields/migration.sql +6 -0
- package/prisma/migrations/20260507130000_sprint10_visual_baselines/migration.sql +27 -0
- package/prisma/migrations/20260507130100_sprint10_phase3_contract_baselines/migration.sql +32 -0
- package/prisma/migrations/20260507130200_sprint10_phase4_tenant_fuzz/migration.sql +34 -0
- package/prisma/schema.prisma +107 -0
- package/prisma-client/edge.js +36 -4
- package/prisma-client/index-browser.js +33 -1
- package/prisma-client/index.d.ts +15602 -10678
- package/prisma-client/index.js +36 -4
- package/prisma-client/package.json +1 -1
- package/prisma-client/schema.prisma +107 -0
- package/prisma-client/wasm.js +33 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createPrismaAutoPromotionEvaluator — Prisma-backed implementation of the
|
|
3
|
+
* SDK AutoPromotionEvaluator contract introduced by QAP-095.
|
|
4
|
+
*
|
|
5
|
+
* Sprint 9 Phase 3 (Policy + UI). Pure-read evaluator. Reads project
|
|
6
|
+
* mode-change boundary + recent telemetry and reports a 5-gate eligibility
|
|
7
|
+
* snapshot (see product brief §11.2 promotion criteria). NEVER mutates
|
|
8
|
+
* state — promotion itself is a separate ProjectModeStore.setMode() call
|
|
9
|
+
* the UI / cron makes once an operator confirms.
|
|
10
|
+
*
|
|
11
|
+
* # Window semantics
|
|
12
|
+
*
|
|
13
|
+
* t0 = now (config-injectable for tests)
|
|
14
|
+
* lookbackStart = t0 - PROMOTION_LOOKBACK_DAYS * 1d
|
|
15
|
+
*
|
|
16
|
+
* attempts/regression queries scope to attemptedAt >= lookbackStart.
|
|
17
|
+
* escalations queries scope to QATicket.updatedAt >= lookbackStart
|
|
18
|
+
* AND finalBucket = ESCALATION (the bucket assignment lands on
|
|
19
|
+
* updatedAt — see QATicket schema header).
|
|
20
|
+
*
|
|
21
|
+
* # Trust aggregation
|
|
22
|
+
*
|
|
23
|
+
* trustPercent is a SAMPLE-SIZE-WEIGHTED average. Each ClassificationTrust
|
|
24
|
+
* row contributes `trustPercent * attemptsLast30d` to the numerator and
|
|
25
|
+
* `attemptsLast30d` to the denominator. A row with `attemptsLast30d=0`
|
|
26
|
+
* contributes nothing — a brand-new tuple with no observations doesn't
|
|
27
|
+
* dilute the average. If NO rows have any observations, the gate's
|
|
28
|
+
* current value is 0 (which fails the >= 70 threshold by design).
|
|
29
|
+
*
|
|
30
|
+
* # Tenant isolation
|
|
31
|
+
*
|
|
32
|
+
* Every query scopes by projectId. The Project row read at the top
|
|
33
|
+
* (modeChangedAt) doubles as the existence check — `project_not_found`
|
|
34
|
+
* is thrown before any per-window aggregation runs, so we never spend
|
|
35
|
+
* round trips for a missing project.
|
|
36
|
+
*/
|
|
37
|
+
import type { PrismaClient } from './prisma.js';
|
|
38
|
+
import { type AutoPromotionEvaluator } from '@derwinjs/sdk';
|
|
39
|
+
export interface PrismaAutoPromotionEvaluatorConfig {
|
|
40
|
+
/** Generated Prisma client. Pass an instance per process. */
|
|
41
|
+
prisma: PrismaClient;
|
|
42
|
+
/**
|
|
43
|
+
* Optional clock injection for deterministic window-boundary tests.
|
|
44
|
+
* Tests pass a fixed Date; production callers omit (defaults to
|
|
45
|
+
* `new Date()`).
|
|
46
|
+
*/
|
|
47
|
+
now?: () => Date;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Public default thresholds — exported so the policy editor UI can render
|
|
51
|
+
* "needs >= 30 days" copy without round-tripping through the evaluator.
|
|
52
|
+
* Mirrors the constants above; if a caller-tunable variant ever lands,
|
|
53
|
+
* the constants stay as the wired defaults.
|
|
54
|
+
*/
|
|
55
|
+
export declare const DEFAULT_PROMOTION_THRESHOLDS: {
|
|
56
|
+
readonly daysOperating: 30;
|
|
57
|
+
readonly attempts: 50;
|
|
58
|
+
readonly trustPercent: 70;
|
|
59
|
+
readonly regressionPercent: 5;
|
|
60
|
+
readonly escalations: 0;
|
|
61
|
+
};
|
|
62
|
+
export declare function createPrismaAutoPromotionEvaluator(config: PrismaAutoPromotionEvaluatorConfig): AutoPromotionEvaluator;
|
|
63
|
+
//# sourceMappingURL=auto-promotion-evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-promotion-evaluator.d.ts","sourceRoot":"","sources":["../src/auto-promotion-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAEL,KAAK,sBAAsB,EAG5B,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,kCAAkC;IACjD,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAYD;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B;;;;;;CAM/B,CAAC;AA6BX,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,kCAAkC,GACzC,sBAAsB,CAuIxB"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createPrismaAutoPromotionEvaluator — Prisma-backed implementation of the
|
|
3
|
+
* SDK AutoPromotionEvaluator contract introduced by QAP-095.
|
|
4
|
+
*
|
|
5
|
+
* Sprint 9 Phase 3 (Policy + UI). Pure-read evaluator. Reads project
|
|
6
|
+
* mode-change boundary + recent telemetry and reports a 5-gate eligibility
|
|
7
|
+
* snapshot (see product brief §11.2 promotion criteria). NEVER mutates
|
|
8
|
+
* state — promotion itself is a separate ProjectModeStore.setMode() call
|
|
9
|
+
* the UI / cron makes once an operator confirms.
|
|
10
|
+
*
|
|
11
|
+
* # Window semantics
|
|
12
|
+
*
|
|
13
|
+
* t0 = now (config-injectable for tests)
|
|
14
|
+
* lookbackStart = t0 - PROMOTION_LOOKBACK_DAYS * 1d
|
|
15
|
+
*
|
|
16
|
+
* attempts/regression queries scope to attemptedAt >= lookbackStart.
|
|
17
|
+
* escalations queries scope to QATicket.updatedAt >= lookbackStart
|
|
18
|
+
* AND finalBucket = ESCALATION (the bucket assignment lands on
|
|
19
|
+
* updatedAt — see QATicket schema header).
|
|
20
|
+
*
|
|
21
|
+
* # Trust aggregation
|
|
22
|
+
*
|
|
23
|
+
* trustPercent is a SAMPLE-SIZE-WEIGHTED average. Each ClassificationTrust
|
|
24
|
+
* row contributes `trustPercent * attemptsLast30d` to the numerator and
|
|
25
|
+
* `attemptsLast30d` to the denominator. A row with `attemptsLast30d=0`
|
|
26
|
+
* contributes nothing — a brand-new tuple with no observations doesn't
|
|
27
|
+
* dilute the average. If NO rows have any observations, the gate's
|
|
28
|
+
* current value is 0 (which fails the >= 70 threshold by design).
|
|
29
|
+
*
|
|
30
|
+
* # Tenant isolation
|
|
31
|
+
*
|
|
32
|
+
* Every query scopes by projectId. The Project row read at the top
|
|
33
|
+
* (modeChangedAt) doubles as the existence check — `project_not_found`
|
|
34
|
+
* is thrown before any per-window aggregation runs, so we never spend
|
|
35
|
+
* round trips for a missing project.
|
|
36
|
+
*/
|
|
37
|
+
import { AutoPromotionEvaluatorError, } from '@derwinjs/sdk';
|
|
38
|
+
// ─── Constants ───────────────────────────────────────────────────────────
|
|
39
|
+
const PROMOTION_DAYS_OPERATING_MIN = 30;
|
|
40
|
+
const PROMOTION_ATTEMPTS_MIN = 50;
|
|
41
|
+
const PROMOTION_TRUST_MIN = 70;
|
|
42
|
+
const PROMOTION_REGRESSION_MAX = 5;
|
|
43
|
+
const PROMOTION_ESCALATIONS_MAX = 0;
|
|
44
|
+
const PROMOTION_LOOKBACK_DAYS = 30;
|
|
45
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
46
|
+
/**
|
|
47
|
+
* Public default thresholds — exported so the policy editor UI can render
|
|
48
|
+
* "needs >= 30 days" copy without round-tripping through the evaluator.
|
|
49
|
+
* Mirrors the constants above; if a caller-tunable variant ever lands,
|
|
50
|
+
* the constants stay as the wired defaults.
|
|
51
|
+
*/
|
|
52
|
+
export const DEFAULT_PROMOTION_THRESHOLDS = {
|
|
53
|
+
daysOperating: PROMOTION_DAYS_OPERATING_MIN,
|
|
54
|
+
attempts: PROMOTION_ATTEMPTS_MIN,
|
|
55
|
+
trustPercent: PROMOTION_TRUST_MIN,
|
|
56
|
+
regressionPercent: PROMOTION_REGRESSION_MAX,
|
|
57
|
+
escalations: PROMOTION_ESCALATIONS_MAX,
|
|
58
|
+
};
|
|
59
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
60
|
+
const MERGED_DISPATCH_STATUSES = ['AUTO_MERGED', 'HUMAN_MERGED'];
|
|
61
|
+
/**
|
|
62
|
+
* Sample-size-weighted average of trustPercent across rows.
|
|
63
|
+
* Returns `Math.round(sum(trustPercent * total) / sum(total))`.
|
|
64
|
+
* Returns 0 when there are no rows OR no observations across rows.
|
|
65
|
+
*/
|
|
66
|
+
function weightedTrustAverage(rows) {
|
|
67
|
+
let weightedSum = 0;
|
|
68
|
+
let totalSum = 0;
|
|
69
|
+
for (const row of rows) {
|
|
70
|
+
weightedSum += row.trustPercent * row.attemptsLast30d;
|
|
71
|
+
totalSum += row.attemptsLast30d;
|
|
72
|
+
}
|
|
73
|
+
if (totalSum === 0)
|
|
74
|
+
return 0;
|
|
75
|
+
return Math.round(weightedSum / totalSum);
|
|
76
|
+
}
|
|
77
|
+
// ─── Factory ─────────────────────────────────────────────────────────────
|
|
78
|
+
export function createPrismaAutoPromotionEvaluator(config) {
|
|
79
|
+
const { prisma } = config;
|
|
80
|
+
const now = config.now ?? (() => new Date());
|
|
81
|
+
return {
|
|
82
|
+
async evaluate(input) {
|
|
83
|
+
if (typeof input.projectId !== 'string' || input.projectId.length === 0) {
|
|
84
|
+
throw new AutoPromotionEvaluatorError('invalid_input', 'AutoPromotionEvaluator: projectId is required');
|
|
85
|
+
}
|
|
86
|
+
const at = now();
|
|
87
|
+
const lookbackStart = new Date(at.getTime() - PROMOTION_LOOKBACK_DAYS * MS_PER_DAY);
|
|
88
|
+
// Project existence check + modeChangedAt for daysOperating gate.
|
|
89
|
+
// This double-duty read also gives us tenant isolation — a missing /
|
|
90
|
+
// wrong-project id throws before we run any per-window aggregation.
|
|
91
|
+
const project = await prisma.project.findUnique({
|
|
92
|
+
where: { id: input.projectId },
|
|
93
|
+
select: { id: true, modeChangedAt: true },
|
|
94
|
+
});
|
|
95
|
+
if (project === null) {
|
|
96
|
+
throw new AutoPromotionEvaluatorError('project_not_found', `AutoPromotionEvaluator: project ${input.projectId} not found`);
|
|
97
|
+
}
|
|
98
|
+
// Gate 1 — daysOperating (floor((now - modeChangedAt) / 1d))
|
|
99
|
+
const daysOperating = Math.floor((at.getTime() - project.modeChangedAt.getTime()) / MS_PER_DAY);
|
|
100
|
+
// Gate 2 — attempts in last 30d (AUTO_MERGED ∪ HUMAN_MERGED)
|
|
101
|
+
const attempts = await prisma.qAFixAttempt.count({
|
|
102
|
+
where: {
|
|
103
|
+
projectId: input.projectId,
|
|
104
|
+
dispatchStatus: { in: [...MERGED_DISPATCH_STATUSES] },
|
|
105
|
+
attemptedAt: { gte: lookbackStart },
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
// Gate 3 — trustPercent (sample-size-weighted average across all
|
|
109
|
+
// (classification, surface) tuples for this project).
|
|
110
|
+
const trustRows = await prisma.classificationTrust.findMany({
|
|
111
|
+
where: { projectId: input.projectId },
|
|
112
|
+
select: { trustPercent: true, attemptsLast30d: true },
|
|
113
|
+
});
|
|
114
|
+
const trustPercent = weightedTrustAverage(trustRows);
|
|
115
|
+
// Gate 4 — regressionPercent (regressed / total in last 30d, * 100).
|
|
116
|
+
// totalRecent counts ALL dispatchStatus values within the window so
|
|
117
|
+
// the denominator captures every post-author attempt, not just merged
|
|
118
|
+
// ones. This matches the operator-facing definition of "recent fix
|
|
119
|
+
// activity" used elsewhere in the policy editor.
|
|
120
|
+
const totalRecent = await prisma.qAFixAttempt.count({
|
|
121
|
+
where: {
|
|
122
|
+
projectId: input.projectId,
|
|
123
|
+
attemptedAt: { gte: lookbackStart },
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
const regressed = await prisma.qAFixAttempt.count({
|
|
127
|
+
where: {
|
|
128
|
+
projectId: input.projectId,
|
|
129
|
+
regressionDetected: true,
|
|
130
|
+
attemptedAt: { gte: lookbackStart },
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
const regressionPercent = totalRecent === 0 ? 0 : Math.round((regressed / totalRecent) * 100);
|
|
134
|
+
// Gate 5 — escalations (QATicket.finalBucket=ESCALATION in last 30d).
|
|
135
|
+
const escalations = await prisma.qATicket.count({
|
|
136
|
+
where: {
|
|
137
|
+
projectId: input.projectId,
|
|
138
|
+
finalBucket: 'ESCALATION',
|
|
139
|
+
updatedAt: { gte: lookbackStart },
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
// Build the 5 gate results in a stable order. UI renders them as a
|
|
143
|
+
// table in this order; reordering would break operator muscle memory.
|
|
144
|
+
const gates = [
|
|
145
|
+
{
|
|
146
|
+
name: 'daysOperating',
|
|
147
|
+
pass: daysOperating >= PROMOTION_DAYS_OPERATING_MIN,
|
|
148
|
+
current: daysOperating,
|
|
149
|
+
threshold: PROMOTION_DAYS_OPERATING_MIN,
|
|
150
|
+
comparator: 'gte',
|
|
151
|
+
label: 'Days operating in current mode',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'attempts',
|
|
155
|
+
pass: attempts >= PROMOTION_ATTEMPTS_MIN,
|
|
156
|
+
current: attempts,
|
|
157
|
+
threshold: PROMOTION_ATTEMPTS_MIN,
|
|
158
|
+
comparator: 'gte',
|
|
159
|
+
label: 'Merged attempts (last 30 days)',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'trustPercent',
|
|
163
|
+
pass: trustPercent >= PROMOTION_TRUST_MIN,
|
|
164
|
+
current: trustPercent,
|
|
165
|
+
threshold: PROMOTION_TRUST_MIN,
|
|
166
|
+
comparator: 'gte',
|
|
167
|
+
label: 'Weighted trust percent',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'regressionPercent',
|
|
171
|
+
pass: regressionPercent <= PROMOTION_REGRESSION_MAX,
|
|
172
|
+
current: regressionPercent,
|
|
173
|
+
threshold: PROMOTION_REGRESSION_MAX,
|
|
174
|
+
comparator: 'lte',
|
|
175
|
+
label: 'Regression rate (last 30 days)',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'escalations',
|
|
179
|
+
pass: escalations === PROMOTION_ESCALATIONS_MAX,
|
|
180
|
+
current: escalations,
|
|
181
|
+
threshold: PROMOTION_ESCALATIONS_MAX,
|
|
182
|
+
comparator: 'eq',
|
|
183
|
+
label: 'Escalations (last 30 days)',
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
const eligible = gates.every((gate) => gate.pass);
|
|
187
|
+
return {
|
|
188
|
+
eligible,
|
|
189
|
+
gates,
|
|
190
|
+
computedAt: at,
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=auto-promotion-evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-promotion-evaluator.js","sourceRoot":"","sources":["../src/auto-promotion-evaluator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createPrismaContractBaselineStore — Prisma-backed implementation of the SDK
|
|
3
|
+
* ContractBaselineStore contract introduced by QAP-103.
|
|
4
|
+
*
|
|
5
|
+
* Sprint 10 Phase 3 (Test Surfaces — API contract diff). Baselines are
|
|
6
|
+
* stored as Postgres TEXT (model ContractBaseline) keyed by
|
|
7
|
+
* (projectId, specKey). One row per (projectId, specKey) — setBaseline
|
|
8
|
+
* upserts and is the only path to replace an approved baseline.
|
|
9
|
+
*
|
|
10
|
+
* Tenant isolation: every method scopes by projectId. Pattern D applies —
|
|
11
|
+
* unknown / wrong-project lookups return null rather than throwing or
|
|
12
|
+
* leaking existence (defense-in-depth against tenant enumeration).
|
|
13
|
+
*/
|
|
14
|
+
import type { PrismaClient } from './prisma.js';
|
|
15
|
+
import { type ContractBaselineStore } from '@derwinjs/sdk';
|
|
16
|
+
export interface PrismaContractBaselineStoreConfig {
|
|
17
|
+
/** Generated Prisma client. Pass an instance per process. */
|
|
18
|
+
prisma: PrismaClient;
|
|
19
|
+
}
|
|
20
|
+
export declare function createPrismaContractBaselineStore(config: PrismaContractBaselineStoreConfig): ContractBaselineStore;
|
|
21
|
+
//# sourceMappingURL=contract-baseline-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-baseline-store.d.ts","sourceRoot":"","sources":["../src/contract-baseline-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,iCAAiC;IAChD,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAqDD,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,iCAAiC,GACxC,qBAAqB,CA0EvB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createPrismaContractBaselineStore — Prisma-backed implementation of the SDK
|
|
3
|
+
* ContractBaselineStore contract introduced by QAP-103.
|
|
4
|
+
*
|
|
5
|
+
* Sprint 10 Phase 3 (Test Surfaces — API contract diff). Baselines are
|
|
6
|
+
* stored as Postgres TEXT (model ContractBaseline) keyed by
|
|
7
|
+
* (projectId, specKey). One row per (projectId, specKey) — setBaseline
|
|
8
|
+
* upserts and is the only path to replace an approved baseline.
|
|
9
|
+
*
|
|
10
|
+
* Tenant isolation: every method scopes by projectId. Pattern D applies —
|
|
11
|
+
* unknown / wrong-project lookups return null rather than throwing or
|
|
12
|
+
* leaking existence (defense-in-depth against tenant enumeration).
|
|
13
|
+
*/
|
|
14
|
+
import { ContractBaselineStoreError, } from '@derwinjs/sdk';
|
|
15
|
+
// ─── Validation ──────────────────────────────────────────────────────────
|
|
16
|
+
function assertNonEmpty(value, fieldName) {
|
|
17
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
18
|
+
throw new ContractBaselineStoreError('invalid_input', `createPrismaContractBaselineStore: ${fieldName} is required and non-empty`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function assertValidFormat(value) {
|
|
22
|
+
if (value !== 'openapi' && value !== 'json-schema') {
|
|
23
|
+
throw new ContractBaselineStoreError('invalid_format', `createPrismaContractBaselineStore: format must be 'openapi' or 'json-schema'`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Map a Prisma row to the SDK ContractBaseline shape. Coerces the stored
|
|
28
|
+
* `format` string back to the SDK union — defense in depth in case a
|
|
29
|
+
* malformed value somehow landed (the factory's setBaseline path validates
|
|
30
|
+
* before write, but external writes or bad migrations could bypass it).
|
|
31
|
+
*/
|
|
32
|
+
function toContractBaseline(row) {
|
|
33
|
+
const format = row.format === 'json-schema' ? 'json-schema' : 'openapi';
|
|
34
|
+
return {
|
|
35
|
+
id: row.id,
|
|
36
|
+
projectId: row.projectId,
|
|
37
|
+
specKey: row.specKey,
|
|
38
|
+
spec: row.spec,
|
|
39
|
+
format,
|
|
40
|
+
capturedAt: row.capturedAt,
|
|
41
|
+
capturedBy: row.capturedBy,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// ─── Factory ─────────────────────────────────────────────────────────────
|
|
45
|
+
export function createPrismaContractBaselineStore(config) {
|
|
46
|
+
const { prisma } = config;
|
|
47
|
+
return {
|
|
48
|
+
async getBaseline(input) {
|
|
49
|
+
assertNonEmpty(input.projectId, 'projectId');
|
|
50
|
+
assertNonEmpty(input.specKey, 'specKey');
|
|
51
|
+
const row = await prisma.contractBaseline.findUnique({
|
|
52
|
+
where: {
|
|
53
|
+
projectId_specKey: {
|
|
54
|
+
projectId: input.projectId,
|
|
55
|
+
specKey: input.specKey,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
if (row === null)
|
|
60
|
+
return null;
|
|
61
|
+
return toContractBaseline(row);
|
|
62
|
+
},
|
|
63
|
+
async setBaseline(input) {
|
|
64
|
+
assertNonEmpty(input.projectId, 'projectId');
|
|
65
|
+
assertNonEmpty(input.specKey, 'specKey');
|
|
66
|
+
assertNonEmpty(input.spec, 'spec');
|
|
67
|
+
assertNonEmpty(input.capturedBy, 'capturedBy');
|
|
68
|
+
assertValidFormat(input.format);
|
|
69
|
+
const row = await prisma.contractBaseline.upsert({
|
|
70
|
+
where: {
|
|
71
|
+
projectId_specKey: {
|
|
72
|
+
projectId: input.projectId,
|
|
73
|
+
specKey: input.specKey,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
create: {
|
|
77
|
+
projectId: input.projectId,
|
|
78
|
+
specKey: input.specKey,
|
|
79
|
+
spec: input.spec,
|
|
80
|
+
format: input.format,
|
|
81
|
+
capturedBy: input.capturedBy,
|
|
82
|
+
},
|
|
83
|
+
update: {
|
|
84
|
+
spec: input.spec,
|
|
85
|
+
format: input.format,
|
|
86
|
+
capturedBy: input.capturedBy,
|
|
87
|
+
capturedAt: new Date(),
|
|
88
|
+
},
|
|
89
|
+
select: { id: true },
|
|
90
|
+
});
|
|
91
|
+
return { id: row.id };
|
|
92
|
+
},
|
|
93
|
+
async listBaselines(input) {
|
|
94
|
+
assertNonEmpty(input.projectId, 'projectId');
|
|
95
|
+
const rows = await prisma.contractBaseline.findMany({
|
|
96
|
+
where: { projectId: input.projectId },
|
|
97
|
+
orderBy: { capturedAt: 'desc' },
|
|
98
|
+
});
|
|
99
|
+
return rows.map(toContractBaseline);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=contract-baseline-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-baseline-store.js","sourceRoot":"","sources":["../src/contract-baseline-store.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,5 +31,10 @@ export { createPrismaTrustThresholdConfigStore, type PrismaTrustThresholdConfigS
|
|
|
31
31
|
export { createPrismaFreezeWindowEvaluator, parseCron, mostRecentFire, type PrismaFreezeWindowEvaluatorConfig, } from './freeze-window-evaluator.js';
|
|
32
32
|
export { createPrismaBudgetGate, type PrismaBudgetGateConfig } from './budget-gate.js';
|
|
33
33
|
export { createPrismaKillSwitchEvaluator, DEFAULT_KILL_SWITCH_THRESHOLDS, type PrismaKillSwitchEvaluatorConfig, } from './kill-switch-evaluator.js';
|
|
34
|
+
export { createPrismaProjectModeStore, type PrismaProjectModeStoreConfig, } from './project-mode-store.js';
|
|
35
|
+
export { createPrismaAutoPromotionEvaluator, DEFAULT_PROMOTION_THRESHOLDS, type PrismaAutoPromotionEvaluatorConfig, } from './auto-promotion-evaluator.js';
|
|
36
|
+
export { createPrismaVisualBaselineStore, type PrismaVisualBaselineStoreConfig, } from './visual-baseline-store.js';
|
|
37
|
+
export { createPrismaContractBaselineStore, type PrismaContractBaselineStoreConfig, } from './contract-baseline-store.js';
|
|
38
|
+
export { createPrismaTenantFuzzConfigStore, type PrismaTenantFuzzConfigStoreConfig, } from './tenant-fuzz-config-store.js';
|
|
34
39
|
export * from './prisma.js';
|
|
35
40
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC;AAIpD,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAE,KAAK,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,EAClC,KAAK,kCAAkC,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,8BAA8B,EAC9B,KAAK,8BAA8B,GACpC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,EACT,KAAK,4BAA4B,GAClC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,EACvC,KAAK,uCAAuC,GAC7C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,EACrC,KAAK,qCAAqC,GAC3C,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,EACd,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC;AAIpD,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAE,KAAK,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,EAClC,KAAK,kCAAkC,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,8BAA8B,EAC9B,KAAK,8BAA8B,GACpC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,EACT,KAAK,4BAA4B,GAClC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,EACvC,KAAK,uCAAuC,GAC7C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,EACrC,KAAK,qCAAqC,GAC3C,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,EACd,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,4BAA4B,EAC5B,KAAK,4BAA4B,GAClC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kCAAkC,EAClC,4BAA4B,EAC5B,KAAK,kCAAkC,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,GACvC,MAAM,+BAA+B,CAAC;AA4BvC,cAAc,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,11 @@ export { createPrismaTrustThresholdConfigStore, } from './trust-threshold-config
|
|
|
32
32
|
export { createPrismaFreezeWindowEvaluator, parseCron, mostRecentFire, } from './freeze-window-evaluator.js';
|
|
33
33
|
export { createPrismaBudgetGate } from './budget-gate.js';
|
|
34
34
|
export { createPrismaKillSwitchEvaluator, DEFAULT_KILL_SWITCH_THRESHOLDS, } from './kill-switch-evaluator.js';
|
|
35
|
+
export { createPrismaProjectModeStore, } from './project-mode-store.js';
|
|
36
|
+
export { createPrismaAutoPromotionEvaluator, DEFAULT_PROMOTION_THRESHOLDS, } from './auto-promotion-evaluator.js';
|
|
37
|
+
export { createPrismaVisualBaselineStore, } from './visual-baseline-store.js';
|
|
38
|
+
export { createPrismaContractBaselineStore, } from './contract-baseline-store.js';
|
|
39
|
+
export { createPrismaTenantFuzzConfigStore, } from './tenant-fuzz-config-store.js';
|
|
35
40
|
// ─── Prisma client re-export ─────────────────────────────────────────────
|
|
36
41
|
//
|
|
37
42
|
// @derwinjs/db ships its OWN generated Prisma client (output: prisma-client/
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,cAAuB,CAAC;AAEpD,4EAA4E;AAE5E,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAmC,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,GAElC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,GAEnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,8BAA8B,GAE/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAkC,MAAM,qBAAqB,CAAC;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,GAEV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,GAExC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,GAEtC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,GAEf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,GAE/B,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,cAAuB,CAAC;AAEpD,4EAA4E;AAE5E,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAmC,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iCAAiC,GAElC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,kCAAkC,GAEnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,8BAA8B,GAE/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAkC,MAAM,qBAAqB,CAAC;AAChG,OAAO,EACL,4BAA4B,EAC5B,SAAS,GAEV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uCAAuC,GAExC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,qCAAqC,GAEtC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iCAAiC,EACjC,SAAS,EACT,cAAc,GAEf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAA+B,MAAM,kBAAkB,CAAC;AACvF,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,GAE/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,4BAA4B,GAE7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kCAAkC,EAClC,4BAA4B,GAE7B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,+BAA+B,GAEhC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,GAElC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,iCAAiC,GAElC,MAAM,+BAA+B,CAAC;AAEvC,4EAA4E;AAC5E,EAAE;AACF,6EAA6E;AAC7E,wEAAwE;AACxE,sEAAsE;AACtE,wEAAwE;AACxE,wEAAwE;AACxE,gDAAgD;AAChD,EAAE;AACF,+DAA+D;AAC/D,0EAA0E;AAC1E,yCAAyC;AACzC,+EAA+E;AAC/E,yCAAyC;AACzC,uEAAuE;AACvE,sEAAsE;AACtE,kEAAkE;AAClE,+BAA+B;AAC/B,EAAE;AACF,oBAAoB;AACpB,8DAA8D;AAC9D,4CAA4C;AAC5C,qEAAqE;AACrE,QAAQ;AACR,gDAAgD;AAEhD,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createPrismaProjectModeStore — Prisma-backed implementation of the SDK
|
|
3
|
+
* ProjectModeStore contract introduced by QAP-090.
|
|
4
|
+
*
|
|
5
|
+
* Sprint 9 (Policy + UI, Phase 1). Single choke point for reading and
|
|
6
|
+
* writing `Project.mode` (OBSERVE / TICKET_ONLY / AUTHOR / AUTO — see
|
|
7
|
+
* product brief §11.2). Every mode change goes through `setMode` so the
|
|
8
|
+
* audit log (ProjectModeLog) stays in lockstep with the Project row.
|
|
9
|
+
*
|
|
10
|
+
* Tenant isolation: every read scopes by projectId. `getMode` returns
|
|
11
|
+
* null for unknown projectId; `listLog` returns an empty array. `setMode`
|
|
12
|
+
* throws `project_not_found` (rather than returning null) because a
|
|
13
|
+
* mode-change call against a missing project is a caller bug, not a
|
|
14
|
+
* cross-tenant probe — this matches the operator UX of the policy editor.
|
|
15
|
+
*
|
|
16
|
+
* Atomicity: `setMode` wraps (a) read fromMode → (b) update Project.mode +
|
|
17
|
+
* modeChangedAt + modeChangedBy → (c) insert ProjectModeLog row in a
|
|
18
|
+
* single Prisma interactive transaction so a partial write never leaves
|
|
19
|
+
* the audit log out of sync with the Project row.
|
|
20
|
+
*/
|
|
21
|
+
import type { PrismaClient } from './prisma.js';
|
|
22
|
+
import { type ProjectModeStore } from '@derwinjs/sdk';
|
|
23
|
+
export interface PrismaProjectModeStoreConfig {
|
|
24
|
+
/** Generated Prisma client. Pass an instance per process. */
|
|
25
|
+
prisma: PrismaClient;
|
|
26
|
+
}
|
|
27
|
+
export declare function createPrismaProjectModeStore(config: PrismaProjectModeStoreConfig): ProjectModeStore;
|
|
28
|
+
//# sourceMappingURL=project-mode-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-mode-store.d.ts","sourceRoot":"","sources":["../src/project-mode-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAML,KAAK,gBAAgB,EAEtB,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,4BAA4B;IAC3C,6DAA6D;IAC7D,MAAM,EAAE,YAAY,CAAC;CACtB;AAgED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,4BAA4B,GACnC,gBAAgB,CA+ElB"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createPrismaProjectModeStore — Prisma-backed implementation of the SDK
|
|
3
|
+
* ProjectModeStore contract introduced by QAP-090.
|
|
4
|
+
*
|
|
5
|
+
* Sprint 9 (Policy + UI, Phase 1). Single choke point for reading and
|
|
6
|
+
* writing `Project.mode` (OBSERVE / TICKET_ONLY / AUTHOR / AUTO — see
|
|
7
|
+
* product brief §11.2). Every mode change goes through `setMode` so the
|
|
8
|
+
* audit log (ProjectModeLog) stays in lockstep with the Project row.
|
|
9
|
+
*
|
|
10
|
+
* Tenant isolation: every read scopes by projectId. `getMode` returns
|
|
11
|
+
* null for unknown projectId; `listLog` returns an empty array. `setMode`
|
|
12
|
+
* throws `project_not_found` (rather than returning null) because a
|
|
13
|
+
* mode-change call against a missing project is a caller bug, not a
|
|
14
|
+
* cross-tenant probe — this matches the operator UX of the policy editor.
|
|
15
|
+
*
|
|
16
|
+
* Atomicity: `setMode` wraps (a) read fromMode → (b) update Project.mode +
|
|
17
|
+
* modeChangedAt + modeChangedBy → (c) insert ProjectModeLog row in a
|
|
18
|
+
* single Prisma interactive transaction so a partial write never leaves
|
|
19
|
+
* the audit log out of sync with the Project row.
|
|
20
|
+
*/
|
|
21
|
+
import { ProjectModeStoreError, ProjectModeValues, } from '@derwinjs/sdk';
|
|
22
|
+
// ─── Validation ──────────────────────────────────────────────────────────
|
|
23
|
+
function validateSetInput(input) {
|
|
24
|
+
if (typeof input.projectId !== 'string' || input.projectId.length === 0) {
|
|
25
|
+
throw new ProjectModeStoreError('invalid_input', 'ProjectModeStore: projectId is required');
|
|
26
|
+
}
|
|
27
|
+
if (!ProjectModeValues.includes(input.toMode)) {
|
|
28
|
+
throw new ProjectModeStoreError('invalid_mode', `ProjectModeStore: toMode must be one of ${ProjectModeValues.join(', ')} (got ${input.toMode})`);
|
|
29
|
+
}
|
|
30
|
+
if (typeof input.reason !== 'string' || input.reason.trim().length === 0) {
|
|
31
|
+
throw new ProjectModeStoreError('invalid_input', 'ProjectModeStore: reason is required');
|
|
32
|
+
}
|
|
33
|
+
if (typeof input.changedBy !== 'string' || input.changedBy.trim().length === 0) {
|
|
34
|
+
throw new ProjectModeStoreError('invalid_input', 'ProjectModeStore: changedBy is required');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function mapProjectRow(row) {
|
|
38
|
+
return {
|
|
39
|
+
projectId: row.id,
|
|
40
|
+
mode: row.mode,
|
|
41
|
+
modeChangedAt: row.modeChangedAt,
|
|
42
|
+
modeChangedBy: row.modeChangedBy,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function mapLogRow(row) {
|
|
46
|
+
return {
|
|
47
|
+
id: row.id,
|
|
48
|
+
projectId: row.projectId,
|
|
49
|
+
fromMode: row.fromMode,
|
|
50
|
+
toMode: row.toMode,
|
|
51
|
+
reason: row.reason,
|
|
52
|
+
changedBy: row.changedBy,
|
|
53
|
+
changedAt: row.changedAt,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// ─── Factory ─────────────────────────────────────────────────────────────
|
|
57
|
+
export function createPrismaProjectModeStore(config) {
|
|
58
|
+
const { prisma } = config;
|
|
59
|
+
return {
|
|
60
|
+
async getMode(input) {
|
|
61
|
+
const row = await prisma.project.findUnique({
|
|
62
|
+
where: { id: input.projectId },
|
|
63
|
+
select: {
|
|
64
|
+
id: true,
|
|
65
|
+
mode: true,
|
|
66
|
+
modeChangedAt: true,
|
|
67
|
+
modeChangedBy: true,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
if (row === null)
|
|
71
|
+
return null;
|
|
72
|
+
return mapProjectRow(row);
|
|
73
|
+
},
|
|
74
|
+
async setMode(input) {
|
|
75
|
+
validateSetInput(input);
|
|
76
|
+
// Atomic: read fromMode → update Project → insert log row.
|
|
77
|
+
// Interactive transaction so all three steps share a snapshot and
|
|
78
|
+
// commit together.
|
|
79
|
+
const updated = await prisma.$transaction(async (tx) => {
|
|
80
|
+
const existing = await tx.project.findUnique({
|
|
81
|
+
where: { id: input.projectId },
|
|
82
|
+
select: { id: true, mode: true },
|
|
83
|
+
});
|
|
84
|
+
if (existing === null) {
|
|
85
|
+
throw new ProjectModeStoreError('project_not_found', `ProjectModeStore: project ${input.projectId} not found`);
|
|
86
|
+
}
|
|
87
|
+
const fromMode = existing.mode;
|
|
88
|
+
const now = new Date();
|
|
89
|
+
const next = await tx.project.update({
|
|
90
|
+
where: { id: input.projectId },
|
|
91
|
+
data: {
|
|
92
|
+
mode: input.toMode,
|
|
93
|
+
modeChangedAt: now,
|
|
94
|
+
modeChangedBy: input.changedBy,
|
|
95
|
+
},
|
|
96
|
+
select: {
|
|
97
|
+
id: true,
|
|
98
|
+
mode: true,
|
|
99
|
+
modeChangedAt: true,
|
|
100
|
+
modeChangedBy: true,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
await tx.projectModeLog.create({
|
|
104
|
+
data: {
|
|
105
|
+
projectId: input.projectId,
|
|
106
|
+
fromMode,
|
|
107
|
+
toMode: input.toMode,
|
|
108
|
+
reason: input.reason,
|
|
109
|
+
changedBy: input.changedBy,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
return next;
|
|
113
|
+
});
|
|
114
|
+
return mapProjectRow(updated);
|
|
115
|
+
},
|
|
116
|
+
async listLog(input) {
|
|
117
|
+
const rows = await prisma.projectModeLog.findMany({
|
|
118
|
+
where: { projectId: input.projectId },
|
|
119
|
+
orderBy: { changedAt: 'desc' },
|
|
120
|
+
take: input.limit ?? 50,
|
|
121
|
+
});
|
|
122
|
+
return rows.map(mapLogRow);
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=project-mode-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-mode-store.js","sourceRoot":"","sources":["../src/project-mode-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -79,7 +79,7 @@ const stubRepo = {
|
|
|
79
79
|
openPR: (_opts) => {
|
|
80
80
|
throw new Error('smoke: stubRepo.openPR called — DRY_RUN should not reach repo');
|
|
81
81
|
},
|
|
82
|
-
mergePR: (
|
|
82
|
+
mergePR: (_input) => {
|
|
83
83
|
throw new Error('smoke: stubRepo.mergePR called — DRY_RUN should not reach repo');
|
|
84
84
|
},
|
|
85
85
|
revertPR: (_prNumber, _reason) => {
|