@open-mercato/search 0.5.1-develop.2699.f8b50c8046 → 0.5.1-develop.2708.d6c4f6e5d1

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.
@@ -85,7 +85,7 @@ async function updateReindexProgress(db, tenantId, type, processedDelta, organiz
85
85
  processed_count: sql`coalesce(processed_count, 0) + ${delta}`,
86
86
  heartbeat_at: sql`now()`
87
87
  }).where("entity_type", "=", entityType).where(sql`tenant_id is not distinct from ${tenantId}`).where(sql`organization_id is not distinct from ${organizationId ?? null}`).where("finished_at", "is", null).executeTakeFirst();
88
- const updated = Number(result?.numUpdatedRows ?? 0n);
88
+ const updated = Number(result?.numUpdatedRows ?? 0);
89
89
  if (updated === 0) {
90
90
  await prepareJob(db, scope, "reindexing");
91
91
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/search/lib/reindex-lock.ts"],
4
- "sourcesContent": ["\nimport { type Kysely, sql } from 'kysely'\nimport {\n prepareJob,\n finalizeJob,\n type JobScope,\n} from '@open-mercato/core/modules/query_index/lib/jobs'\n\nexport const REINDEX_LOCK_KEY = 'reindex_lock'\n\nexport type ReindexLockType = 'fulltext' | 'vector'\n\n// Entity type mapping for search reindex jobs\nconst LOCK_ENTITY_TYPES: Record<ReindexLockType, string> = {\n fulltext: 'search:reindex:fulltext',\n vector: 'search:reindex:vector',\n}\n\n// Heartbeat staleness threshold (30 seconds)\nconst HEARTBEAT_STALE_MS = 30 * 1000\n\nexport type ReindexLockStatus = {\n type: ReindexLockType\n action: string\n startedAt: string\n tenantId: string\n organizationId?: string | null\n processedCount?: number | null\n totalCount?: number | null\n}\n\nfunction buildScope(\n type: ReindexLockType,\n tenantId: string,\n organizationId?: string | null,\n): JobScope {\n return {\n entityType: LOCK_ENTITY_TYPES[type],\n tenantId,\n organizationId: organizationId ?? null,\n partitionIndex: null,\n partitionCount: null,\n }\n}\n\n/**\n * Check if a reindex operation is currently in progress for a specific type.\n * Returns the lock status if active, null if no lock or lock is stale.\n *\n * Automatically cleans up stale locks (heartbeat older than 60 seconds).\n */\nexport async function getReindexLockStatus(\n db: Kysely<any>,\n tenantId: string,\n options?: { type?: ReindexLockType },\n): Promise<ReindexLockStatus | null> {\n const typesToCheck: ReindexLockType[] = options?.type\n ? [options.type]\n : ['fulltext', 'vector']\n\n for (const lockType of typesToCheck) {\n const entityType = LOCK_ENTITY_TYPES[lockType]\n\n try {\n const job = await db\n .selectFrom('entity_index_jobs' as any)\n .selectAll()\n .where('entity_type' as any, '=', entityType)\n .where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n .where('finished_at' as any, 'is', null)\n .executeTakeFirst() as {\n id: string\n status?: string | null\n started_at?: Date | string | null\n heartbeat_at?: Date | string | null\n organization_id?: string | null\n processed_count?: number | null\n total_count?: number | null\n } | undefined\n\n if (!job) continue\n\n // Check heartbeat staleness\n const heartbeatAt = job.heartbeat_at\n ? new Date(job.heartbeat_at as string | Date).getTime()\n : 0\n const elapsed = Date.now() - heartbeatAt\n\n if (elapsed > HEARTBEAT_STALE_MS) {\n // Auto-cleanup stale lock\n await db\n .updateTable('entity_index_jobs' as any)\n .set({ finished_at: sql`now()` } as any)\n .where('id' as any, '=', job.id)\n .execute()\n continue\n }\n\n // started_at comes as string from Kysely, convert if needed\n const startedAtStr = job.started_at\n ? (typeof job.started_at === 'string' ? job.started_at : new Date(job.started_at).toISOString())\n : new Date().toISOString()\n\n const result = {\n type: lockType,\n action: job.status || 'reindexing',\n startedAt: startedAtStr,\n tenantId,\n organizationId: job.organization_id ?? null,\n processedCount: job.processed_count ?? null,\n totalCount: job.total_count ?? null,\n }\n return result\n } catch {\n continue\n }\n }\n\n return null\n}\n\n/**\n * Acquire a reindex lock for a specific type. Returns whether lock was acquired.\n * Fulltext and vector locks are independent - they don't block each other.\n */\nexport async function acquireReindexLock(\n db: Kysely<any>,\n options: {\n type: ReindexLockType\n action: string\n tenantId: string\n organizationId?: string | null\n totalCount?: number | null\n },\n): Promise<{ acquired: boolean; jobId?: string }> {\n // Check existing active lock\n const existing = await getReindexLockStatus(db, options.tenantId, {\n type: options.type,\n })\n if (existing) {\n return { acquired: false }\n }\n\n try {\n const scope = buildScope(\n options.type,\n options.tenantId,\n options.organizationId,\n )\n const jobId = await prepareJob(db, scope, 'reindexing', {\n totalCount: options.totalCount,\n })\n\n return { acquired: true, jobId: jobId ?? undefined }\n } catch {\n return { acquired: false }\n }\n}\n\n/**\n * Release the reindex lock for a specific type.\n */\nexport async function clearReindexLock(\n db: Kysely<any>,\n tenantId: string,\n type: ReindexLockType,\n organizationId?: string | null,\n): Promise<void> {\n try {\n const scope = buildScope(type, tenantId, organizationId)\n await finalizeJob(db, scope)\n } catch {\n // Ignore errors when clearing lock\n }\n}\n\n/**\n * Update the reindex progress and refresh the heartbeat.\n * Call this periodically during batch processing to prevent stale lock detection.\n *\n * If no active lock exists (e.g., it expired after queue restart), this will\n * recreate the lock so the reindex button stays disabled while processing.\n */\nexport async function updateReindexProgress(\n db: Kysely<any>,\n tenantId: string,\n type: ReindexLockType,\n processedDelta: number,\n organizationId?: string | null,\n): Promise<void> {\n try {\n const scope = buildScope(type, tenantId, organizationId)\n const entityType = LOCK_ENTITY_TYPES[type]\n const delta = Math.max(0, processedDelta)\n\n // Try to update existing active job first\n const result = await db\n .updateTable('entity_index_jobs' as any)\n .set({\n processed_count: sql`coalesce(processed_count, 0) + ${delta}`,\n heartbeat_at: sql`now()`,\n } as any)\n .where('entity_type' as any, '=', entityType)\n .where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n .where(sql<boolean>`organization_id is not distinct from ${organizationId ?? null}`)\n .where('finished_at' as any, 'is', null)\n .executeTakeFirst()\n\n // Kysely returns numUpdatedRows as bigint; coerce\n const updated = Number(result?.numUpdatedRows ?? 0n)\n\n // If no active lock exists, recreate it\n if (updated === 0) {\n await prepareJob(db, scope, 'reindexing')\n }\n } catch {\n // Ignore errors when updating progress\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\nimport { type Kysely, sql } from 'kysely'\nimport {\n prepareJob,\n finalizeJob,\n type JobScope,\n} from '@open-mercato/core/modules/query_index/lib/jobs'\n\nexport const REINDEX_LOCK_KEY = 'reindex_lock'\n\nexport type ReindexLockType = 'fulltext' | 'vector'\n\n// Entity type mapping for search reindex jobs\nconst LOCK_ENTITY_TYPES: Record<ReindexLockType, string> = {\n fulltext: 'search:reindex:fulltext',\n vector: 'search:reindex:vector',\n}\n\n// Heartbeat staleness threshold (30 seconds)\nconst HEARTBEAT_STALE_MS = 30 * 1000\n\nexport type ReindexLockStatus = {\n type: ReindexLockType\n action: string\n startedAt: string\n tenantId: string\n organizationId?: string | null\n processedCount?: number | null\n totalCount?: number | null\n}\n\nfunction buildScope(\n type: ReindexLockType,\n tenantId: string,\n organizationId?: string | null,\n): JobScope {\n return {\n entityType: LOCK_ENTITY_TYPES[type],\n tenantId,\n organizationId: organizationId ?? null,\n partitionIndex: null,\n partitionCount: null,\n }\n}\n\n/**\n * Check if a reindex operation is currently in progress for a specific type.\n * Returns the lock status if active, null if no lock or lock is stale.\n *\n * Automatically cleans up stale locks (heartbeat older than 60 seconds).\n */\nexport async function getReindexLockStatus(\n db: Kysely<any>,\n tenantId: string,\n options?: { type?: ReindexLockType },\n): Promise<ReindexLockStatus | null> {\n const typesToCheck: ReindexLockType[] = options?.type\n ? [options.type]\n : ['fulltext', 'vector']\n\n for (const lockType of typesToCheck) {\n const entityType = LOCK_ENTITY_TYPES[lockType]\n\n try {\n const job = await db\n .selectFrom('entity_index_jobs' as any)\n .selectAll()\n .where('entity_type' as any, '=', entityType)\n .where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n .where('finished_at' as any, 'is', null)\n .executeTakeFirst() as {\n id: string\n status?: string | null\n started_at?: Date | string | null\n heartbeat_at?: Date | string | null\n organization_id?: string | null\n processed_count?: number | null\n total_count?: number | null\n } | undefined\n\n if (!job) continue\n\n // Check heartbeat staleness\n const heartbeatAt = job.heartbeat_at\n ? new Date(job.heartbeat_at as string | Date).getTime()\n : 0\n const elapsed = Date.now() - heartbeatAt\n\n if (elapsed > HEARTBEAT_STALE_MS) {\n // Auto-cleanup stale lock\n await db\n .updateTable('entity_index_jobs' as any)\n .set({ finished_at: sql`now()` } as any)\n .where('id' as any, '=', job.id)\n .execute()\n continue\n }\n\n // started_at comes as string from Kysely, convert if needed\n const startedAtStr = job.started_at\n ? (typeof job.started_at === 'string' ? job.started_at : new Date(job.started_at).toISOString())\n : new Date().toISOString()\n\n const result = {\n type: lockType,\n action: job.status || 'reindexing',\n startedAt: startedAtStr,\n tenantId,\n organizationId: job.organization_id ?? null,\n processedCount: job.processed_count ?? null,\n totalCount: job.total_count ?? null,\n }\n return result\n } catch {\n continue\n }\n }\n\n return null\n}\n\n/**\n * Acquire a reindex lock for a specific type. Returns whether lock was acquired.\n * Fulltext and vector locks are independent - they don't block each other.\n */\nexport async function acquireReindexLock(\n db: Kysely<any>,\n options: {\n type: ReindexLockType\n action: string\n tenantId: string\n organizationId?: string | null\n totalCount?: number | null\n },\n): Promise<{ acquired: boolean; jobId?: string }> {\n // Check existing active lock\n const existing = await getReindexLockStatus(db, options.tenantId, {\n type: options.type,\n })\n if (existing) {\n return { acquired: false }\n }\n\n try {\n const scope = buildScope(\n options.type,\n options.tenantId,\n options.organizationId,\n )\n const jobId = await prepareJob(db, scope, 'reindexing', {\n totalCount: options.totalCount,\n })\n\n return { acquired: true, jobId: jobId ?? undefined }\n } catch {\n return { acquired: false }\n }\n}\n\n/**\n * Release the reindex lock for a specific type.\n */\nexport async function clearReindexLock(\n db: Kysely<any>,\n tenantId: string,\n type: ReindexLockType,\n organizationId?: string | null,\n): Promise<void> {\n try {\n const scope = buildScope(type, tenantId, organizationId)\n await finalizeJob(db, scope)\n } catch {\n // Ignore errors when clearing lock\n }\n}\n\n/**\n * Update the reindex progress and refresh the heartbeat.\n * Call this periodically during batch processing to prevent stale lock detection.\n *\n * If no active lock exists (e.g., it expired after queue restart), this will\n * recreate the lock so the reindex button stays disabled while processing.\n */\nexport async function updateReindexProgress(\n db: Kysely<any>,\n tenantId: string,\n type: ReindexLockType,\n processedDelta: number,\n organizationId?: string | null,\n): Promise<void> {\n try {\n const scope = buildScope(type, tenantId, organizationId)\n const entityType = LOCK_ENTITY_TYPES[type]\n const delta = Math.max(0, processedDelta)\n\n // Try to update existing active job first\n const result = await db\n .updateTable('entity_index_jobs' as any)\n .set({\n processed_count: sql`coalesce(processed_count, 0) + ${delta}`,\n heartbeat_at: sql`now()`,\n } as any)\n .where('entity_type' as any, '=', entityType)\n .where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n .where(sql<boolean>`organization_id is not distinct from ${organizationId ?? null}`)\n .where('finished_at' as any, 'is', null)\n .executeTakeFirst()\n\n // Kysely returns numUpdatedRows as bigint; coerce\n const updated = Number(result?.numUpdatedRows ?? 0)\n\n // If no active lock exists, recreate it\n if (updated === 0) {\n await prepareJob(db, scope, 'reindexing')\n }\n } catch {\n // Ignore errors when updating progress\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/search",
3
- "version": "0.5.1-develop.2699.f8b50c8046",
3
+ "version": "0.5.1-develop.2708.d6c4f6e5d1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -126,9 +126,9 @@
126
126
  "zod": "^4.3.6"
127
127
  },
128
128
  "peerDependencies": {
129
- "@open-mercato/core": "0.5.1-develop.2699.f8b50c8046",
130
- "@open-mercato/queue": "0.5.1-develop.2699.f8b50c8046",
131
- "@open-mercato/shared": "0.5.1-develop.2699.f8b50c8046"
129
+ "@open-mercato/core": "0.5.1-develop.2708.d6c4f6e5d1",
130
+ "@open-mercato/queue": "0.5.1-develop.2708.d6c4f6e5d1",
131
+ "@open-mercato/shared": "0.5.1-develop.2708.d6c4f6e5d1"
132
132
  },
133
133
  "devDependencies": {
134
134
  "@types/jest": "^30.0.0",
@@ -207,7 +207,7 @@ export async function updateReindexProgress(
207
207
  .executeTakeFirst()
208
208
 
209
209
  // Kysely returns numUpdatedRows as bigint; coerce
210
- const updated = Number(result?.numUpdatedRows ?? 0n)
210
+ const updated = Number(result?.numUpdatedRows ?? 0)
211
211
 
212
212
  // If no active lock exists, recreate it
213
213
  if (updated === 0) {