@open-mercato/core 0.6.3-develop.3586.1.d5a44c810f → 0.6.3-develop.3593.1.8eda8943fa

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.
@@ -1,4 +1,4 @@
1
- [build:core] found 2553 entry points
1
+ [build:core] found 2554 entry points
2
2
  [build:core] built successfully
3
3
  [build:core:generated] found 172 entry points
4
4
  [build:core:generated] built successfully
@@ -1,35 +1,9 @@
1
- import { sql } from "@mikro-orm/postgresql";
2
- const PERSON_COMPANY_LINKS_TABLE = "customer_person_company_links";
3
- const PERSON_COMPANY_LINKS_DELETED_AT_COLUMN = "deleted_at";
4
- let supportsDeletedAtColumnPromise = null;
5
- let warnedAboutMissingDeletedAtColumn = false;
6
- async function customerPersonCompanyLinksSupportDeletedAt(em) {
7
- if (typeof em.getKysely !== "function") {
8
- return true;
9
- }
10
- if (!supportsDeletedAtColumnPromise) {
11
- const db = em.getKysely();
12
- const probe = db.selectFrom("information_schema.columns").select(["column_name"]).where(sql`table_schema = current_schema()`).where("table_name", "=", PERSON_COMPANY_LINKS_TABLE).where("column_name", "=", PERSON_COMPANY_LINKS_DELETED_AT_COLUMN).executeTakeFirst().then((row) => !!row).catch(() => false);
13
- supportsDeletedAtColumnPromise = probe;
14
- return probe;
15
- }
16
- return supportsDeletedAtColumnPromise;
1
+ async function customerPersonCompanyLinksSupportDeletedAt(_em) {
2
+ return true;
17
3
  }
18
- function warnMissingCustomerPersonCompanyLinksDeletedAt(source) {
19
- if (warnedAboutMissingDeletedAtColumn) {
20
- return;
21
- }
22
- warnedAboutMissingDeletedAtColumn = true;
23
- console.warn(
24
- `[${source}] missing ${PERSON_COMPANY_LINKS_TABLE}.${PERSON_COMPANY_LINKS_DELETED_AT_COLUMN}; continuing without link soft-delete filtering. Run yarn db:migrate.`
25
- );
4
+ function warnMissingCustomerPersonCompanyLinksDeletedAt(_source) {
26
5
  }
27
- async function withActiveCustomerPersonCompanyLinkFilter(em, where, source) {
28
- const supportsDeletedAt = await customerPersonCompanyLinksSupportDeletedAt(em);
29
- if (!supportsDeletedAt) {
30
- warnMissingCustomerPersonCompanyLinksDeletedAt(source);
31
- return { ...where };
32
- }
6
+ async function withActiveCustomerPersonCompanyLinkFilter(_em, where, _source) {
33
7
  return { ...where, deletedAt: null };
34
8
  }
35
9
  function filterActivePersonCompanyLinks(links) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/lib/personCompanyLinkTable.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { sql } from '@mikro-orm/postgresql'\n\nconst PERSON_COMPANY_LINKS_TABLE = 'customer_person_company_links'\nconst PERSON_COMPANY_LINKS_DELETED_AT_COLUMN = 'deleted_at'\n\nlet supportsDeletedAtColumnPromise: Promise<boolean> | null = null\nlet warnedAboutMissingDeletedAtColumn = false\n\nexport async function customerPersonCompanyLinksSupportDeletedAt(em: EntityManager): Promise<boolean> {\n if (typeof (em as { getKysely?: unknown }).getKysely !== 'function') {\n return true\n }\n if (!supportsDeletedAtColumnPromise) {\n const db = em.getKysely<any>() as any\n const probe: Promise<boolean> = db\n .selectFrom('information_schema.columns')\n .select(['column_name'])\n .where(sql<boolean>`table_schema = current_schema()`)\n .where('table_name', '=', PERSON_COMPANY_LINKS_TABLE)\n .where('column_name', '=', PERSON_COMPANY_LINKS_DELETED_AT_COLUMN)\n .executeTakeFirst()\n .then((row: unknown) => !!row)\n .catch(() => false)\n supportsDeletedAtColumnPromise = probe\n return probe\n }\n return supportsDeletedAtColumnPromise\n}\n\nexport function warnMissingCustomerPersonCompanyLinksDeletedAt(source: string): void {\n if (warnedAboutMissingDeletedAtColumn) {\n return\n }\n warnedAboutMissingDeletedAtColumn = true\n console.warn(\n `[${source}] missing ${PERSON_COMPANY_LINKS_TABLE}.${PERSON_COMPANY_LINKS_DELETED_AT_COLUMN}; ` +\n 'continuing without link soft-delete filtering. Run yarn db:migrate.',\n )\n}\n\nexport async function withActiveCustomerPersonCompanyLinkFilter<T extends Record<string, unknown>>(\n em: EntityManager,\n where: T,\n source: string,\n): Promise<T & { deletedAt?: null }> {\n const supportsDeletedAt = await customerPersonCompanyLinksSupportDeletedAt(em)\n if (!supportsDeletedAt) {\n warnMissingCustomerPersonCompanyLinksDeletedAt(source)\n return { ...where }\n }\n return { ...where, deletedAt: null }\n}\n\n/**\n * Drop soft-deleted link rows from a result set as a defense-in-depth fallback.\n * MikroORM has historically dropped `deletedAt: null` from the WHERE clause for\n * nullable date columns under certain configurations, so callers SHOULD apply this\n * after `findWithDecryption(...)` until the upstream query filter is verified to\n * fully cover all callers.\n */\nexport function filterActivePersonCompanyLinks<T extends { deletedAt?: Date | string | null | undefined }>(\n links: T[] | null | undefined,\n): T[] {\n if (!Array.isArray(links)) return []\n return links.filter((entry) => entry?.deletedAt == null)\n}\n"],
5
- "mappings": "AACA,SAAS,WAAW;AAEpB,MAAM,6BAA6B;AACnC,MAAM,yCAAyC;AAE/C,IAAI,iCAA0D;AAC9D,IAAI,oCAAoC;AAExC,eAAsB,2CAA2C,IAAqC;AACpG,MAAI,OAAQ,GAA+B,cAAc,YAAY;AACnE,WAAO;AAAA,EACT;AACA,MAAI,CAAC,gCAAgC;AACnC,UAAM,KAAK,GAAG,UAAe;AAC7B,UAAM,QAA0B,GAC7B,WAAW,4BAA4B,EACvC,OAAO,CAAC,aAAa,CAAC,EACtB,MAAM,oCAA6C,EACnD,MAAM,cAAc,KAAK,0BAA0B,EACnD,MAAM,eAAe,KAAK,sCAAsC,EAChE,iBAAiB,EACjB,KAAK,CAAC,QAAiB,CAAC,CAAC,GAAG,EAC5B,MAAM,MAAM,KAAK;AACpB,qCAAiC;AACjC,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,+CAA+C,QAAsB;AACnF,MAAI,mCAAmC;AACrC;AAAA,EACF;AACA,sCAAoC;AACpC,UAAQ;AAAA,IACN,IAAI,MAAM,aAAa,0BAA0B,IAAI,sCAAsC;AAAA,EAE7F;AACF;AAEA,eAAsB,0CACpB,IACA,OACA,QACmC;AACnC,QAAM,oBAAoB,MAAM,2CAA2C,EAAE;AAC7E,MAAI,CAAC,mBAAmB;AACtB,mDAA+C,MAAM;AACrD,WAAO,EAAE,GAAG,MAAM;AAAA,EACpB;AACA,SAAO,EAAE,GAAG,OAAO,WAAW,KAAK;AACrC;AASO,SAAS,+BACd,OACK;AACL,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,SAAO,MAAM,OAAO,CAAC,UAAU,OAAO,aAAa,IAAI;AACzD;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\n\n// The previous implementation probed `information_schema.columns` on every\n// first call via `em.getKysely()` to decide whether to add a `deletedAt: null`\n// filter. When that probe ran inside an already-active MikroORM transaction it\n// shared the transaction's connection \u2014 and any failure (including transient\n// connection-pool state, an aborted TX from a sibling query, or pg returning\n// 25P02) propagated back into the host transaction, poisoning every following\n// query with `current transaction is aborted, commands ignored until end of\n// transaction block`. That is what produced the standalone-CI failure burst\n// (loadPersonCompanyLinks \u2192 25P02 \u2192 customers.people.create \u2192 500) and the\n// sync_excel worker `failedCount: 1` regression.\n//\n// The `deleted_at` column on `customer_person_company_links` has been part of\n// the committed module snapshot since `Migration20260415095203` (April 2026)\n// and is referenced by `Migration20260417140000` (partial unique index uses\n// `where deleted_at is null`). Any environment running these migrations\n// already has the column. So the probe is no longer load-bearing \u2014 it only\n// adds risk. We now unconditionally include `deletedAt: null` in the filter.\n// If a downstream DB is genuinely un-migrated, the underlying `em.find` will\n// surface the authentic `column \"deleted_at\" of relation\n// \"customer_person_company_links\" does not exist` (pg 42703) pointing the\n// operator at the real fix (`yarn db:migrate`).\n//\n// `customerPersonCompanyLinksSupportDeletedAt` and\n// `warnMissingCustomerPersonCompanyLinksDeletedAt` are kept as exported\n// no-op-equivalents so external callers (and the published @open-mercato/core\n// API surface) don't break.\n\nexport async function customerPersonCompanyLinksSupportDeletedAt(_em: EntityManager): Promise<boolean> {\n return true\n}\n\nexport function warnMissingCustomerPersonCompanyLinksDeletedAt(_source: string): void {\n // No-op: column is guaranteed present by Migration20260415095203 and the\n // module snapshot. Kept for backward-compatible exports.\n}\n\nexport async function withActiveCustomerPersonCompanyLinkFilter<T extends Record<string, unknown>>(\n _em: EntityManager,\n where: T,\n _source: string,\n): Promise<T & { deletedAt?: null }> {\n return { ...where, deletedAt: null }\n}\n\n/**\n * Drop soft-deleted link rows from a result set as a defense-in-depth fallback.\n * MikroORM has historically dropped `deletedAt: null` from the WHERE clause for\n * nullable date columns under certain configurations, so callers SHOULD apply this\n * after `findWithDecryption(...)` until the upstream query filter is verified to\n * fully cover all callers.\n */\nexport function filterActivePersonCompanyLinks<T extends { deletedAt?: Date | string | null | undefined }>(\n links: T[] | null | undefined,\n): T[] {\n if (!Array.isArray(links)) return []\n return links.filter((entry) => entry?.deletedAt == null)\n}\n"],
5
+ "mappings": "AA6BA,eAAsB,2CAA2C,KAAsC;AACrG,SAAO;AACT;AAEO,SAAS,+CAA+C,SAAuB;AAGtF;AAEA,eAAsB,0CACpB,KACA,OACA,SACmC;AACnC,SAAO,EAAE,GAAG,OAAO,WAAW,KAAK;AACrC;AASO,SAAS,+BACd,OACK;AACL,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,SAAO,MAAM,OAAO,CAAC,UAAU,OAAO,aAAa,IAAI;AACzD;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,12 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260521175027 extends Migration {
3
+ async up() {
4
+ this.addSql(`alter table "customer_person_company_links" add column if not exists "deleted_at" timestamptz null;`);
5
+ }
6
+ async down() {
7
+ }
8
+ }
9
+ export {
10
+ Migration20260521175027
11
+ };
12
+ //# sourceMappingURL=Migration20260521175027.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/customers/migrations/Migration20260521175027.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\n/**\n * Idempotent backstop for `customer_person_company_links.deleted_at`.\n *\n * The column was originally added by `Migration20260415095203` and is\n * referenced by `Migration20260417140000`'s partial unique index\n * (`where \"deleted_at\" is null`). It is part of the committed\n * `migrations/.snapshot-open-mercato.json`.\n *\n * However, the runtime defensive probe that lived in\n * `packages/core/src/modules/customers/lib/personCompanyLinkTable.ts`\n * historically existed because an aborted-transaction state on a\n * shared connection could (very rarely) make `loadPersonCompanyLinks`\n * fail in a way that *looked* like the column was missing \u2014 and the\n * cached fallback then silently dropped the `deletedAt: null` filter.\n * That probe is removed in the same change as this migration (no\n * Kysely query is ever issued from inside an active MikroORM TX);\n * this migration is the matching belt-and-suspenders guarantee that\n * the column is physically present so the unconditional `deletedAt:\n * null` filter cannot 42703.\n *\n * Postgres-native `add column if not exists` is used so this re-applies\n * cleanly on already-migrated databases without raising.\n */\nexport class Migration20260521175027 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`alter table \"customer_person_company_links\" add column if not exists \"deleted_at\" timestamptz null;`);\n }\n\n override async down(): Promise<void> {\n // No-op on the way down: dropping the column would break\n // `Migration20260417140000`'s partial unique index, which is the\n // authoritative owner of the column going forward. The original\n // `Migration20260415095203` down still drops it for full rollback.\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAyBnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,qGAAqG;AAAA,EACnH;AAAA,EAEA,MAAe,OAAsB;AAAA,EAKrC;AAEF;",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.3-develop.3586.1.d5a44c810f",
3
+ "version": "0.6.3-develop.3593.1.8eda8943fa",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -242,16 +242,16 @@
242
242
  "zod": "^4.4.3"
243
243
  },
