Showing the changes to scripts/migration/service-split-postgres-cli.ts (1 of 2 files). Show all
Unified · Split
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | /* oxlint-disable executor/no-error-constructor, executor/no-try-catch-or-throw -- boundary: one-shot migration CLI */ |
| 2 | 2 | |
| 3 | +import { createHash } from "node:crypto"; | |
| 3 | 4 | import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; |
| 4 | 5 | import { resolve } from "node:path"; |
| 5 | 6 | import { pathToFileURL } from "node:url"; |
| @@ -220,14 +221,10 @@ const scrubJson = (value: unknown): unknown => { · 214 unmodified lines | ||
| 220 | 221 | return value; |
| 221 | 222 | }; |
| 222 | 223 | |
| 223 | −const stableId = (...parts: readonly string[]): string => { | |
| 224 | − const text = parts.join("\u0000"); | |
| 225 | − let hash = 0; | |
| 226 | − for (let index = 0; index < text.length; index += 1) { | |
| 227 | − hash = (hash * 31 + text.charCodeAt(index)) >>> 0; | |
| 228 | − } | |
| 229 | − return `service_split_${hash.toString(36)}`; | |
| 230 | −}; | |
| 224 | +// sha256-based: a 31-bit hash collides around ~50k rows (observed in prod); | |
| 225 | +// 96 bits keeps re-run determinism with no realistic collision risk. | |
| 226 | +const stableId = (...parts: readonly string[]): string => | |
| 227 | + `service_split_${createHash("sha256").update(parts.join("\u0000")).digest("hex").slice(0, 24)}`; | |
| 231 | 228 | |
| 232 | 229 | const operationKeyPrefix = (integration: string): string => |
| 233 | 230 | `${operationStorageKey(integration, "").split(".").slice(0, 2).join(".")}.%`; |
| @@ -280,8 +277,8 @@ export const applyOrg = async (sql: SqlClient, org: OrgPlan): Promise<void> => { · 46 unmodified lines | ||
| 280 | 277 | row.target.pluginId, |
| 281 | 278 | row.target.name, |
| 282 | 279 | row.target.description, |
| 283 | − JSON.stringify(scrubJson(row.config)), | |
| 284 | − row.healthCheck ? JSON.stringify(scrubJson(row.healthCheck)) : null, | |
| 280 | + scrubJson(row.config), | |
| 281 | + row.healthCheck ? scrubJson(row.healthCheck) : null, | |
| 285 | 282 | now, |
| 286 | 283 | stableId("integration", org.tenant, row.target.slug), |
| 287 | 284 | org.tenant, |
| @@ -391,13 +388,11 @@ export const applyOrg = async (sql: SqlClient, org: OrgPlan): Promise<void> => { · 103 unmodified lines | ||
| 391 | 388 | params.push( |
| 392 | 389 | integration.target.pluginId, |
| 393 | 390 | operationStorageKey(integration.target.slug, toolName), |
| 394 | − JSON.stringify( | |
| 395 | − scrubJson({ | |
| 396 | − ...storageDataRecord(operation), | |
| 397 | − integration: integration.target.slug, | |
| 398 | − toolName, | |
| 399 | − }), | |
| 400 | − ), | |
| 391 | + scrubJson({ | |
| 392 | + ...storageDataRecord(operation), | |
| 393 | + integration: integration.target.slug, | |
| 394 | + toolName, | |
| 395 | + }), | |
| 401 | 396 | operation.created_at, |
| 402 | 397 | now, |
| 403 | 398 | stableId("operation", org.tenant, integration.target.slug, toolName), |