@cosmicdrift/kumiko-framework 0.335.0 → 0.336.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/api/anonymous-live-entities.d.ts +2 -0
- package/dist/api/anonymous-live-entities.js +17 -0
- package/dist/api/index.d.ts +2 -1
- package/dist/api/index.js +1 -0
- package/dist/api/server.js +6 -3
- package/dist/api/sse-route.d.ts +4 -1
- package/dist/api/sse-route.js +38 -11
- package/dist/db/blind-index-cleanup.js +27 -16
- package/dist/db/event-store-executor-read.js +6 -2
- package/dist/engine/boot-validator/query-output-columns.js +12 -0
- package/dist/engine/boot-validator/screens.js +22 -13
- package/dist/engine/build-app-schema.js +3 -1
- package/dist/engine/create-app.js +10 -1
- package/dist/engine/extension-names.d.ts +4 -0
- package/dist/engine/extension-names.js +4 -0
- package/dist/engine/feature-ast/extractors/handlers.js +1 -0
- package/dist/engine/feature-entity-handlers.d.ts +1 -0
- package/dist/engine/feature-entity-handlers.js +2 -0
- package/dist/engine/registry-validate.d.ts +1 -0
- package/dist/engine/registry-validate.js +14 -0
- package/dist/engine/registry.js +2 -1
- package/dist/engine/steps/_event-match.js +12 -4
- package/dist/engine/system-user.d.ts +1 -0
- package/dist/engine/system-user.js +3 -0
- package/dist/env/dry-run.js +10 -3
- package/dist/event-store/event-store.js +4 -1
- package/dist/jobs/job-runner.js +29 -7
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.js +1 -1
- package/dist/observability/standard-metrics.d.ts +4 -0
- package/dist/observability/standard-metrics.js +16 -0
- package/dist/pipeline/event-dispatcher-delivery.js +5 -0
- package/dist/pipeline/event-dispatcher.js +4 -1
- package/dist/pipeline/system-hooks.js +10 -13
- package/dist/pipeline/write-origin.js +13 -6
- package/dist/stack/drain-event-consumers.js +3 -0
- package/dist/stack/drain-jobs.d.ts +3 -1
- package/dist/stack/drain-jobs.js +31 -1
- package/package.json +4 -4
- package/src/changes.json +58 -0
- package/src/scripts/codemod/pii-personal-migration.ts +56 -26
- package/src/scripts/codemod/unprocessable-error-details-reason.ts +61 -24
|
@@ -105,9 +105,25 @@ function resolveDetailsProperty(optsLiteral: ObjectLiteralExpression): DetailsRe
|
|
|
105
105
|
/** True if removing this shorthand-bound identifier would leave its declaration with no other use. */
|
|
106
106
|
function wouldLeaveUnusedVariable(nameNode: Identifier): boolean {
|
|
107
107
|
try {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
// The shorthand name resolves to the object-literal property symbol too, and
|
|
109
|
+
// a declaration counts as a reference, so look up the variable's own uses.
|
|
110
|
+
const shorthand = nameNode.getParent();
|
|
111
|
+
const variableSymbol = Node.isShorthandPropertyAssignment(shorthand)
|
|
112
|
+
? shorthand.getValueSymbol()
|
|
113
|
+
: undefined;
|
|
114
|
+
const declarations = variableSymbol?.getDeclarations() ?? [];
|
|
115
|
+
const declarationNames = declarations.flatMap((declaration) =>
|
|
116
|
+
Node.isVariableDeclaration(declaration) || Node.isParameterDeclaration(declaration)
|
|
117
|
+
? [declaration.getNameNode()]
|
|
118
|
+
: [],
|
|
119
|
+
);
|
|
120
|
+
// No resolvable declaration: can't verify, treat as unsafe.
|
|
121
|
+
if (declarationNames.length === 0) return true;
|
|
122
|
+
return declarationNames
|
|
123
|
+
.flatMap((declarationName) =>
|
|
124
|
+
Node.isIdentifier(declarationName) ? declarationName.findReferencesAsNodes() : [],
|
|
125
|
+
)
|
|
126
|
+
.every((usage) => usage === nameNode);
|
|
111
127
|
} catch {
|
|
112
128
|
// Can't verify — treat as unsafe rather than guess.
|
|
113
129
|
return true;
|
|
@@ -122,12 +138,11 @@ type RemovalResult =
|
|
|
122
138
|
/** Removes the `reason` property from a `details` object literal, in place. */
|
|
123
139
|
function removeReasonProperty(detailsLiteral: ObjectLiteralExpression): RemovalResult {
|
|
124
140
|
const properties = detailsLiteral.getProperties();
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
141
|
+
const hasSpread = properties.some((p) => Node.isSpreadAssignment(p));
|
|
142
|
+
const spreadSkip: RemovalResult = {
|
|
143
|
+
kind: "skip",
|
|
144
|
+
note: "details object literal has a spread next to an explicit reason — not statically decidable",
|
|
145
|
+
};
|
|
131
146
|
|
|
132
147
|
for (const prop of properties) {
|
|
133
148
|
if (Node.isPropertyAssignment(prop)) {
|
|
@@ -145,12 +160,14 @@ function removeReasonProperty(detailsLiteral: ObjectLiteralExpression): RemovalR
|
|
|
145
160
|
? nameNode.getLiteralText()
|
|
146
161
|
: undefined;
|
|
147
162
|
if (propName === "reason") {
|
|
163
|
+
if (hasSpread) return spreadSkip;
|
|
148
164
|
prop.remove();
|
|
149
165
|
return { kind: "removed" };
|
|
150
166
|
}
|
|
151
167
|
continue;
|
|
152
168
|
}
|
|
153
169
|
if (Node.isShorthandPropertyAssignment(prop) && prop.getName() === "reason") {
|
|
170
|
+
if (hasSpread) return spreadSkip;
|
|
154
171
|
if (wouldLeaveUnusedVariable(prop.getNameNode())) {
|
|
155
172
|
return {
|
|
156
173
|
kind: "skip",
|
|
@@ -166,13 +183,20 @@ function removeReasonProperty(detailsLiteral: ObjectLiteralExpression): RemovalR
|
|
|
166
183
|
|
|
167
184
|
type CallOutcome = "changed" | "skipped" | "not-a-match";
|
|
168
185
|
|
|
169
|
-
|
|
186
|
+
// "manual": a concrete `reason` the codemod found but cannot remove safely.
|
|
187
|
+
// "unverified": opts/details not statically analyzable — may well be fine, so
|
|
188
|
+
// it is listed apart to keep the actionable list short.
|
|
189
|
+
type SkipKind = "manual" | "unverified";
|
|
190
|
+
type ReportSkip = (note: string, kind: SkipKind) => void;
|
|
191
|
+
|
|
192
|
+
function processNewExpression(args: readonly Node[], report: ReportSkip): CallOutcome {
|
|
170
193
|
const optsArg = args[1];
|
|
171
194
|
if (!optsArg) return "not-a-match";
|
|
172
195
|
|
|
173
196
|
if (!Node.isObjectLiteralExpression(optsArg)) {
|
|
174
197
|
report(
|
|
175
198
|
"second argument (opts) is not a statically-analyzable object literal — cannot verify details.reason",
|
|
199
|
+
"unverified",
|
|
176
200
|
);
|
|
177
201
|
return "skipped";
|
|
178
202
|
}
|
|
@@ -180,14 +204,14 @@ function processNewExpression(args: readonly Node[], report: (note: string) => v
|
|
|
180
204
|
const detailsRes = resolveDetailsProperty(optsArg);
|
|
181
205
|
if (detailsRes.kind === "absent") return "not-a-match";
|
|
182
206
|
if (detailsRes.kind === "unresolvable") {
|
|
183
|
-
report(detailsRes.note);
|
|
207
|
+
report(detailsRes.note, "unverified");
|
|
184
208
|
return "skipped";
|
|
185
209
|
}
|
|
186
210
|
|
|
187
211
|
const removal = removeReasonProperty(detailsRes.literal);
|
|
188
212
|
if (removal.kind === "absent") return "not-a-match";
|
|
189
213
|
if (removal.kind === "skip") {
|
|
190
|
-
report(removal.note);
|
|
214
|
+
report(removal.note, "manual");
|
|
191
215
|
return "skipped";
|
|
192
216
|
}
|
|
193
217
|
return "changed";
|
|
@@ -195,16 +219,14 @@ function processNewExpression(args: readonly Node[], report: (note: string) => v
|
|
|
195
219
|
|
|
196
220
|
// `failUnprocessable(reason, details)` takes the details literal directly as
|
|
197
221
|
// its second argument (no `{ details }` wrapper like the ctor's opts).
|
|
198
|
-
function processFailUnprocessableCall(
|
|
199
|
-
args: readonly Node[],
|
|
200
|
-
report: (note: string) => void,
|
|
201
|
-
): CallOutcome {
|
|
222
|
+
function processFailUnprocessableCall(args: readonly Node[], report: ReportSkip): CallOutcome {
|
|
202
223
|
const detailsArg = args[1];
|
|
203
224
|
if (!detailsArg) return "not-a-match";
|
|
204
225
|
|
|
205
226
|
if (!Node.isObjectLiteralExpression(detailsArg)) {
|
|
206
227
|
report(
|
|
207
228
|
"second argument (details) is not a statically-analyzable object literal — cannot verify details.reason",
|
|
229
|
+
"unverified",
|
|
208
230
|
);
|
|
209
231
|
return "skipped";
|
|
210
232
|
}
|
|
@@ -212,18 +234,23 @@ function processFailUnprocessableCall(
|
|
|
212
234
|
const removal = removeReasonProperty(detailsArg);
|
|
213
235
|
if (removal.kind === "absent") return "not-a-match";
|
|
214
236
|
if (removal.kind === "skip") {
|
|
215
|
-
report(removal.note);
|
|
237
|
+
report(removal.note, "manual");
|
|
216
238
|
return "skipped";
|
|
217
239
|
}
|
|
218
240
|
return "changed";
|
|
219
241
|
}
|
|
220
242
|
|
|
221
|
-
type SkipEntry = {
|
|
243
|
+
type SkipEntry = {
|
|
244
|
+
readonly file: string;
|
|
245
|
+
readonly line: number;
|
|
246
|
+
readonly note: string;
|
|
247
|
+
readonly kind: SkipKind;
|
|
248
|
+
};
|
|
222
249
|
|
|
223
250
|
type MigratableCall = {
|
|
224
251
|
readonly exportName: "UnprocessableError" | "failUnprocessable";
|
|
225
252
|
readonly localKind: "class" | "function";
|
|
226
|
-
readonly process: (args: readonly Node[], report:
|
|
253
|
+
readonly process: (args: readonly Node[], report: ReportSkip) => CallOutcome;
|
|
227
254
|
};
|
|
228
255
|
|
|
229
256
|
const UNPROCESSABLE_ERROR_CTOR: MigratableCall = {
|
|
@@ -256,7 +283,7 @@ function migrateCallSite(
|
|
|
256
283
|
const note = binding
|
|
257
284
|
? `${target.exportName} is imported from "${binding.moduleSpecifier}", not a @cosmicdrift/kumiko-* package`
|
|
258
285
|
: `${target.exportName} has no @cosmicdrift/kumiko-* import in this file (likely a locally defined ${target.localKind})`;
|
|
259
|
-
skips.push({ file, line, note });
|
|
286
|
+
skips.push({ file, line, note, kind: "manual" });
|
|
260
287
|
return false;
|
|
261
288
|
}
|
|
262
289
|
if (!KUMIKO_MODULE_RE.test(binding.moduleSpecifier)) {
|
|
@@ -264,11 +291,14 @@ function migrateCallSite(
|
|
|
264
291
|
file,
|
|
265
292
|
line,
|
|
266
293
|
note: `${target.exportName} is imported from "${binding.moduleSpecifier}", not a @cosmicdrift/kumiko-* package`,
|
|
294
|
+
kind: "manual",
|
|
267
295
|
});
|
|
268
296
|
return false;
|
|
269
297
|
}
|
|
270
298
|
|
|
271
|
-
const outcome = target.process(site.getArguments(), (note) =>
|
|
299
|
+
const outcome = target.process(site.getArguments(), (note, kind) =>
|
|
300
|
+
skips.push({ file, line, note, kind }),
|
|
301
|
+
);
|
|
272
302
|
return outcome === "changed";
|
|
273
303
|
}
|
|
274
304
|
|
|
@@ -320,9 +350,16 @@ async function main(): Promise<void> {
|
|
|
320
350
|
console.log(
|
|
321
351
|
`Touched ${touchedFiles} files, removed ${removedTotal} redundant "reason" propert(y/ies).`,
|
|
322
352
|
);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
console.log(
|
|
353
|
+
for (const kind of ["manual", "unverified"] as const) {
|
|
354
|
+
const ofKind = skips.filter((s) => s.kind === kind);
|
|
355
|
+
console.log(
|
|
356
|
+
kind === "manual"
|
|
357
|
+
? `Skipped ${ofKind.length} site(s) needing manual work:`
|
|
358
|
+
: `Unverified ${ofKind.length} site(s) (opts/details not statically analyzable, may be fine):`,
|
|
359
|
+
);
|
|
360
|
+
for (const s of ofKind) {
|
|
361
|
+
console.log(` ${relative(rootDir, s.file)}:${s.line} — ${s.note}`);
|
|
362
|
+
}
|
|
326
363
|
}
|
|
327
364
|
console.log();
|
|
328
365
|
}
|