244
244
  "peerDependencies": {
245
- "@open-mercato/ai-assistant": "0.6.3-develop.3586.1.d5a44c810f",
246
- "@open-mercato/shared": "0.6.3-develop.3586.1.d5a44c810f",
247
- "@open-mercato/ui": "0.6.3-develop.3586.1.d5a44c810f",
245
+ "@open-mercato/ai-assistant": "0.6.3-develop.3593.1.8eda8943fa",
246
+ "@open-mercato/shared": "0.6.3-develop.3593.1.8eda8943fa",
247
+ "@open-mercato/ui": "0.6.3-develop.3593.1.8eda8943fa",
248
248
  "react": "^19.0.0",
249
249
  "react-dom": "^19.0.0"
250
250
  },
251
251
  "devDependencies": {
252
- "@open-mercato/ai-assistant": "0.6.3-develop.3586.1.d5a44c810f",
253
- "@open-mercato/shared": "0.6.3-develop.3586.1.d5a44c810f",
254
- "@open-mercato/ui": "0.6.3-develop.3586.1.d5a44c810f",
252
+ "@open-mercato/ai-assistant": "0.6.3-develop.3593.1.8eda8943fa",
253
+ "@open-mercato/shared": "0.6.3-develop.3593.1.8eda8943fa",
254
+ "@open-mercato/ui": "0.6.3-develop.3593.1.8eda8943fa",
255
255
  "@testing-library/dom": "^10.4.1",
256
256
  "@testing-library/jest-dom": "^6.9.1",
257
257
  "@testing-library/react": "^16.3.1",
@@ -1,54 +1,46 @@
1
1
  import type { EntityManager } from '@mikro-orm/postgresql'
2
- import { sql } from '@mikro-orm/postgresql'
3
2
 
4
- const PERSON_COMPANY_LINKS_TABLE = 'customer_person_company_links'
5
- const PERSON_COMPANY_LINKS_DELETED_AT_COLUMN = 'deleted_at'
3
+ // The previous implementation probed `information_schema.columns` on every
4
+ // first call via `em.getKysely()` to decide whether to add a `deletedAt: null`
5
+ // filter. When that probe ran inside an already-active MikroORM transaction it
6
+ // shared the transaction's connection — and any failure (including transient
7
+ // connection-pool state, an aborted TX from a sibling query, or pg returning
8
+ // 25P02) propagated back into the host transaction, poisoning every following
9
+ // query with `current transaction is aborted, commands ignored until end of
10
+ // transaction block`. That is what produced the standalone-CI failure burst
11
+ // (loadPersonCompanyLinks → 25P02 → customers.people.create → 500) and the
12
+ // sync_excel worker `failedCount: 1` regression.
13
+ //
14
+ // The `deleted_at` column on `customer_person_company_links` has been part of
15
+ // the committed module snapshot since `Migration20260415095203` (April 2026)
16
+ // and is referenced by `Migration20260417140000` (partial unique index uses
17
+ // `where deleted_at is null`). Any environment running these migrations
18
+ // already has the column. So the probe is no longer load-bearing — it only
19
+ // adds risk. We now unconditionally include `deletedAt: null` in the filter.
20
+ // If a downstream DB is genuinely un-migrated, the underlying `em.find` will
21
+ // surface the authentic `column "deleted_at" of relation
22
+ // "customer_person_company_links" does not exist` (pg 42703) pointing the
23
+ // operator at the real fix (`yarn db:migrate`).
24
+ //
25
+ // `customerPersonCompanyLinksSupportDeletedAt` and
26
+ // `warnMissingCustomerPersonCompanyLinksDeletedAt` are kept as exported
27
+ // no-op-equivalents so external callers (and the published @open-mercato/core
28
+ // API surface) don't break.
6
29
 
7
- let supportsDeletedAtColumnPromise: Promise<boolean> | null = null
8
- let warnedAboutMissingDeletedAtColumn = false
9
-
10
- export async function customerPersonCompanyLinksSupportDeletedAt(em: EntityManager): Promise<boolean> {
11
- if (typeof (em as { getKysely?: unknown }).getKysely !== 'function') {
12
- return true
13
- }
14
- if (!supportsDeletedAtColumnPromise) {
15
- const db = em.getKysely<any>() as any
16
- const probe: Promise<boolean> = db
17
- .selectFrom('information_schema.columns')
18
- .select(['column_name'])
19
- .where(sql<boolean>`table_schema = current_schema()`)
20
- .where('table_name', '=', PERSON_COMPANY_LINKS_TABLE)
21
- .where('column_name', '=', PERSON_COMPANY_LINKS_DELETED_AT_COLUMN)
22
- .executeTakeFirst()
23
- .then((row: unknown) => !!row)
24
- .catch(() => false)
25
- supportsDeletedAtColumnPromise = probe
26
- return probe
27
- }
28
- return supportsDeletedAtColumnPromise
30
+ export async function customerPersonCompanyLinksSupportDeletedAt(_em: EntityManager): Promise<boolean> {
31
+ return true
29
32
  }
30
33
 
31
- export function warnMissingCustomerPersonCompanyLinksDeletedAt(source: string): void {
32
- if (warnedAboutMissingDeletedAtColumn) {
33
- return
34
- }
35
- warnedAboutMissingDeletedAtColumn = true
36
- console.warn(
37
- `[${source}] missing ${PERSON_COMPANY_LINKS_TABLE}.${PERSON_COMPANY_LINKS_DELETED_AT_COLUMN}; ` +
38
- 'continuing without link soft-delete filtering. Run yarn db:migrate.',
39
- )
34
+ export function warnMissingCustomerPersonCompanyLinksDeletedAt(_source: string): void {
35
+ // No-op: column is guaranteed present by Migration20260415095203 and the
36
+ // module snapshot. Kept for backward-compatible exports.
40
37
  }
41
38
 
42
39
  export async function withActiveCustomerPersonCompanyLinkFilter<T extends Record<string, unknown>>(
43
- em: EntityManager,
40
+ _em: EntityManager,
44
41
  where: T,
45
- source: string,
42
+ _source: string,
46
43
  ): Promise<T & { deletedAt?: null }> {
47
- const supportsDeletedAt = await customerPersonCompanyLinksSupportDeletedAt(em)
48
- if (!supportsDeletedAt) {
49
- warnMissingCustomerPersonCompanyLinksDeletedAt(source)
50
- return { ...where }
51
- }
52
44
  return { ...where, deletedAt: null }
53
45
  }
54
46
 
@@ -0,0 +1,39 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+
3
+ /**
4
+ * Idempotent backstop for `customer_person_company_links.deleted_at`.
5
+ *
6
+ * The column was originally added by `Migration20260415095203` and is
7
+ * referenced by `Migration20260417140000`'s partial unique index
8
+ * (`where "deleted_at" is null`). It is part of the committed
9
+ * `migrations/.snapshot-open-mercato.json`.
10
+ *
11
+ * However, the runtime defensive probe that lived in
12
+ * `packages/core/src/modules/customers/lib/personCompanyLinkTable.ts`
13
+ * historically existed because an aborted-transaction state on a
14
+ * shared connection could (very rarely) make `loadPersonCompanyLinks`
15
+ * fail in a way that *looked* like the column was missing — and the
16
+ * cached fallback then silently dropped the `deletedAt: null` filter.
17
+ * That probe is removed in the same change as this migration (no
18
+ * Kysely query is ever issued from inside an active MikroORM TX);
19
+ * this migration is the matching belt-and-suspenders guarantee that
20
+ * the column is physically present so the unconditional `deletedAt:
21
+ * null` filter cannot 42703.
22
+ *
23
+ * Postgres-native `add column if not exists` is used so this re-applies
24
+ * cleanly on already-migrated databases without raising.
25
+ */
26
+ export class Migration20260521175027 extends Migration {
27
+
28
+ override async up(): Promise<void> {
29
+ this.addSql(`alter table "customer_person_company_links" add column if not exists "deleted_at" timestamptz null;`);
30
+ }
31
+
32
+ override async down(): Promise<void> {
33
+ // No-op on the way down: dropping the column would break
34
+ // `Migration20260417140000`'s partial unique index, which is the
35
+ // authoritative owner of the column going forward. The original
36
+ // `Migration20260415095203` down still drops it for full rollback.
37
+ }
38
+
39
+ }