@teamscala/service-boot 0.23.430 → 0.23.432

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.
Files changed (82) hide show
  1. package/package.json +12 -19
  2. package/src/agreement-gate/signing-shell.ts +19 -15
  3. package/src/attach-proposal-accept.ts +5 -2
  4. package/src/auth-gate/public-paths.ts +7 -16
  5. package/src/auth-gate.ts +54 -42
  6. package/src/bind-page-handler.ts +20 -32
  7. package/src/build-client-assets/build-lock.ts +15 -6
  8. package/src/build-client-assets/hashed-output.ts +3 -1
  9. package/src/build-client-assets/hydrate-bundle.ts +59 -57
  10. package/src/build-client-assets/input-fingerprint.ts +50 -57
  11. package/src/build-client-assets/input-hashing.ts +2 -4
  12. package/src/build-client-assets/manifest.ts +8 -11
  13. package/src/build-client-assets/source-candidates.ts +8 -16
  14. package/src/build-client-assets/sourcemaps-upload.ts +17 -10
  15. package/src/build-client-assets/styles-build.ts +17 -19
  16. package/src/build-client-assets.test.ts +2 -2
  17. package/src/build-client-assets.ts +16 -22
  18. package/src/content-gate/access.ts +5 -2
  19. package/src/content-gate/catalog.ts +26 -18
  20. package/src/content-gate/gate.ts +7 -3
  21. package/src/discover-blocks.ts +5 -7
  22. package/src/fn-routers/agreement-certificate.ts +1 -1
  23. package/src/fn-routers/agreement-send-router.ts +5 -4
  24. package/src/fn-routers/agreement-sign-side-effects.ts +27 -22
  25. package/src/fn-routers/assessment-report-email.ts +3 -2
  26. package/src/fn-routers/auth-router.ts +20 -21
  27. package/src/fn-routers/chat-session-router-shared.ts +12 -3
  28. package/src/fn-routers/chat-session-router.ts +8 -6
  29. package/src/fn-routers/conversation-ownership.ts +3 -2
  30. package/src/fn-routers/messaging-whatsapp-router.test.ts +3 -1
  31. package/src/fn-routers/messaging-whatsapp-router.ts +17 -3
  32. package/src/fn-routers/persist-chat-messages.ts +6 -4
  33. package/src/fn-routers/proposal-send-router.ts +4 -3
  34. package/src/fn-routers/public-agreement-router.ts +5 -4
  35. package/src/fn-routers/public-assessment-router.ts +5 -4
  36. package/src/fn-routers/public-gpt-session-router.ts +17 -12
  37. package/src/fn-routers/user-preferences-router.ts +6 -15
  38. package/src/fn-routers/work-items-router.ts +21 -17
  39. package/src/handlers/platform-fault-escalation/delivery.ts +36 -0
  40. package/src/handlers/platform-fault-escalation/orpc-client.ts +38 -18
  41. package/src/handlers/platform-fault-escalation-logic.ts +26 -5
  42. package/src/handlers/platform-fault-escalation.test.ts +67 -15
  43. package/src/handlers/platform-fault-escalation.ts +16 -0
  44. package/src/handlers/projects-digest.ts +1 -1
  45. package/src/handlers/scala-tools-currency-watch.test.ts +1 -5
  46. package/src/handlers/scala-tools-currency-watch.ts +23 -32
  47. package/src/handlers/singleton-tools-currency-watch.test.ts +1 -5
  48. package/src/handlers/singleton-tools-currency-watch.ts +27 -19
  49. package/src/handlers/upstream-issue-sync.ts +11 -4
  50. package/src/handlers/whatsapp-liveness.ts +14 -4
  51. package/src/install-harness.ts +1 -1
  52. package/src/install-logging.ts +1 -1
  53. package/src/mount-orpc-router.test.ts +56 -10
  54. package/src/mount-orpc-router.ts +23 -9
  55. package/src/mount-server-packages.ts +17 -15
  56. package/src/pg-boss-mount.ts +5 -12
  57. package/src/proposal-gate.ts +7 -2
  58. package/src/read-html-template.test.ts +12 -15
  59. package/src/read-html-template.ts +2 -1
  60. package/src/readiness-gate.ts +2 -1
  61. package/src/register-crash-handlers.ts +4 -8
  62. package/src/register-page-server-client.ts +15 -19
  63. package/src/register-registry-page-route/ai-chat-prefetch.ts +16 -12
  64. package/src/register-registry-page-route/apply-page-branding.ts +68 -56
  65. package/src/register-registry-page-route/graph-cache.ts +22 -18
  66. package/src/register-registry-page-route/meta-title.ts +24 -20
  67. package/src/register-registry-page-route/prefetch-org-id.ts +6 -2
  68. package/src/register-registry-page-route/proposal-approval-email-token.ts +5 -3
  69. package/src/register-registry-page-route/run-content-gates.ts +2 -4
  70. package/src/register-registry-page-route.ts +1 -2
  71. package/src/register-static-assets.ts +6 -5
  72. package/src/resolve-app-base-url.ts +12 -5
  73. package/src/resolvers/portal-route-paths.ts +15 -11
  74. package/src/resource-chat-inject.ts +84 -72
  75. package/src/resource-not-found.ts +23 -19
  76. package/src/scala-tools-currency-watchdog.ts +41 -12
  77. package/src/two-phase-full-app.ts +61 -29
  78. package/src/two-phase-minimal-app.ts +39 -31
  79. package/src/two-phase-readiness.ts +50 -38
  80. package/src/ui-service.ts +50 -38
  81. package/src/handlers/pane-outbox-drain.ts +0 -39
  82. package/src/handlers/prune-stale-data.ts +0 -110
