{"version":3,"file":"media-usage-work-BcgwlEe5.mjs","names":[],"sources":["../src/database/repositories/media-usage-work.ts"],"sourcesContent":["import { sql, type Kysely, type RawBuilder, type Selectable } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { isPostgres } from \"../dialect-helpers.js\";\nimport type { Database, MediaUsageWorkTable } from \"../types.js\";\nimport { decodeCursor, encodeCursor, type FindManyResult } from \"./types.js\";\n\nexport type MediaUsageWorkState = \"pending\" | \"retry\" | \"leased\" | \"failed\";\nexport type MediaUsageWorkVersion = number | string;\nconst MAX_PORTABLE_DURATION_SECONDS = 365 * 24 * 60 * 60;\nconst MAX_WORK_SELECTION_LIMIT = 100;\nconst NON_NEGATIVE_DECIMAL_PATTERN = /^(?:0|[1-9][0-9]*)$/;\nconst POSITIVE_DECIMAL_PATTERN = /^[1-9][0-9]*$/;\nconst STABLE_ERROR_CODE_PATTERN = /^[A-Z][A-Z0-9_]{0,63}$/;\n\nexport const MEDIA_USAGE_WORK_OPERATOR_DEFAULT_LIMIT = 50;\nexport const MEDIA_USAGE_WORK_OPERATOR_MAX_LIMIT = 100;\nexport const MEDIA_USAGE_RECONCILIATION_PAGE_LIMIT = 50;\nconst MEDIA_USAGE_WORK_STATES = [\"pending\", \"retry\", \"leased\", \"failed\"] as const;\n\nexport interface MediaUsageWorkIdentity {\n\tcollectionId: string;\n\tcontentId: string;\n\tworkVersion: MediaUsageWorkVersion;\n}\n\nexport interface MediaUsageWorkLease extends MediaUsageWorkIdentity {\n\tleaseToken: string;\n}\n\nexport interface MediaUsageWorkRecord extends MediaUsageWorkIdentity {\n\tcollectionSlug: string;\n\tchangeEpoch: number | string;\n\tstate: MediaUsageWorkState;\n\tattemptCount: number;\n\tnextAttemptAt: string;\n\tleaseToken: string | null;\n\tleaseExpiresAt: string | null;\n\tlastAttemptedAt: string | null;\n\tlastErrorCode: string | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface MediaUsageOperatorWorkItem {\n\tcollectionId: string;\n\tcollectionSlug: string;\n\tcontentId: string;\n\tstate: MediaUsageWorkState;\n\tattemptCount: number;\n\tnextAttemptAt: string;\n\tleaseExpiresAt: string | null;\n\tlastAttemptedAt: string | null;\n\tlastErrorCode: string | null;\n\tupdatedAt: string;\n}\n\nexport type MediaUsageOperatorRetryResult =\n\t| { outcome: \"pending\"; changed: boolean; work: MediaUsageOperatorWorkItem }\n\t| { outcome: \"lease_active\"; leaseExpiresAt: string }\n\t| { outcome: \"collection_not_found\" }\n\t| { outcome: \"conflict\" };\n\nexport class MediaUsageWorkRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\tasync enqueueReconciliationPage(input: {\n\t\tcollectionId: string;\n\t\tcollectionSlug: string;\n\t\trunToken: string;\n\t\tleaseToken: string;\n\t\tchangeEpoch: number | string;\n\t\tphase: \"scan\" | \"sources\";\n\t\tcontentIds: readonly string[];\n\t}): Promise<void> {\n\t\tif (!input.collectionId || !input.collectionSlug || !input.runToken || !input.leaseToken) {\n\t\t\tthrow new Error(\"Reconciliation enqueue requires exact collection and lease identity\");\n\t\t}\n\t\tassertNonNegativeDecimal(input.changeEpoch, \"change epoch\");\n\t\tconst contentIds = [...new Set(input.contentIds)];\n\t\tif (contentIds.length < 1 || contentIds.length > MEDIA_USAGE_RECONCILIATION_PAGE_LIMIT) {\n\t\t\tthrow new Error(\"Reconciliation enqueue requires from 1 to 50 content IDs\");\n\t\t}\n\t\tif (contentIds.some((contentId) => !contentId)) {\n\t\t\tthrow new Error(\"Reconciliation enqueue content IDs must not be empty\");\n\t\t}\n\t\tconst now = this.timestampOffset(0);\n\t\tconst pageValues = sql.join(\n\t\t\tcontentIds.map((contentId) => sql`(${contentId})`),\n\t\t\tsql`, `,\n\t\t);\n\t\tawait sql`\n\t\t\tWITH page(content_id) AS (VALUES ${pageValues})\n\t\t\tINSERT INTO _emdash_media_usage_work (\n\t\t\t\tcollection_id, collection_slug, content_id, change_epoch, work_version,\n\t\t\t\tstate, attempt_count, next_attempt_at, lease_token, lease_expires_at,\n\t\t\t\tlast_attempted_at, last_error_code, created_at, updated_at\n\t\t\t)\n\t\t\tSELECT\n\t\t\t\t${input.collectionId}, ${input.collectionSlug}, page.content_id, ${input.changeEpoch}, 1,\n\t\t\t\t'pending', 0, ${now}, NULL, NULL, NULL, NULL, ${now}, ${now}\n\t\t\tFROM page\n\t\t\tWHERE EXISTS (\n\t\t\t\tSELECT 1\n\t\t\t\tFROM _emdash_media_usage_reconciliations AS reconciliation\n\t\t\t\tINNER JOIN _emdash_media_usage_index_status AS status\n\t\t\t\t\tON status.collection_id = reconciliation.collection_id\n\t\t\t\t\tAND status.scope_key = reconciliation.collection_slug\n\t\t\t\tINNER JOIN _emdash_collections AS collection\n\t\t\t\t\tON collection.id = reconciliation.collection_id\n\t\t\t\t\tAND collection.slug = reconciliation.collection_slug\n\t\t\t\tWHERE reconciliation.collection_id = ${input.collectionId}\n\t\t\t\t\tAND reconciliation.collection_slug = ${input.collectionSlug}\n\t\t\t\t\tAND reconciliation.run_token = ${input.runToken}\n\t\t\t\t\tAND reconciliation.target_epoch = ${input.changeEpoch}\n\t\t\t\t\tAND reconciliation.state = 'leased'\n\t\t\t\t\tAND reconciliation.phase = ${input.phase}\n\t\t\t\t\tAND reconciliation.lease_token = ${input.leaseToken}\n\t\t\t\t\tAND ${this.qualifiedLeaseIsLive(\"reconciliation.lease_expires_at\")}\n\t\t\t\t\tAND status.adapter_id = 'content-media'\n\t\t\t\t\tAND status.scope_type = 'collection'\n\t\t\t\t\tAND status.capture_state = 'active'\n\t\t\t\t\tAND status.reconciliation_required = 1\n\t\t\t\t\tAND status.status = 'running'\n\t\t\t\t\tAND status.cursor = ${input.runToken}\n\t\t\t\t\tAND status.change_epoch = ${input.changeEpoch}\n\t\t\t\t\tAND EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM _emdash_media_usage_activation AS activation\n\t\t\t\t\t\tWHERE activation.task_key = 'incremental_capture'\n\t\t\t\t\t\t\tAND activation.state = 'active'\n\t\t\t\t\t)\n\t\t\t\t\tAND NOT EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM _emdash_media_usage_collection_deletions AS deletion\n\t\t\t\t\t\tWHERE deletion.collection_id = reconciliation.collection_id\n\t\t\t\t\t)\n\t\t\t)\n\t\t\tON CONFLICT (collection_id, content_id) DO UPDATE SET\n\t\t\t\tcollection_slug = excluded.collection_slug,\n\t\t\t\tchange_epoch = excluded.change_epoch,\n\t\t\t\twork_version = _emdash_media_usage_work.work_version + 1,\n\t\t\t\tstate = 'pending',\n\t\t\t\tattempt_count = 0,\n\t\t\t\tnext_attempt_at = excluded.next_attempt_at,\n\t\t\t\tlease_token = NULL,\n\t\t\t\tlease_expires_at = NULL,\n\t\t\t\tlast_attempted_at = NULL,\n\t\t\t\tlast_error_code = NULL,\n\t\t\t\tupdated_at = excluded.updated_at\n\t\t\tWHERE _emdash_media_usage_work.change_epoch < excluded.change_epoch\n\t\t`.execute(this.db);\n\t}\n\n\tasync findOperatorPage(options: {\n\t\tcollectionSlug: string;\n\t\tstate?: MediaUsageWorkState;\n\t\tlimit?: number;\n\t\tcursor?: string;\n\t}): Promise<FindManyResult<MediaUsageOperatorWorkItem> | null> {\n\t\tif (!options.collectionSlug) {\n\t\t\tthrow new Error(\"Media usage work listing requires a collection slug\");\n\t\t}\n\t\tif (options.state !== undefined && !isMediaUsageWorkState(options.state)) {\n\t\t\tthrow new Error(\"Media usage work listing requires a valid state\");\n\t\t}\n\t\tconst limit = operatorLimit(options.limit);\n\t\tconst cursor = options.cursor ? decodeCursor(options.cursor) : null;\n\t\tconst collection = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select([\"id\", \"slug\"])\n\t\t\t.where(\"slug\", \"=\", options.collectionSlug)\n\t\t\t.executeTakeFirst();\n\t\tif (!collection) return null;\n\n\t\tconst states = options.state ? [options.state] : MEDIA_USAGE_WORK_STATES;\n\t\tconst candidates: MediaUsageOperatorWorkItem[] = [];\n\t\tfor (const state of states) {\n\t\t\tconst rows = await this.findOperatorRows({\n\t\t\t\tcollectionId: collection.id,\n\t\t\t\tcollectionSlug: collection.slug,\n\t\t\t\tstate,\n\t\t\t\tlimit: limit + 1,\n\t\t\t\tcursor,\n\t\t\t});\n\t\t\tcandidates.push(...rows.map(rowToOperatorWork));\n\t\t}\n\n\t\tconst ordered = candidates.toSorted(compareOperatorWork);\n\t\tconst items = ordered.slice(0, limit);\n\t\tconst result: FindManyResult<MediaUsageOperatorWorkItem> = { items };\n\t\tif (ordered.length > limit && items.length > 0) {\n\t\t\tconst last = items.at(-1)!;\n\t\t\tresult.nextCursor = encodeCursor(last.updatedAt, last.contentId);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate async findOperatorRows(input: {\n\t\tcollectionId: string;\n\t\tcollectionSlug: string;\n\t\tstate: MediaUsageWorkState;\n\t\tlimit: number;\n\t\tcursor: { orderValue: string; id: string } | null;\n\t}): Promise<Selectable<MediaUsageWorkTable>[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_media_usage_work as work\")\n\t\t\t.innerJoin(\"_emdash_collections as current_collection\", (join) =>\n\t\t\t\tjoin\n\t\t\t\t\t.onRef(\"current_collection.id\", \"=\", \"work.collection_id\")\n\t\t\t\t\t.onRef(\"current_collection.slug\", \"=\", \"work.collection_slug\"),\n\t\t\t)\n\t\t\t.selectAll(\"work\")\n\t\t\t.where(\"work.collection_id\", \"=\", input.collectionId)\n\t\t\t.where(\"work.collection_slug\", \"=\", input.collectionSlug)\n\t\t\t.where(\"work.state\", \"=\", input.state);\n\t\tif (input.cursor) {\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"work.updated_at\", \"<\", input.cursor!.orderValue),\n\t\t\t\t\teb.and([\n\t\t\t\t\t\teb(\"work.updated_at\", \"=\", input.cursor!.orderValue),\n\t\t\t\t\t\teb(\"work.content_id\", \"<\", input.cursor!.id),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\t\treturn query\n\t\t\t.orderBy(\"work.updated_at\", \"desc\")\n\t\t\t.orderBy(\"work.content_id\", \"desc\")\n\t\t\t.limit(input.limit)\n\t\t\t.execute();\n\t}\n\n\tasync retryOperatorWork(input: {\n\t\tcollectionId: string;\n\t\tcontentId: string;\n\t}): Promise<MediaUsageOperatorRetryResult> {\n\t\tif (!input.collectionId || !input.contentId) {\n\t\t\tthrow new Error(\"Media usage operator retry requires collection and content IDs\");\n\t\t}\n\t\tconst collection = await this.findActiveOperatorCollection(input.collectionId);\n\t\tif (!collection) return { outcome: \"collection_not_found\" };\n\n\t\tconst observed = await this.findWorkByIdentity(input.collectionId, input.contentId);\n\t\tif (observed?.state === \"pending\" && observed.collection_slug === collection.slug) {\n\t\t\treturn { outcome: \"pending\", changed: false, work: rowToOperatorWork(observed) };\n\t\t}\n\n\t\tconst invalidated = await this.invalidateCoverageForOperatorRetry({\n\t\t\t...input,\n\t\t\tcollectionSlug: collection.slug,\n\t\t\tobserved,\n\t\t});\n\t\tif (!invalidated) return this.operatorRetryLost(input);\n\n\t\tconst reopened = observed\n\t\t\t? await this.reopenObservedWork(observed, collection.slug, invalidated.change_epoch)\n\t\t\t: await this.createOperatorWork({\n\t\t\t\t\t...input,\n\t\t\t\t\tcollectionSlug: collection.slug,\n\t\t\t\t\tchangeEpoch: invalidated.change_epoch,\n\t\t\t\t});\n\t\tif (reopened) {\n\t\t\treturn { outcome: \"pending\", changed: true, work: rowToOperatorWork(reopened) };\n\t\t}\n\t\treturn this.operatorRetryLost(input);\n\t}\n\n\tprivate async findActiveOperatorCollection(\n\t\tcollectionId: string,\n\t): Promise<{ id: string; slug: string } | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_collections as collection\")\n\t\t\t.innerJoin(\"_emdash_media_usage_index_status as status\", (join) =>\n\t\t\t\tjoin\n\t\t\t\t\t.onRef(\"status.collection_id\", \"=\", \"collection.id\")\n\t\t\t\t\t.onRef(\"status.scope_key\", \"=\", \"collection.slug\"),\n\t\t\t)\n\t\t\t.select([\"collection.id\", \"collection.slug\"])\n\t\t\t.where(\"collection.id\", \"=\", collectionId)\n\t\t\t.where(\"status.adapter_id\", \"=\", \"content-media\")\n\t\t\t.where(\"status.scope_type\", \"=\", \"collection\")\n\t\t\t.where(\"status.capture_state\", \"=\", \"active\")\n\t\t\t.executeTakeFirst();\n\t\treturn row ?? null;\n\t}\n\n\tprivate async findWorkByIdentity(\n\t\tcollectionId: string,\n\t\tcontentId: string,\n\t): Promise<Selectable<MediaUsageWorkTable> | null> {\n\t\treturn (\n\t\t\t(await this.db\n\t\t\t\t.selectFrom(\"_emdash_media_usage_work\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"collection_id\", \"=\", collectionId)\n\t\t\t\t.where(\"content_id\", \"=\", contentId)\n\t\t\t\t.executeTakeFirst()) ?? null\n\t\t);\n\t}\n\n\tprivate async invalidateCoverageForOperatorRetry(input: {\n\t\tcollectionId: string;\n\t\tcollectionSlug: string;\n\t\tcontentId: string;\n\t\tobserved: Selectable<MediaUsageWorkTable> | null;\n\t}): Promise<{ change_epoch: number | string } | null> {\n\t\tlet query = this.db\n\t\t\t.updateTable(\"_emdash_media_usage_index_status as status\")\n\t\t\t.set({\n\t\t\t\tchange_epoch: sql<number>`change_epoch + 1`,\n\t\t\t\tstatus: sql<string>`CASE WHEN status = 'complete' THEN 'stale' ELSE status END`,\n\t\t\t\tcompleted_at: sql<\n\t\t\t\t\tstring | null\n\t\t\t\t>`CASE WHEN status = 'complete' THEN NULL ELSE completed_at END`,\n\t\t\t\tupdated_at: this.timestampOffset(0),\n\t\t\t})\n\t\t\t.where(\"status.adapter_id\", \"=\", \"content-media\")\n\t\t\t.where(\"status.scope_type\", \"=\", \"collection\")\n\t\t\t.where(\"status.scope_key\", \"=\", input.collectionSlug)\n\t\t\t.where(\"status.collection_id\", \"=\", input.collectionId)\n\t\t\t.where(\"status.capture_state\", \"=\", \"active\")\n\t\t\t.where((eb) =>\n\t\t\t\teb.exists(\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_collections as collection\")\n\t\t\t\t\t\t.select(\"collection.id\")\n\t\t\t\t\t\t.whereRef(\"collection.id\", \"=\", \"status.collection_id\")\n\t\t\t\t\t\t.whereRef(\"collection.slug\", \"=\", \"status.scope_key\"),\n\t\t\t\t),\n\t\t\t);\n\n\t\tconst observed = input.observed;\n\t\tif (observed) {\n\t\t\tquery = query.where((eb) => {\n\t\t\t\tlet work = eb\n\t\t\t\t\t.selectFrom(\"_emdash_media_usage_work as work\")\n\t\t\t\t\t.select(\"work.content_id\")\n\t\t\t\t\t.whereRef(\"work.collection_id\", \"=\", \"status.collection_id\")\n\t\t\t\t\t.where(\"work.content_id\", \"=\", input.contentId)\n\t\t\t\t\t.where(\"work.work_version\", \"=\", observed.work_version)\n\t\t\t\t\t.where(\"work.state\", \"=\", observed.state);\n\t\t\t\tif (observed.state === \"leased\") {\n\t\t\t\t\twork = work\n\t\t\t\t\t\t.where(\"work.lease_expires_at\", \"is not\", null)\n\t\t\t\t\t\t.where(this.timestampIsDue(\"work.lease_expires_at\"));\n\t\t\t\t}\n\t\t\t\treturn eb.exists(work);\n\t\t\t});\n\t\t} else {\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.not(\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"_emdash_media_usage_work as work\")\n\t\t\t\t\t\t\t.select(\"work.content_id\")\n\t\t\t\t\t\t\t.whereRef(\"work.collection_id\", \"=\", \"status.collection_id\")\n\t\t\t\t\t\t\t.where(\"work.content_id\", \"=\", input.contentId),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn (await query.returning(\"change_epoch\").executeTakeFirst()) ?? null;\n\t}\n\n\tprivate async reopenObservedWork(\n\t\tobserved: Selectable<MediaUsageWorkTable>,\n\t\tcollectionSlug: string,\n\t\tchangeEpoch: number | string,\n\t): Promise<Selectable<MediaUsageWorkTable> | null> {\n\t\tlet query = this.db\n\t\t\t.updateTable(\"_emdash_media_usage_work\")\n\t\t\t.set({\n\t\t\t\tcollection_slug: collectionSlug,\n\t\t\t\tchange_epoch: changeEpoch,\n\t\t\t\twork_version: sql<number>`work_version + 1`,\n\t\t\t\tstate: \"pending\",\n\t\t\t\tattempt_count: 0,\n\t\t\t\tnext_attempt_at: this.timestampOffset(0),\n\t\t\t\tlease_token: null,\n\t\t\t\tlease_expires_at: null,\n\t\t\t\tlast_attempted_at: null,\n\t\t\t\tlast_error_code: null,\n\t\t\t\tupdated_at: this.timestampOffset(0),\n\t\t\t})\n\t\t\t.where(\"collection_id\", \"=\", observed.collection_id)\n\t\t\t.where(\"content_id\", \"=\", observed.content_id)\n\t\t\t.where(\"work_version\", \"=\", observed.work_version)\n\t\t\t.where(\"state\", \"=\", observed.state)\n\t\t\t.where((eb) =>\n\t\t\t\teb.exists(\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_collections as collection\")\n\t\t\t\t\t\t.innerJoin(\"_emdash_media_usage_index_status as status\", (join) =>\n\t\t\t\t\t\t\tjoin\n\t\t\t\t\t\t\t\t.onRef(\"status.collection_id\", \"=\", \"collection.id\")\n\t\t\t\t\t\t\t\t.onRef(\"status.scope_key\", \"=\", \"collection.slug\"),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.select(\"collection.id\")\n\t\t\t\t\t\t.where(\"collection.id\", \"=\", observed.collection_id)\n\t\t\t\t\t\t.where(\"collection.slug\", \"=\", collectionSlug)\n\t\t\t\t\t\t.where(\"status.adapter_id\", \"=\", \"content-media\")\n\t\t\t\t\t\t.where(\"status.scope_type\", \"=\", \"collection\")\n\t\t\t\t\t\t.where(\"status.capture_state\", \"=\", \"active\")\n\t\t\t\t\t\t.where(\"status.change_epoch\", \"=\", changeEpoch),\n\t\t\t\t),\n\t\t\t);\n\t\tif (observed.state === \"leased\") {\n\t\t\tquery = query\n\t\t\t\t.where(\"lease_expires_at\", \"is not\", null)\n\t\t\t\t.where(this.timestampIsDue(\"lease_expires_at\"));\n\t\t}\n\t\treturn (await query.returningAll().executeTakeFirst()) ?? null;\n\t}\n\n\tprivate async createOperatorWork(input: {\n\t\tcollectionId: string;\n\t\tcollectionSlug: string;\n\t\tcontentId: string;\n\t\tchangeEpoch: number | string;\n\t}): Promise<Selectable<MediaUsageWorkTable> | null> {\n\t\tconst now = this.timestampOffset(0);\n\t\treturn (\n\t\t\t(await this.db\n\t\t\t\t.insertInto(\"_emdash_media_usage_work\")\n\t\t\t\t.columns([\n\t\t\t\t\t\"collection_id\",\n\t\t\t\t\t\"collection_slug\",\n\t\t\t\t\t\"content_id\",\n\t\t\t\t\t\"change_epoch\",\n\t\t\t\t\t\"work_version\",\n\t\t\t\t\t\"state\",\n\t\t\t\t\t\"attempt_count\",\n\t\t\t\t\t\"next_attempt_at\",\n\t\t\t\t\t\"lease_token\",\n\t\t\t\t\t\"lease_expires_at\",\n\t\t\t\t\t\"last_attempted_at\",\n\t\t\t\t\t\"last_error_code\",\n\t\t\t\t\t\"created_at\",\n\t\t\t\t\t\"updated_at\",\n\t\t\t\t])\n\t\t\t\t.expression((insert) =>\n\t\t\t\t\tinsert\n\t\t\t\t\t\t.selectFrom(\"_emdash_media_usage_index_status as status\")\n\t\t\t\t\t\t.innerJoin(\"_emdash_collections as collection\", (join) =>\n\t\t\t\t\t\t\tjoin\n\t\t\t\t\t\t\t\t.onRef(\"collection.id\", \"=\", \"status.collection_id\")\n\t\t\t\t\t\t\t\t.onRef(\"collection.slug\", \"=\", \"status.scope_key\"),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.select((select) => [\n\t\t\t\t\t\t\tselect.val(input.collectionId).as(\"collection_id\"),\n\t\t\t\t\t\t\t\"collection.slug as collection_slug\",\n\t\t\t\t\t\t\tselect.val(input.contentId).as(\"content_id\"),\n\t\t\t\t\t\t\t\"status.change_epoch as change_epoch\",\n\t\t\t\t\t\t\tselect.val(1).as(\"work_version\"),\n\t\t\t\t\t\t\tselect.val(\"pending\").as(\"state\"),\n\t\t\t\t\t\t\tselect.val(0).as(\"attempt_count\"),\n\t\t\t\t\t\t\tnow.as(\"next_attempt_at\"),\n\t\t\t\t\t\t\tsql<null>`NULL`.as(\"lease_token\"),\n\t\t\t\t\t\t\tsql<null>`NULL`.as(\"lease_expires_at\"),\n\t\t\t\t\t\t\tsql<null>`NULL`.as(\"last_attempted_at\"),\n\t\t\t\t\t\t\tsql<null>`NULL`.as(\"last_error_code\"),\n\t\t\t\t\t\t\tnow.as(\"created_at\"),\n\t\t\t\t\t\t\tnow.as(\"updated_at\"),\n\t\t\t\t\t\t])\n\t\t\t\t\t\t.where(\"status.adapter_id\", \"=\", \"content-media\")\n\t\t\t\t\t\t.where(\"status.scope_type\", \"=\", \"collection\")\n\t\t\t\t\t\t.where(\"status.scope_key\", \"=\", input.collectionSlug)\n\t\t\t\t\t\t.where(\"status.collection_id\", \"=\", input.collectionId)\n\t\t\t\t\t\t.where(\"status.capture_state\", \"=\", \"active\")\n\t\t\t\t\t\t.where(\"status.change_epoch\", \"=\", input.changeEpoch),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) => conflict.columns([\"collection_id\", \"content_id\"]).doNothing())\n\t\t\t\t.returningAll()\n\t\t\t\t.executeTakeFirst()) ?? null\n\t\t);\n\t}\n\n\tprivate async operatorRetryLost(input: {\n\t\tcollectionId: string;\n\t\tcontentId: string;\n\t}): Promise<MediaUsageOperatorRetryResult> {\n\t\tif (!(await this.findActiveOperatorCollection(input.collectionId))) {\n\t\t\treturn { outcome: \"collection_not_found\" };\n\t\t}\n\t\tconst current = await this.findWorkByIdentity(input.collectionId, input.contentId);\n\t\tif (current?.state === \"pending\") {\n\t\t\treturn { outcome: \"pending\", changed: false, work: rowToOperatorWork(current) };\n\t\t}\n\t\tconst liveLease = await this.findLiveLeaseExpiry(input.collectionId, input.contentId);\n\t\tif (liveLease) return { outcome: \"lease_active\", leaseExpiresAt: liveLease };\n\t\treturn { outcome: \"conflict\" };\n\t}\n\n\tprivate async findLiveLeaseExpiry(\n\t\tcollectionId: string,\n\t\tcontentId: string,\n\t): Promise<string | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_media_usage_work\")\n\t\t\t.select(\"lease_expires_at\")\n\t\t\t.where(\"collection_id\", \"=\", collectionId)\n\t\t\t.where(\"content_id\", \"=\", contentId)\n\t\t\t.where(\"state\", \"=\", \"leased\")\n\t\t\t.where(\"lease_expires_at\", \"is not\", null)\n\t\t\t.where(this.leaseIsLive())\n\t\t\t.executeTakeFirst();\n\t\treturn row?.lease_expires_at ?? null;\n\t}\n\n\tasync findDueWork(limit: number): Promise<MediaUsageWorkRecord[]> {\n\t\tif (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_WORK_SELECTION_LIMIT) {\n\t\t\tthrow new Error(\n\t\t\t\t`Media usage due-work limit must be a whole number from 1 to ${MAX_WORK_SELECTION_LIMIT}`,\n\t\t\t);\n\t\t}\n\n\t\tconst pendingRows = await this.findDueRows(\"pending\", \"next_attempt_at\", limit);\n\t\tconst retryRows = await this.findDueRows(\"retry\", \"next_attempt_at\", limit);\n\t\tconst leasedRows = await this.findDueRows(\"leased\", \"lease_expires_at\", limit);\n\n\t\treturn [...pendingRows, ...retryRows, ...leasedRows]\n\t\t\t.map(rowToWork)\n\t\t\t.toSorted(compareDueWork)\n\t\t\t.slice(0, limit);\n\t}\n\n\tprivate async findDueRows(\n\t\tstate: \"pending\" | \"retry\" | \"leased\",\n\t\ttimestampColumn: \"next_attempt_at\" | \"lease_expires_at\",\n\t\tlimit: number,\n\t): Promise<Selectable<MediaUsageWorkTable>[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_media_usage_work\")\n\t\t\t.selectAll()\n\t\t\t.where(\"state\", \"=\", state)\n\t\t\t.where(this.timestampIsDue(timestampColumn))\n\t\t\t.orderBy(timestampColumn, \"asc\");\n\t\tif (timestampColumn === \"next_attempt_at\") {\n\t\t\tquery = query.orderBy(\"updated_at\", \"asc\");\n\t\t}\n\t\treturn query\n\t\t\t.orderBy(\"collection_id\", \"asc\")\n\t\t\t.orderBy(\"content_id\", \"asc\")\n\t\t\t.limit(limit)\n\t\t\t.execute();\n\t}\n\n\tasync findWorkForContent(\n\t\tcollectionSlug: string,\n\t\tcontentId: string,\n\t): Promise<MediaUsageWorkRecord | null> {\n\t\tif (!collectionSlug || !contentId) {\n\t\t\tthrow new Error(\"Media usage work lookup requires collection and content identity\");\n\t\t}\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_media_usage_work\")\n\t\t\t.innerJoin(\"_emdash_collections as current_collection\", (join) =>\n\t\t\t\tjoin\n\t\t\t\t\t.onRef(\"current_collection.id\", \"=\", \"_emdash_media_usage_work.collection_id\")\n\t\t\t\t\t.onRef(\"current_collection.slug\", \"=\", \"_emdash_media_usage_work.collection_slug\"),\n\t\t\t)\n\t\t\t.selectAll(\"_emdash_media_usage_work\")\n\t\t\t.where(\"_emdash_media_usage_work.collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"_emdash_media_usage_work.content_id\", \"=\", contentId)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToWork(row) : null;\n\t}\n\n\tasync claimWork(\n\t\tinput: MediaUsageWorkIdentity & {\n\t\t\tleaseDurationSeconds: number;\n\t\t},\n\t): Promise<MediaUsageWorkRecord | null> {\n\t\tassertIdentity(input);\n\t\tconst leaseDurationSeconds = durationSeconds(\n\t\t\tinput.leaseDurationSeconds,\n\t\t\t\"lease duration\",\n\t\t\tfalse,\n\t\t);\n\t\tconst leaseToken = ulid();\n\t\tconst now = this.timestampOffset(0);\n\t\tconst row = await this.db\n\t\t\t.updateTable(\"_emdash_media_usage_work\")\n\t\t\t.set({\n\t\t\t\tstate: \"leased\",\n\t\t\t\tlease_token: leaseToken,\n\t\t\t\tlease_expires_at: this.timestampOffset(leaseDurationSeconds),\n\t\t\t\tlast_attempted_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.where(\"collection_id\", \"=\", input.collectionId)\n\t\t\t.where(\"content_id\", \"=\", input.contentId)\n\t\t\t.where(\"work_version\", \"=\", input.workVersion)\n\t\t\t.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb.and([eb(\"state\", \"in\", [\"pending\", \"retry\"]), this.timestampIsDue(\"next_attempt_at\")]),\n\t\t\t\t\teb.and([\n\t\t\t\t\t\teb(\"state\", \"=\", \"leased\"),\n\t\t\t\t\t\teb(\"lease_expires_at\", \"is not\", null),\n\t\t\t\t\t\tthis.timestampIsDue(\"lease_expires_at\"),\n\t\t\t\t\t]),\n\t\t\t\t]),\n\t\t\t)\n\t\t\t.returningAll()\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? rowToWork(row) : null;\n\t}\n\n\tasync completeWork(input: MediaUsageWorkLease): Promise<boolean> {\n\t\tassertLease(input);\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_emdash_media_usage_work\")\n\t\t\t.where(\"collection_id\", \"=\", input.collectionId)\n\t\t\t.where(\"content_id\", \"=\", input.contentId)\n\t\t\t.where(\"work_version\", \"=\", input.workVersion)\n\t\t\t.where(\"state\", \"=\", \"leased\")\n\t\t\t.where(\"lease_token\", \"=\", input.leaseToken)\n\t\t\t.where(this.leaseIsLive())\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numDeletedRows ?? 0) > 0;\n\t}\n\n\tasync deleteWorkThroughEpoch(\n\t\tcollectionId: string,\n\t\tmaxChangeEpoch: number | string,\n\t): Promise<number> {\n\t\tif (!collectionId) throw new Error(\"Media usage work cleanup requires a collection ID\");\n\t\tassertNonNegativeDecimal(maxChangeEpoch, \"change epoch\");\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_emdash_media_usage_work\")\n\t\t\t.where(\"collection_id\", \"=\", collectionId)\n\t\t\t.where(\"change_epoch\", \"<=\", maxChangeEpoch)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numDeletedRows ?? 0);\n\t}\n\n\tasync retryWork(\n\t\tinput: MediaUsageWorkLease & {\n\t\t\tretryDelaySeconds: number;\n\t\t\terrorCode: string;\n\t\t},\n\t): Promise<boolean> {\n\t\tconst retryDelaySeconds = durationSeconds(input.retryDelaySeconds, \"retry delay\", true);\n\t\tassertErrorCode(input.errorCode);\n\t\treturn this.transitionFailure(input, \"retry\", {\n\t\t\tnext_attempt_at: this.timestampOffset(retryDelaySeconds),\n\t\t});\n\t}\n\n\tasync failWork(\n\t\tinput: MediaUsageWorkLease & {\n\t\t\terrorCode: string;\n\t\t},\n\t): Promise<boolean> {\n\t\tassertErrorCode(input.errorCode);\n\t\treturn this.transitionFailure(input, \"failed\");\n\t}\n\n\tprivate async transitionFailure(\n\t\tinput: MediaUsageWorkLease & { errorCode: string },\n\t\tstate: \"retry\" | \"failed\",\n\t\textra: { next_attempt_at?: RawBuilder<string> } = {},\n\t): Promise<boolean> {\n\t\tassertLease(input);\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"_emdash_media_usage_work\")\n\t\t\t.set({\n\t\t\t\tstate,\n\t\t\t\tattempt_count: sql<number>`attempt_count + 1`,\n\t\t\t\tlease_token: null,\n\t\t\t\tlease_expires_at: null,\n\t\t\t\tlast_error_code: input.errorCode,\n\t\t\t\tupdated_at: this.timestampOffset(0),\n\t\t\t\t...extra,\n\t\t\t})\n\t\t\t.where(\"collection_id\", \"=\", input.collectionId)\n\t\t\t.where(\"content_id\", \"=\", input.contentId)\n\t\t\t.where(\"work_version\", \"=\", input.workVersion)\n\t\t\t.where(\"state\", \"=\", \"leased\")\n\t\t\t.where(\"lease_token\", \"=\", input.leaseToken)\n\t\t\t.where(this.leaseIsLive())\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numUpdatedRows ?? 0) > 0;\n\t}\n\n\tprivate leaseIsLive(): RawBuilder<boolean> {\n\t\treturn isPostgres(this.db)\n\t\t\t? sql<boolean>`lease_expires_at::timestamptz > clock_timestamp()`\n\t\t\t: sql<boolean>`lease_expires_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;\n\t}\n\n\tprivate qualifiedLeaseIsLive(column: string): RawBuilder<boolean> {\n\t\tconst expiry = sql.ref(column);\n\t\treturn isPostgres(this.db)\n\t\t\t? sql<boolean>`${expiry} > to_char(statement_timestamp() AT TIME ZONE 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')`\n\t\t\t: sql<boolean>`${expiry} > strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;\n\t}\n\n\tprivate timestampIsDue(\n\t\tcolumn: \"next_attempt_at\" | \"lease_expires_at\" | \"work.lease_expires_at\",\n\t): RawBuilder<boolean> {\n\t\treturn isPostgres(this.db)\n\t\t\t? sql<boolean>`${sql.ref(column)} <= to_char(\n\t\t\t\tstatement_timestamp() AT TIME ZONE 'UTC',\n\t\t\t\t'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"'\n\t\t\t)`\n\t\t\t: sql<boolean>`${sql.ref(column)} <= strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;\n\t}\n\n\tprivate timestampOffset(offsetSeconds: number): RawBuilder<string> {\n\t\tif (isPostgres(this.db)) {\n\t\t\treturn sql<string>`to_char(\n\t\t\t\t(clock_timestamp() AT TIME ZONE 'UTC') + (${offsetSeconds} * INTERVAL '1 second'),\n\t\t\t\t'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"'\n\t\t\t)`;\n\t\t}\n\t\treturn sql<string>`strftime(\n\t\t\t'%Y-%m-%dT%H:%M:%fZ',\n\t\t\t'now',\n\t\t\t${`${offsetSeconds >= 0 ? \"+\" : \"\"}${offsetSeconds} seconds`}\n\t\t)`;\n\t}\n}\n\nfunction operatorLimit(value: number | undefined): number {\n\tif (value === undefined) return MEDIA_USAGE_WORK_OPERATOR_DEFAULT_LIMIT;\n\tif (!Number.isSafeInteger(value) || value < 1 || value > MEDIA_USAGE_WORK_OPERATOR_MAX_LIMIT) {\n\t\tthrow new Error(\n\t\t\t`Media usage operator limit must be a whole number from 1 to ${MEDIA_USAGE_WORK_OPERATOR_MAX_LIMIT}`,\n\t\t);\n\t}\n\treturn value;\n}\n\nfunction durationSeconds(value: number, label: string, allowZero: boolean): number {\n\tif (\n\t\t!Number.isSafeInteger(value) ||\n\t\tvalue < (allowZero ? 0 : 1) ||\n\t\tvalue > MAX_PORTABLE_DURATION_SECONDS\n\t) {\n\t\tthrow new Error(\n\t\t\t`Media usage work ${label} must be ${allowZero ? \"a non-negative\" : \"a positive\"} whole number of seconds no greater than one year`,\n\t\t);\n\t}\n\treturn value;\n}\n\nfunction assertIdentity(input: MediaUsageWorkIdentity): void {\n\tif (!input.collectionId || !input.contentId) {\n\t\tthrow new Error(\"Media usage work identity must include collection and content IDs\");\n\t}\n\tconst validVersion =\n\t\t(typeof input.workVersion === \"number\" &&\n\t\t\tNumber.isSafeInteger(input.workVersion) &&\n\t\t\tinput.workVersion > 0) ||\n\t\t(typeof input.workVersion === \"string\" && POSITIVE_DECIMAL_PATTERN.test(input.workVersion));\n\tif (!validVersion) {\n\t\tthrow new Error(\"Media usage work identity must include a work version\");\n\t}\n}\n\nfunction assertNonNegativeDecimal(value: number | string, label: string): void {\n\tconst valid =\n\t\t(typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0) ||\n\t\t(typeof value === \"string\" && NON_NEGATIVE_DECIMAL_PATTERN.test(value));\n\tif (!valid) throw new Error(`Media usage work ${label} must be a non-negative whole number`);\n}\n\nfunction assertToken(value: string): void {\n\tif (!value) throw new Error(\"Media usage work lease token must not be empty\");\n}\n\nfunction assertLease(input: MediaUsageWorkLease): void {\n\tassertIdentity(input);\n\tassertToken(input.leaseToken);\n}\n\nfunction assertErrorCode(value: string): void {\n\tif (!STABLE_ERROR_CODE_PATTERN.test(value)) {\n\t\tthrow new Error(\"Media usage work error code must use a stable SCREAMING_SNAKE_CASE value\");\n\t}\n}\n\nfunction rowToWork(row: Selectable<MediaUsageWorkTable>): MediaUsageWorkRecord {\n\tif (!isMediaUsageWorkState(row.state)) {\n\t\tthrow new Error(`Invalid media usage work state: ${row.state}`);\n\t}\n\treturn {\n\t\tcollectionId: row.collection_id,\n\t\tcollectionSlug: row.collection_slug,\n\t\tcontentId: row.content_id,\n\t\tchangeEpoch: row.change_epoch,\n\t\tworkVersion: row.work_version,\n\t\tstate: row.state,\n\t\tattemptCount: row.attempt_count,\n\t\tnextAttemptAt: row.next_attempt_at,\n\t\tleaseToken: row.lease_token,\n\t\tleaseExpiresAt: row.lease_expires_at,\n\t\tlastAttemptedAt: row.last_attempted_at,\n\t\tlastErrorCode: row.last_error_code,\n\t\tcreatedAt: row.created_at,\n\t\tupdatedAt: row.updated_at,\n\t};\n}\n\nfunction rowToOperatorWork(\n\trow: Selectable<MediaUsageWorkTable> | MediaUsageWorkRecord,\n): MediaUsageOperatorWorkItem {\n\tconst work = \"collection_id\" in row ? rowToWork(row) : row;\n\treturn {\n\t\tcollectionId: work.collectionId,\n\t\tcollectionSlug: work.collectionSlug,\n\t\tcontentId: work.contentId,\n\t\tstate: work.state,\n\t\tattemptCount: work.attemptCount,\n\t\tnextAttemptAt: work.nextAttemptAt,\n\t\tleaseExpiresAt: work.leaseExpiresAt,\n\t\tlastAttemptedAt: work.lastAttemptedAt,\n\t\tlastErrorCode: work.lastErrorCode,\n\t\tupdatedAt: work.updatedAt,\n\t};\n}\n\nfunction isMediaUsageWorkState(value: string): value is MediaUsageWorkState {\n\treturn value === \"pending\" || value === \"retry\" || value === \"leased\" || value === \"failed\";\n}\n\nfunction compareDueWork(a: MediaUsageWorkRecord, b: MediaUsageWorkRecord): number {\n\tconst eligibility = dueTimestamp(a).localeCompare(dueTimestamp(b));\n\tif (eligibility !== 0) return eligibility;\n\tconst updated = a.updatedAt.localeCompare(b.updatedAt);\n\tif (updated !== 0) return updated;\n\tconst collection = a.collectionId.localeCompare(b.collectionId);\n\treturn collection !== 0 ? collection : a.contentId.localeCompare(b.contentId);\n}\n\nfunction compareOperatorWork(a: MediaUsageOperatorWorkItem, b: MediaUsageOperatorWorkItem): number {\n\tconst updated = b.updatedAt.localeCompare(a.updatedAt);\n\treturn updated !== 0 ? updated : b.contentId.localeCompare(a.contentId);\n}\n\nfunction dueTimestamp(work: MediaUsageWorkRecord): string {\n\tif (work.state !== \"leased\") return work.nextAttemptAt;\n\tif (!work.leaseExpiresAt) throw new Error(\"Due leased media usage work must have a lease expiry\");\n\treturn work.leaseExpiresAt;\n}\n"],"mappings":"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"}