@pattern-stack/codegen 0.22.0 → 0.23.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/CHANGELOG.md +33 -0
- package/dist/{chunk-NR7QQ6ZI.js → chunk-42763UEE.js} +2 -2
- package/dist/{chunk-6ECCJVYW.js → chunk-4M66MQYA.js} +44 -2
- package/dist/chunk-4M66MQYA.js.map +1 -0
- package/dist/{chunk-FNHNSFIJ.js → chunk-6XP2Q5SS.js} +2 -2
- package/dist/{chunk-VDL5CJ5C.js → chunk-7B7MMDOJ.js} +54 -1
- package/dist/chunk-7B7MMDOJ.js.map +1 -0
- package/dist/{chunk-NXHL5YII.js → chunk-7LKAMLV4.js} +4 -4
- package/dist/{chunk-6DQEIXYU.js → chunk-FIUC6QB5.js} +1 -1
- package/dist/chunk-FIUC6QB5.js.map +1 -0
- package/dist/{chunk-DB5UXJC3.js → chunk-PNCOUFFI.js} +4 -2
- package/dist/chunk-PNCOUFFI.js.map +1 -0
- package/dist/{chunk-QXVCRA23.js → chunk-SH76CFAY.js} +9 -4
- package/dist/chunk-SH76CFAY.js.map +1 -0
- package/dist/runtime/base-classes/index.js +17 -17
- package/dist/runtime/subsystems/auth/auth.module.js +3 -3
- package/dist/runtime/subsystems/auth/index.js +7 -7
- package/dist/runtime/subsystems/bridge/bridge.module.js +4 -4
- package/dist/runtime/subsystems/bridge/index.js +4 -4
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +1 -1
- package/dist/runtime/subsystems/events/events.module.js +2 -2
- package/dist/runtime/subsystems/events/index.js +2 -2
- package/dist/runtime/subsystems/index.js +12 -12
- package/dist/runtime/subsystems/jobs/index.js +3 -3
- package/dist/runtime/subsystems/jobs/job-worker.d.ts +592 -4
- package/dist/runtime/subsystems/jobs/job-worker.js +3 -1
- package/dist/runtime/subsystems/jobs/job-worker.module.js +3 -3
- package/dist/runtime/subsystems/jobs/jobs-domain.module.d.ts +19 -0
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +1 -1
- package/dist/src/cli/index.js +211 -60
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +477 -1
- package/dist/src/index.js +1 -1
- package/package.json +1 -1
- package/runtime/subsystems/events/event-bus.drizzle-backend.ts +23 -7
- package/runtime/subsystems/jobs/job-worker.module.ts +5 -0
- package/runtime/subsystems/jobs/job-worker.ts +126 -12
- package/runtime/subsystems/jobs/jobs-domain.module.ts +19 -0
- package/templates/entity/new/clean-lite-ps/prompt-extension.js +59 -10
- package/templates/subsystem/jobs-config/codegen-config-jobs-block.ejs.t +11 -0
- package/dist/chunk-6DQEIXYU.js.map +0 -1
- package/dist/chunk-6ECCJVYW.js.map +0 -1
- package/dist/chunk-DB5UXJC3.js.map +0 -1
- package/dist/chunk-QXVCRA23.js.map +0 -1
- package/dist/chunk-VDL5CJ5C.js.map +0 -1
- /package/dist/{chunk-NR7QQ6ZI.js.map → chunk-42763UEE.js.map} +0 -0
- /package/dist/{chunk-FNHNSFIJ.js.map → chunk-6XP2Q5SS.js.map} +0 -0
- /package/dist/{chunk-NXHL5YII.js.map → chunk-7LKAMLV4.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Jobs: claim heartbeat (CLAIM-HB-1) — long-running handlers are no longer
|
|
10
|
+
swept mid-flight.** The drizzle `JobWorker` stamped `claimed_at` once at claim
|
|
11
|
+
and never renewed it, while `sweepStaleClaims` reset any `running` row whose
|
|
12
|
+
`claimed_at` aged past `staleThresholdMs` (default 5 min) back to `pending`.
|
|
13
|
+
Consequence: ANY handler that legitimately ran longer than the threshold was
|
|
14
|
+
silently re-queued and re-claimed by a second worker, running CONCURRENTLY
|
|
15
|
+
with the still-live (uncancellable) original. Discovered by the swe-brain
|
|
16
|
+
dogfood: a 365-day Gmail backfill could never finish inside 5 min, so it
|
|
17
|
+
re-spawned a fresh concurrent mailbox walk every ~6 min for 5 days (writes
|
|
18
|
+
were idempotent upserts, so no corruption — but a non-idempotent handler would
|
|
19
|
+
have corrupted). Fix: a live worker now tracks its in-flight run IDs and bumps
|
|
20
|
+
`claimed_at = now()` for them every `claimHeartbeatIntervalMs` (new
|
|
21
|
+
`JobWorkerOptions` knob, default `staleThresholdMs / 3`). The sweeper now
|
|
22
|
+
fires only for genuinely dead workers (renewal stopped) — its documented
|
|
23
|
+
"stranded by a crashed worker" intent.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **Jobs: consumer-threadable lease tuning.** `jobs.extensions.drizzle` now
|
|
28
|
+
accepts `stale_threshold_ms`, `stale_sweeper_interval_ms`, and
|
|
29
|
+
`claim_heartbeat_interval_ms`, threaded through the subsystem barrel generator
|
|
30
|
+
into both `JobsDomainModule.forRoot` and `JobWorkerModule.forRoot` (camelCase
|
|
31
|
+
runtime keys). All optional; the worker defaults the heartbeat to a third of
|
|
32
|
+
the stale threshold.
|
|
33
|
+
|
|
34
|
+
> **Deferred (CLAIM-HB-1 follow-up):** fencing — a claim token on `job_run` so a
|
|
35
|
+
> swept-and-reclaimed run cannot be double-completed by a zombie attempt that
|
|
36
|
+
> finishes after the sweep. Needs a schema/migration change + write-site guards;
|
|
37
|
+
> tracked as issue #501. The heartbeat closes the practical
|
|
38
|
+
> re-claim-loop bug; fencing hardens the residual crash-recovery race.
|
|
39
|
+
|
|
7
40
|
## [0.21.0] — 2026-06-06
|
|
8
41
|
|
|
9
42
|
**FieldMeta enrichment (ADR-040, Phase A of type-aware rendering).** The
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-DUUCU77W.js";
|
|
8
8
|
import {
|
|
9
9
|
DrizzleEventBus
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PNCOUFFI.js";
|
|
11
11
|
import {
|
|
12
12
|
MemoryEventBus
|
|
13
13
|
} from "./chunk-GOO5ZMYO.js";
|
|
@@ -200,4 +200,4 @@ export {
|
|
|
200
200
|
EventSchedulerLifecycle,
|
|
201
201
|
EventsModule
|
|
202
202
|
};
|
|
203
|
-
//# sourceMappingURL=chunk-
|
|
203
|
+
//# sourceMappingURL=chunk-42763UEE.js.map
|
|
@@ -396,9 +396,15 @@ var ProviderIntegrationSchema = z.object({
|
|
|
396
396
|
field_mapping: z.record(z.string(), z.string()).optional(),
|
|
397
397
|
read_only_fields: z.array(z.string()).optional()
|
|
398
398
|
});
|
|
399
|
+
var SinkPolicySchema = z.object({
|
|
400
|
+
delete: z.enum(["soft", "tombstone", "noop"]).optional(),
|
|
401
|
+
// NO .default() — see default fence in spec §Goal
|
|
402
|
+
exclude_fields: z.array(z.string()).optional()
|
|
403
|
+
}).strict();
|
|
399
404
|
var IntegrationConfigSchema = z.object({
|
|
400
405
|
electric: z.boolean().optional().default(false),
|
|
401
|
-
providers: z.record(z.string(), ProviderIntegrationSchema).optional()
|
|
406
|
+
providers: z.record(z.string(), ProviderIntegrationSchema).optional(),
|
|
407
|
+
sink: SinkPolicySchema.optional()
|
|
402
408
|
});
|
|
403
409
|
var EventDeclarationSchema = z.object({
|
|
404
410
|
name: z.string().regex(/^[a-z][a-z0-9_]*$/, "Event name must be snake_case"),
|
|
@@ -567,6 +573,42 @@ var EntityDefinitionSchema = z.object({
|
|
|
567
573
|
});
|
|
568
574
|
}
|
|
569
575
|
}
|
|
576
|
+
}).superRefine((entity, ctx) => {
|
|
577
|
+
const excludeFields = entity.integration?.sink?.exclude_fields;
|
|
578
|
+
if (!excludeFields || excludeFields.length === 0) return;
|
|
579
|
+
const declaredFields = new Set(Object.keys(entity.fields ?? {}));
|
|
580
|
+
const fkColumns = /* @__PURE__ */ new Set();
|
|
581
|
+
for (const rel of Object.values(entity.relationships ?? {})) {
|
|
582
|
+
if (rel.type === "belongs_to" && typeof rel.foreign_key === "string") {
|
|
583
|
+
fkColumns.add(rel.foreign_key);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
for (let i = 0; i < excludeFields.length; i++) {
|
|
587
|
+
const name = excludeFields[i];
|
|
588
|
+
if (!declaredFields.has(name)) {
|
|
589
|
+
ctx.addIssue({
|
|
590
|
+
code: "custom",
|
|
591
|
+
path: ["integration", "sink", "exclude_fields", i],
|
|
592
|
+
message: `exclude_fields: '${name}' is not a declared field. Declared fields: ${[...declaredFields].join(", ")}`
|
|
593
|
+
});
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
if (fkColumns.has(name)) {
|
|
597
|
+
ctx.addIssue({
|
|
598
|
+
code: "custom",
|
|
599
|
+
path: ["integration", "sink", "exclude_fields", i],
|
|
600
|
+
message: `exclude_fields: '${name}' is a FK column (belongs_to foreign_key). Excluding FK columns corrupts the FK-resolver path \u2014 exclude FK columns is not supported. Declare it in exclude_fields only for copy-through scalars.`
|
|
601
|
+
});
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
if (name === "user_id") {
|
|
605
|
+
ctx.addIssue({
|
|
606
|
+
code: "custom",
|
|
607
|
+
path: ["integration", "sink", "exclude_fields", i],
|
|
608
|
+
message: `exclude_fields: 'user_id' cannot be excluded. It is used for user-scoping and EAV dual-write; excluding it would break those mechanisms.`
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
}
|
|
570
612
|
});
|
|
571
613
|
|
|
572
614
|
// src/schema/event-definition.schema.ts
|
|
@@ -4305,4 +4347,4 @@ export {
|
|
|
4305
4347
|
analyzeDomain,
|
|
4306
4348
|
validateEntities
|
|
4307
4349
|
};
|
|
4308
|
-
//# sourceMappingURL=chunk-
|
|
4350
|
+
//# sourceMappingURL=chunk-4M66MQYA.js.map
|