@@ -1,110 +0,0 @@
1
- /**
2
- * @system server-boot
3
- * @status handwritten
4
- * @edit edit directly
5
- *
6
- * The `db-prune-stale-data` pg-boss handler. Reads the `retention` map from the
7
- * `scheduled_job` row config and prunes stale rows per entry.
8
- *
9
- * Writes use Prisma ORM methods (deleteMany/updateMany) via the prisma-registry
10
- * client — NEVER raw SQL. The `@teamscala/db` client carries the `blockRawSqlWrites`
11
- * audit extension: `$executeRaw`/`$executeRawUnsafe` are blocked so every write
12
- * is audited; ORM methods are the canonical audited path.
13
- *
14
- * SAFETY — identifier allowlist: each retention key selects a FIXED, hardcoded
15
- * Prisma model + field (table/field names are literal in code, never derived
16
- * from the row); the row's value (a duration string) is parsed to a cutoff Date.
17
- * A row can therefore never inject arbitrary SQL or address an unvetted model.
18
- * Keys not in the allowlist are skipped + logged.
19
- *
20
- * `audit_trail.*` is INTENTIONALLY EXCLUDED: `audit-trail-permanent` (critical)
21
- * forbids any DELETE FROM audit_trail. The legacy row's
22
- * `audit_trail.sync_entities: "delete all"` entry is stale drift from before
23
- * the 2026-06-19 hardening — surfaced (skipped + warned), never executed.
24
- *
25
- * Registered under slug `@teamscala/service-boot:prune-stale-data`.
26
- */
27
- import type { ScheduledJobConfig } from "@teamscala/db-validation/registry-schemas/scheduled-job";
28
- import { Prisma } from "@teamscala/db/client";
29
- import { getPrisma } from "@teamscala/db/prisma-registry";
30
- import { getAppLogger } from "@teamscala/logger/app-loggers";
31
- import { pgBossHandlerRegistry } from "../pg-boss-handler-registry.ts";
32
-
33
- const DURATION_RE = /^(\d+)\s+(second|minute|hour|day|week|month|year)s?$/;
34
- const UNIT_TO_MS: Record<string, number> = {
35
- second: 1_000,
36
- minute: 60_000,
37
- hour: 3_600_000,
38
- day: 86_400_000,
39
- week: 604_800_000,
40
- month: 2_592_000_000,
41
- year: 31_536_000_000,
42
- };
43
-
44
- type PrismaClient = ReturnType<typeof getPrisma>;
45
- type PruneOp = (prisma: PrismaClient, cutoff: Date) => Promise<number>;
46
-
47
- // Fixed ops — model + field names literal in code, cutoff Date is the only
48
- // variable. Adding a prunable target = adding an entry here (and confirming the
49
- // model/field + audit-trail-permanent scope).
50
- const PRUNE_OPS: Record<string, PruneOp> = {
51
- "fleet_run_events": async (prisma, cutoff) =>
52
- (await prisma.fleet_run_events.deleteMany({ where: { created_at: { lt: cutoff } } })).count,
53
- "fleet_run_transitions": async (prisma, cutoff) =>
54
- (await prisma.fleet_run_transitions.deleteMany({ where: { created_at: { lt: cutoff } } })).count,
55
- // Null out the bulky transcript JSON of old runs — keep the run row itself.
56
- // A nullable-Json column requires Prisma's DbNull sentinel (bare `null` is
57
- // ambiguous: JSON null vs SQL NULL); DbNull sets the column to SQL NULL.
58
- // Prisma namespace is re-exported from @teamscala/db/client.
59
- "fleet_agent_runs.transcript": async (prisma, cutoff) =>
60
- (
61
- await prisma.fleet_agent_runs.updateMany({
62
- where: { created_at: { lt: cutoff } },
63
- data: { transcript: Prisma.DbNull },
64
- })
65
- ).count,
66
- };
67
-
68
- export async function pruneStaleData({
69
- config,
70
- }: {
71
- config: ScheduledJobConfig;
72
- }): Promise<void> {
73
- const log = getAppLogger();
74
- const retention = config.retention;
75
- if (!retention || Object.keys(retention).length === 0) {
76
- log.info("[db-prune-stale-data] no retention entries — nothing to prune");
77
- return;
78
- }
79
- const prisma = getPrisma();
80
- let ran = 0;
81
- let skipped = 0;
82
- for (const [key, rawValue] of Object.entries(retention)) {
83
- const op = PRUNE_OPS[key];
84
- if (!op) {
85
- log.warn(
86
- `[db-prune-stale-data] skipping "${key}" — not in the prune allowlist ` +
87
- `(audit_trail is excluded by audit-trail-permanent; add the op explicitly to enable)`,
88
- );
89
- skipped++;
90
- continue;
91
- }
92
- const match = DURATION_RE.exec(rawValue.trim());
93
- if (!match) {
94
- log.warn(
95
- `[db-prune-stale-data] skipping "${key}" — value "${rawValue}" is not a duration (expected e.g. "1 day")`,
96
- );
97
- skipped++;
98
- continue;
99
- }
100
- const cutoff = new Date(Date.now() - Number(match[1]) * UNIT_TO_MS[match[2]!]);
101
- const affected = await op(prisma, cutoff);
102
- log.info(
103
- `[db-prune-stale-data] pruned "${key}" older than ${rawValue} — ${affected} row(s) affected`,
104
- );
105
- ran++;
106
- }
107
- log.info(`[db-prune-stale-data] complete — ${ran} op(s) ran, ${skipped} skipped`);
108
- }
109
-
110
- pgBossHandlerRegistry.register("@teamscala/service-boot:prune-stale-data", pruneStaleData);