@happyvertical/smrt-timesheets 0.53.5 → 0.54.0

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,5 +1,5 @@
1
- import { i as ServiceTimeEntryCollection } from "./chunks/service-time-entry-Bq8C9-2d.js";
2
- import { a as AttendanceReplay, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, t as AttendanceBreak } from "./chunks/models-DYz8H_CQ.js";
1
+ import { i as ServiceTimeEntryCollection } from "./chunks/service-time-entry-d-7DR8p_.js";
2
+ import { a as AttendanceReplay, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, t as AttendanceBreak } from "./chunks/models-Cgkkr2v5.js";
3
3
  import { isEmbeddedDatabase, isPostgresDatabase, withEmbeddedWriteTransaction } from "@happyvertical/smrt-core";
4
4
  import { getTenantId, withTenant } from "@happyvertical/smrt-tenancy";
5
5
  //#region src/attendance/service.ts
@@ -1,5 +1,5 @@
1
- import { i as AttendancePunchCollection, n as AttendanceBreakCollection } from "./models-DYz8H_CQ.js";
2
- import { i as integer, n as clipSource, r as instant } from "./rollup-fHN5k25K.js";
1
+ import { i as AttendancePunchCollection, n as AttendanceBreakCollection } from "./models-Cgkkr2v5.js";
2
+ import { i as integer, n as clipSource, r as instant } from "./rollup-CSLT1xrA.js";
3
3
  //#region src/rollup/attendance.ts
4
4
  async function attendanceSources(db, actor, period) {
5
5
  const punches = await AttendancePunchCollection.create({ db });
@@ -57,4 +57,4 @@ async function attendanceSources(db, actor, period) {
57
57
  //#endregion
58
58
  export { attendanceSources };
59
59
 
60
- //# sourceMappingURL=attendance-Bxfh35rv.js.map
60
+ //# sourceMappingURL=attendance-Ct1c5N7f.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"attendance-Bxfh35rv.js","names":[],"sources":["../../src/rollup/attendance.ts"],"sourcesContent":["import type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n AttendanceBreakCollection,\n AttendancePunchCollection,\n} from '../attendance/models.js';\nimport { clipSource, instant, integer } from './calculation.js';\nimport type { TimecardActor, TimecardPeriod, TimecardSource } from './types.js';\n\n/** Optional attendance reader. Called on the rollup's transaction executor. */\nexport async function attendanceSources(\n db: DatabaseInterface,\n actor: TimecardActor,\n period: TimecardPeriod,\n): Promise<{ sources: TimecardSource[]; linkedEntryIds: Set<string> }> {\n const punches = await AttendancePunchCollection.create({ db });\n const breaks = await AttendanceBreakCollection.create({ db });\n const sources: TimecardSource[] = [];\n const linkedEntryIds = new Set<string>();\n for (const punch of await punches.list({ where: { ...actor } })) {\n // A linked punch is authoritative even when pending review: never count its\n // evidence entry behind the review gate, or outside the punch's period.\n if (punch.serviceTimeEntryId) linkedEntryIds.add(punch.serviceTimeEntryId);\n if (!punch.endedAt || punch.reviewRequired) continue;\n const start = instant(punch.startedAt);\n const end = instant(punch.endedAt);\n if (end < start) throw new Error('Invalid attendance interval.');\n let cursor = start;\n let unpaidMs = 0;\n const spans: [number, number][] = [];\n for (const pause of await breaks.list({\n where: { tenantId: actor.tenantId, punchId: punch.id },\n orderBy: 'started_at ASC',\n })) {\n if (!pause.endedAt)\n throw new Error('Closed attendance has an open break.');\n const left = instant(pause.startedAt);\n const right = instant(pause.endedAt);\n if (left < cursor || right < left || right > end)\n throw new Error('Invalid or overlapping attendance breaks.');\n if (!pause.paid) {\n spans.push([cursor, left]);\n unpaidMs += right - left;\n } else {\n spans.push([cursor, right]);\n }\n cursor = right;\n }\n spans.push([cursor, end]);\n const net = Math.round((end - start - unpaidMs) / 1000);\n if (integer(punch.durationSeconds) !== net)\n throw new Error('Attendance duration does not match its breaks.');\n // Round elapsed paid prefixes once, preserving conservation across breaks.\n let paidMs = 0;\n for (const [left, right] of spans) {\n const seconds =\n Math.round((paidMs + right - left) / 1000) - Math.round(paidMs / 1000);\n paidMs += right - left;\n const source = clipSource(\n {\n kind: 'attendance',\n id: String(punch.id),\n startsAt: new Date(left).toISOString(),\n endsAt: new Date(right).toISOString(),\n seconds,\n },\n period,\n );\n if (source?.seconds) sources.push(source);\n }\n }\n return { sources, linkedEntryIds };\n}\n"],"mappings":";;;AASA,eAAsB,kBACpB,IACA,OACA,QACqE;CACrE,MAAM,UAAU,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC7D,MAAM,SAAS,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC5D,MAAM,UAA4B,CAAC;CACnC,MAAM,iCAAiB,IAAI,IAAY;CACvC,KAAA,MAAW,SAAS,MAAM,QAAQ,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG;EAG/D,IAAI,MAAM,oBAAoB,eAAe,IAAI,MAAM,kBAAkB;EACzE,IAAI,CAAC,MAAM,WAAW,MAAM,gBAAgB;EAC5C,MAAM,QAAQ,QAAQ,MAAM,SAAS;EACrC,MAAM,MAAM,QAAQ,MAAM,OAAO;EACjC,IAAI,MAAM,OAAO,MAAM,IAAI,MAAM,8BAA8B;EAC/D,IAAI,SAAS;EACb,IAAI,WAAW;EACf,MAAM,QAA4B,CAAC;EACnC,KAAA,MAAW,SAAS,MAAM,OAAO,KAAK;GACpC,OAAO;IAAE,UAAU,MAAM;IAAU,SAAS,MAAM;GAAG;GACrD,SAAS;EACX,CAAC,GAAG;GACF,IAAI,CAAC,MAAM,SACT,MAAM,IAAI,MAAM,sCAAsC;GACxD,MAAM,OAAO,QAAQ,MAAM,SAAS;GACpC,MAAM,QAAQ,QAAQ,MAAM,OAAO;GACnC,IAAI,OAAO,UAAU,QAAQ,QAAQ,QAAQ,KAC3C,MAAM,IAAI,MAAM,2CAA2C;GAC7D,IAAI,CAAC,MAAM,MAAM;IACf,MAAM,KAAK,CAAC,QAAQ,IAAI,CAAC;IACzB,YAAY,QAAQ;GACtB,OACE,MAAM,KAAK,CAAC,QAAQ,KAAK,CAAC;GAE5B,SAAS;EACX;EACA,MAAM,KAAK,CAAC,QAAQ,GAAG,CAAC;EACxB,MAAM,MAAM,KAAK,OAAO,MAAM,QAAQ,YAAY,GAAI;EACtD,IAAI,QAAQ,MAAM,eAAe,MAAM,KACrC,MAAM,IAAI,MAAM,gDAAgD;EAElE,IAAI,SAAS;EACb,KAAA,MAAW,CAAC,MAAM,UAAU,OAAO;GACjC,MAAM,UACJ,KAAK,OAAO,SAAS,QAAQ,QAAQ,GAAI,IAAI,KAAK,MAAM,SAAS,GAAI;GACvE,UAAU,QAAQ;GAClB,MAAM,SAAS,WACb;IACE,MAAM;IACN,IAAI,OAAO,MAAM,EAAE;IACnB,UAAU,IAAI,KAAK,IAAI,CAAA,CAAE,YAAY;IACrC,QAAQ,IAAI,KAAK,KAAK,CAAA,CAAE,YAAY;IACpC;GACF,GACA,MACF;GACA,IAAI,QAAQ,SAAS,QAAQ,KAAK,MAAM;EAC1C;CACF;CACA,OAAO;EAAE;EAAS;CAAe;AACnC"}
1
+ {"version":3,"file":"attendance-Ct1c5N7f.js","names":[],"sources":["../../src/rollup/attendance.ts"],"sourcesContent":["import type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n AttendanceBreakCollection,\n AttendancePunchCollection,\n} from '../attendance/models.js';\nimport { clipSource, instant, integer } from './calculation.js';\nimport type { TimecardActor, TimecardPeriod, TimecardSource } from './types.js';\n\n/** Optional attendance reader. Called on the rollup's transaction executor. */\nexport async function attendanceSources(\n db: DatabaseInterface,\n actor: TimecardActor,\n period: TimecardPeriod,\n): Promise<{ sources: TimecardSource[]; linkedEntryIds: Set<string> }> {\n const punches = await AttendancePunchCollection.create({ db });\n const breaks = await AttendanceBreakCollection.create({ db });\n const sources: TimecardSource[] = [];\n const linkedEntryIds = new Set<string>();\n for (const punch of await punches.list({ where: { ...actor } })) {\n // A linked punch is authoritative even when pending review: never count its\n // evidence entry behind the review gate, or outside the punch's period.\n if (punch.serviceTimeEntryId) linkedEntryIds.add(punch.serviceTimeEntryId);\n if (!punch.endedAt || punch.reviewRequired) continue;\n const start = instant(punch.startedAt);\n const end = instant(punch.endedAt);\n if (end < start) throw new Error('Invalid attendance interval.');\n let cursor = start;\n let unpaidMs = 0;\n const spans: [number, number][] = [];\n for (const pause of await breaks.list({\n where: { tenantId: actor.tenantId, punchId: punch.id },\n orderBy: 'started_at ASC',\n })) {\n if (!pause.endedAt)\n throw new Error('Closed attendance has an open break.');\n const left = instant(pause.startedAt);\n const right = instant(pause.endedAt);\n if (left < cursor || right < left || right > end)\n throw new Error('Invalid or overlapping attendance breaks.');\n if (!pause.paid) {\n spans.push([cursor, left]);\n unpaidMs += right - left;\n } else {\n spans.push([cursor, right]);\n }\n cursor = right;\n }\n spans.push([cursor, end]);\n const net = Math.round((end - start - unpaidMs) / 1000);\n if (integer(punch.durationSeconds) !== net)\n throw new Error('Attendance duration does not match its breaks.');\n // Round elapsed paid prefixes once, preserving conservation across breaks.\n let paidMs = 0;\n for (const [left, right] of spans) {\n const seconds =\n Math.round((paidMs + right - left) / 1000) - Math.round(paidMs / 1000);\n paidMs += right - left;\n const source = clipSource(\n {\n kind: 'attendance',\n id: String(punch.id),\n startsAt: new Date(left).toISOString(),\n endsAt: new Date(right).toISOString(),\n seconds,\n },\n period,\n );\n if (source?.seconds) sources.push(source);\n }\n }\n return { sources, linkedEntryIds };\n}\n"],"mappings":";;;AASA,eAAsB,kBACpB,IACA,OACA,QACqE;CACrE,MAAM,UAAU,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC7D,MAAM,SAAS,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC5D,MAAM,UAA4B,CAAC;CACnC,MAAM,iCAAiB,IAAI,IAAY;CACvC,KAAA,MAAW,SAAS,MAAM,QAAQ,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG;EAG/D,IAAI,MAAM,oBAAoB,eAAe,IAAI,MAAM,kBAAkB;EACzE,IAAI,CAAC,MAAM,WAAW,MAAM,gBAAgB;EAC5C,MAAM,QAAQ,QAAQ,MAAM,SAAS;EACrC,MAAM,MAAM,QAAQ,MAAM,OAAO;EACjC,IAAI,MAAM,OAAO,MAAM,IAAI,MAAM,8BAA8B;EAC/D,IAAI,SAAS;EACb,IAAI,WAAW;EACf,MAAM,QAA4B,CAAC;EACnC,KAAA,MAAW,SAAS,MAAM,OAAO,KAAK;GACpC,OAAO;IAAE,UAAU,MAAM;IAAU,SAAS,MAAM;GAAG;GACrD,SAAS;EACX,CAAC,GAAG;GACF,IAAI,CAAC,MAAM,SACT,MAAM,IAAI,MAAM,sCAAsC;GACxD,MAAM,OAAO,QAAQ,MAAM,SAAS;GACpC,MAAM,QAAQ,QAAQ,MAAM,OAAO;GACnC,IAAI,OAAO,UAAU,QAAQ,QAAQ,QAAQ,KAC3C,MAAM,IAAI,MAAM,2CAA2C;GAC7D,IAAI,CAAC,MAAM,MAAM;IACf,MAAM,KAAK,CAAC,QAAQ,IAAI,CAAC;IACzB,YAAY,QAAQ;GACtB,OACE,MAAM,KAAK,CAAC,QAAQ,KAAK,CAAC;GAE5B,SAAS;EACX;EACA,MAAM,KAAK,CAAC,QAAQ,GAAG,CAAC;EACxB,MAAM,MAAM,KAAK,OAAO,MAAM,QAAQ,YAAY,GAAI;EACtD,IAAI,QAAQ,MAAM,eAAe,MAAM,KACrC,MAAM,IAAI,MAAM,gDAAgD;EAElE,IAAI,SAAS;EACb,KAAA,MAAW,CAAC,MAAM,UAAU,OAAO;GACjC,MAAM,UACJ,KAAK,OAAO,SAAS,QAAQ,QAAQ,GAAI,IAAI,KAAK,MAAM,SAAS,GAAI;GACvE,UAAU,QAAQ;GAClB,MAAM,SAAS,WACb;IACE,MAAM;IACN,IAAI,OAAO,MAAM,EAAE;IACnB,UAAU,IAAI,KAAK,IAAI,CAAA,CAAE,YAAY;IACrC,QAAQ,IAAI,KAAK,KAAK,CAAA,CAAE,YAAY;IACpC;GACF,GACA,MACF;GACA,IAAI,QAAQ,SAAS,QAAQ,KAAK,MAAM;EAC1C;CACF;CACA,OAAO;EAAE;EAAS;CAAe;AACnC"}
@@ -1,4 +1,4 @@
1
- import { o as parseTimesheetJson } from "./service-time-entry-Bq8C9-2d.js";
1
+ import { o as parseTimesheetJson } from "./service-time-entry-d-7DR8p_.js";
2
2
  import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, isEmbeddedDatabase, isPostgresDatabase, smrt, withEmbeddedWriteTransaction } from "@happyvertical/smrt-core";
3
3
  import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
4
4
  //#region src/attendance/models.ts
@@ -163,4 +163,4 @@ var AttendanceReplayCollection = class extends SmrtCollection {
163
163
  //#endregion
164
164
  export { AttendanceReplay as a, AttendancePunchCollection as i, AttendanceBreakCollection as n, AttendanceReplayCollection as o, AttendancePunch as r, AttendanceBreak as t };
165
165
 
166
- //# sourceMappingURL=models-DYz8H_CQ.js.map
166
+ //# sourceMappingURL=models-Cgkkr2v5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"models-DYz8H_CQ.js","names":[],"sources":["../../src/attendance/models.ts"],"sourcesContent":["import {\n crossPackageRef,\n field,\n foreignKey,\n isEmbeddedDatabase,\n isPostgresDatabase,\n SmrtCollection,\n SmrtObject,\n smrt,\n withEmbeddedWriteTransaction,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { parseTimesheetJson } from '../models/json.js';\n\n// Punch closes and break writes share one atomic parent boundary, including direct ORM saves.\nasync function saveWithPunchLock<T extends SmrtObject>(\n model: T,\n punchId: string | null | undefined,\n tenant: string,\n save: () => Promise<T>,\n): Promise<T> {\n return withEmbeddedWriteTransaction(\n model.db,\n isEmbeddedDatabase(model.db),\n (db) =>\n model.withDatabase(db, async () => {\n if (punchId && isPostgresDatabase(db))\n await db.query(\n 'SELECT id FROM attendance_punches WHERE id = $1 AND tenant_id = $2 FOR UPDATE',\n punchId,\n tenant,\n );\n return save();\n }),\n true,\n );\n}\n\n/** A tenant-scoped interval of attendance, independent of billable work. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'attendance_punches',\n indexes: [\n {\n name: 'attendance_punches_open_owner_key',\n columns: ['tenantId', 'profileId', 'openSlot'],\n unique: true,\n },\n ],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class AttendancePunch extends SmrtObject {\n @tenantId() tenantId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile') profileId = '';\n startedAt: Date = new Date();\n endedAt: Date | null = null;\n durationSeconds = 0;\n unpaidBreakSeconds = 0;\n reviewRequired = false;\n recordedOffline = false;\n // Resolve the active table family, including smrt-support's same-named subtype.\n @foreignKey('ServiceTimeEntry', { nullable: true }) serviceTimeEntryId:\n | string\n | null = null;\n /** Unique while open; closed rows retain independent non-null slots on every dialect. */\n @field({ required: true }) openSlot = '';\n\n override async save(): Promise<this> {\n return saveWithPunchLock(this, this.id, this.tenantId, () =>\n this.saveConsistent(),\n );\n }\n\n private async saveConsistent(): Promise<this> {\n if (!this.tenantId || !this.profileId)\n throw new Error('Attendance requires tenantId and profileId.');\n if (\n !Number.isFinite(this.startedAt?.getTime()) ||\n (this.endedAt &&\n (!Number.isFinite(this.endedAt.getTime()) ||\n this.endedAt < this.startedAt))\n )\n throw new Error('Invalid attendance interval.');\n if (\n ![this.durationSeconds, this.unpaidBreakSeconds].every(\n (value) => Number.isSafeInteger(value) && value >= 0,\n )\n )\n throw new Error(\n 'Attendance durations must be nonnegative safe integer seconds.',\n );\n const prior = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (\n prior &&\n (prior.tenant_id !== this.tenantId ||\n prior.profile_id !== this.profileId ||\n new Date(prior.started_at as string).getTime() !==\n this.startedAt.getTime())\n )\n throw new Error('Attendance ownership and start are immutable.');\n if (\n prior?.ended_at &&\n (new Date(prior.ended_at as string).getTime() !==\n this.endedAt?.getTime() ||\n Number(prior.duration_seconds) !== this.durationSeconds ||\n Number(prior.unpaid_break_seconds) !== this.unpaidBreakSeconds)\n )\n throw new Error('Closed attendance evidence is immutable.');\n if (this.id && this.endedAt) {\n const breaks = await this.db.list('attendance_breaks', {\n tenant_id: this.tenantId,\n punch_id: this.id,\n });\n if (\n breaks.some(\n (item) =>\n !item.ended_at ||\n new Date(item.started_at as string).getTime() <\n this.startedAt.getTime() ||\n new Date(item.ended_at as string).getTime() >\n this.endedAt!.getTime(),\n )\n )\n throw new Error('Break must be inside its tenant-owned punch.');\n }\n this.id ??= crypto.randomUUID();\n this.openSlot = this.endedAt ? JSON.stringify(['closed', this.id]) : 'open';\n return super.save();\n }\n}\n\n/** A paid or unpaid break inside one attendance punch. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'attendance_breaks',\n indexes: [\n {\n name: 'attendance_breaks_open_punch_key',\n columns: ['tenantId', 'punchId', 'openSlot'],\n unique: true,\n },\n ],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class AttendanceBreak extends SmrtObject {\n @tenantId() tenantId = '';\n @foreignKey(AttendancePunch) punchId = '';\n startedAt: Date = new Date();\n endedAt: Date | null = null;\n paid = false;\n @field({ required: true }) openSlot = '';\n\n override async save(): Promise<this> {\n return saveWithPunchLock(this, this.punchId, this.tenantId, () =>\n this.saveConsistent(),\n );\n }\n\n private async saveConsistent(): Promise<this> {\n if (!this.tenantId || !this.punchId || typeof this.paid !== 'boolean')\n throw new Error('Invalid attendance break.');\n if (\n !Number.isFinite(this.startedAt?.getTime()) ||\n (this.endedAt &&\n (!Number.isFinite(this.endedAt.getTime()) ||\n this.endedAt < this.startedAt))\n )\n throw new Error('Invalid attendance break interval.');\n const parent = await this.db.get('attendance_punches', {\n id: this.punchId,\n tenant_id: this.tenantId,\n });\n if (\n !parent ||\n this.startedAt.getTime() <\n new Date(parent.started_at as string).getTime() ||\n (parent.ended_at &&\n (!this.endedAt ||\n this.endedAt.getTime() >\n new Date(parent.ended_at as string).getTime()))\n )\n throw new Error('Break must be inside its tenant-owned punch.');\n const prior = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (\n prior &&\n (prior.tenant_id !== this.tenantId ||\n prior.punch_id !== this.punchId ||\n new Date(prior.started_at as string).getTime() !==\n this.startedAt.getTime() ||\n Boolean(prior.paid) !== this.paid)\n )\n throw new Error('Break ownership, start and pay policy are immutable.');\n if (\n prior?.ended_at &&\n new Date(prior.ended_at as string).getTime() !== this.endedAt?.getTime()\n )\n throw new Error('Closed breaks are immutable.');\n this.id ??= crypto.randomUUID();\n this.openSlot = this.endedAt ? JSON.stringify(['closed', this.id]) : 'open';\n return super.save();\n }\n}\n\n/** Durable success or conflict; conflicts do not mutate attendance. */\nexport interface AttendanceReplayOutcome {\n clientId: string;\n punchId?: string;\n error?: string;\n}\n\nfunction validReplayOutcome(value: unknown): value is AttendanceReplayOutcome {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const result = value as Record<string, unknown>;\n return (\n typeof result.clientId === 'string' &&\n result.clientId.length > 0 &&\n ((typeof result.punchId === 'string' &&\n result.punchId.length > 0 &&\n result.error === undefined) ||\n (typeof result.error === 'string' &&\n result.error.length > 0 &&\n result.punchId === undefined))\n );\n}\n\n/** Durable offline-tap outcome; never exposed through generated operations. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'attendance_replays',\n sensitive: true,\n api: { include: [] },\n cli: { include: [] },\n mcp: { include: [] },\n})\nexport class AttendanceReplay extends SmrtObject {\n @tenantId() tenantId = '';\n @field({ required: true, unique: true }) replayKey = '';\n @field({ type: 'text' }) content = '';\n @field({ type: 'text' }) outcome = '{}';\n\n /** Read a durable receipt, failing closed rather than re-executing a corrupt tap. */\n getOutcome(): AttendanceReplayOutcome {\n const value = parseTimesheetJson<unknown>(this.outcome, null);\n if (!validReplayOutcome(value))\n throw new Error('Invalid stored attendance replay outcome.');\n return value;\n }\n\n /** Store the JSON representation of a validated success or refusal. */\n setOutcome(value: AttendanceReplayOutcome): void {\n if (!validReplayOutcome(value))\n throw new Error('Invalid attendance replay outcome.');\n this.outcome = JSON.stringify(value);\n }\n\n override async save(): Promise<this> {\n this.getOutcome();\n return super.save();\n }\n}\n\n/** Punches for attendance and period rollup. */\nexport class AttendancePunchCollection extends SmrtCollection<AttendancePunch> {\n static readonly _itemClass = AttendancePunch;\n}\n/** Break intervals for net duration and period clipping. */\nexport class AttendanceBreakCollection extends SmrtCollection<AttendanceBreak> {\n static readonly _itemClass = AttendanceBreak;\n}\n/** Internal durable replay ledger. */\nexport class AttendanceReplayCollection extends SmrtCollection<AttendanceReplay> {\n static readonly _itemClass = AttendanceReplay;\n}\n"],"mappings":";;;;;;;;;;;;AAeA,eAAe,kBACb,OACA,SACA,QACA,MACY;CACZ,OAAO,6BACL,MAAM,IACN,mBAAmB,MAAM,EAAE,IAC1B,OACC,MAAM,aAAa,IAAI,YAAY;EACjC,IAAI,WAAW,mBAAmB,EAAE,GAClC,MAAM,GAAG,MACP,iFACA,SACA,MACF;EACF,OAAO,KAAK;CACd,CAAC,GACH,IACF;AACF;AAiBO,IAAM,kBAAN,cAA8B,WAAW;CAClC,WAAW;CACkC,YAAY;CACrE,4BAAkB,IAAI,KAAK;CAC3B,UAAuB;CACvB,kBAAkB;CAClB,qBAAqB;CACrB,iBAAiB;CACjB,kBAAkB;CAEkC,qBAEzC;CAEgB,WAAW;CAEtC,MAAe,OAAsB;EACnC,OAAO,kBAAkB,MAAM,KAAK,IAAI,KAAK,gBAC3C,KAAK,eAAe,CACtB;CACF;CAEA,MAAc,iBAAgC;EAC5C,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,WAC1B,MAAM,IAAI,MAAM,6CAA6C;EAC/D,IACE,CAAC,OAAO,SAAS,KAAK,WAAW,QAAQ,CAAC,KACzC,KAAK,YACH,CAAC,OAAO,SAAS,KAAK,QAAQ,QAAQ,CAAC,KACtC,KAAK,UAAU,KAAK,YAExB,MAAM,IAAI,MAAM,8BAA8B;EAChD,IACE,CAAC,CAAC,KAAK,iBAAiB,KAAK,kBAAkB,CAAA,CAAE,OAC9C,UAAU,OAAO,cAAc,KAAK,KAAK,SAAS,CACrD,GAEA,MAAM,IAAI,MACR,gEACF;EACF,MAAM,QAAQ,KAAK,KACf,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,EAAE,IAAI,KAAK,GAAG,CAAC,IACjD;EACJ,IACE,UACC,MAAM,cAAc,KAAK,YACxB,MAAM,eAAe,KAAK,aAC1B,IAAI,KAAK,MAAM,UAAoB,CAAA,CAAE,QAAQ,MAC3C,KAAK,UAAU,QAAQ,IAE3B,MAAM,IAAI,MAAM,+CAA+C;EACjE,IACE,OAAO,aACN,IAAI,KAAK,MAAM,QAAkB,CAAA,CAAE,QAAQ,MAC1C,KAAK,SAAS,QAAQ,KACtB,OAAO,MAAM,gBAAgB,MAAM,KAAK,mBACxC,OAAO,MAAM,oBAAoB,MAAM,KAAK,qBAE9C,MAAM,IAAI,MAAM,0CAA0C;EAC5D,IAAI,KAAK,MAAM,KAAK;QAMhB,MALmB,KAAK,GAAG,KAAK,qBAAqB;IACrD,WAAW,KAAK;IAChB,UAAU,KAAK;GACjB,CAAC,EAAA,CAEQ,MACJ,SACC,CAAC,KAAK,YACN,IAAI,KAAK,KAAK,UAAoB,CAAA,CAAE,QAAQ,IAC1C,KAAK,UAAU,QAAQ,KACzB,IAAI,KAAK,KAAK,QAAkB,CAAA,CAAE,QAAQ,IACxC,KAAK,QAAS,QAAQ,CAC5B,GAEA,MAAM,IAAI,MAAM,8CAA8C;EAAA;EAElE,KAAK,OAAO,OAAO,WAAW;EAC9B,KAAK,WAAW,KAAK,UAAU,KAAK,UAAU,CAAC,UAAU,KAAK,EAAE,CAAC,IAAI;EACrE,OAAO,MAAM,KAAK;CACpB;AACF;AA/Ec,gBAAA,CAAX,SAAS,CAAA,GADC,gBACC,WAAA,YAAA,CAAA;AAC6C,gBAAA,CAAxD,gBAAgB,sCAAsC,CAAA,GAF5C,gBAE8C,WAAA,aAAA,CAAA;AAQL,gBAAA,CAAnD,WAAW,oBAAoB,EAAE,UAAU,KAAK,CAAC,CAAA,GAVvC,gBAUyC,WAAA,sBAAA,CAAA;AAIzB,gBAAA,CAA1B,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAdd,gBAcgB,WAAA,YAAA,CAAA;AAdhB,kBAAN,gBAAA,CAdN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,SAAS,CACP;EACE,MAAM;EACN,SAAS;GAAC;GAAY;GAAa;EAAU;EAC7C,QAAQ;CACV,CACF;CACA,KAAK,EAAE,SAAS,CAAC,QAAQ,KAAK,EAAE;CAChC,KAAK,EAAE,SAAS,CAAC,QAAQ,KAAK,EAAE;CAChC,KAAK,EAAE,SAAS,CAAC,QAAQ,KAAK,EAAE;AAClC,CAAC,CAAA,GACY,eAAA;AAiGN,IAAM,kBAAN,cAA8B,WAAW;CAClC,WAAW;CACM,UAAU;CACvC,4BAAkB,IAAI,KAAK;CAC3B,UAAuB;CACvB,OAAO;CACoB,WAAW;CAEtC,MAAe,OAAsB;EACnC,OAAO,kBAAkB,MAAM,KAAK,SAAS,KAAK,gBAChD,KAAK,eAAe,CACtB;CACF;CAEA,MAAc,iBAAgC;EAC5C,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,WAAW,OAAO,KAAK,SAAS,WAC1D,MAAM,IAAI,MAAM,2BAA2B;EAC7C,IACE,CAAC,OAAO,SAAS,KAAK,WAAW,QAAQ,CAAC,KACzC,KAAK,YACH,CAAC,OAAO,SAAS,KAAK,QAAQ,QAAQ,CAAC,KACtC,KAAK,UAAU,KAAK,YAExB,MAAM,IAAI,MAAM,oCAAoC;EACtD,MAAM,SAAS,MAAM,KAAK,GAAG,IAAI,sBAAsB;GACrD,IAAI,KAAK;GACT,WAAW,KAAK;EAClB,CAAC;EACD,IACE,CAAC,UACD,KAAK,UAAU,QAAQ,IACrB,IAAI,KAAK,OAAO,UAAoB,CAAA,CAAE,QAAQ,KAC/C,OAAO,aACL,CAAC,KAAK,WACL,KAAK,QAAQ,QAAQ,IACnB,IAAI,KAAK,OAAO,QAAkB,CAAA,CAAE,QAAQ,IAElD,MAAM,IAAI,MAAM,8CAA8C;EAChE,MAAM,QAAQ,KAAK,KACf,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,EAAE,IAAI,KAAK,GAAG,CAAC,IACjD;EACJ,IACE,UACC,MAAM,cAAc,KAAK,YACxB,MAAM,aAAa,KAAK,WACxB,IAAI,KAAK,MAAM,UAAoB,CAAA,CAAE,QAAQ,MAC3C,KAAK,UAAU,QAAQ,KACzB,QAAQ,MAAM,IAAI,MAAM,KAAK,OAE/B,MAAM,IAAI,MAAM,sDAAsD;EACxE,IACE,OAAO,YACP,IAAI,KAAK,MAAM,QAAkB,CAAA,CAAE,QAAQ,MAAM,KAAK,SAAS,QAAQ,GAEvE,MAAM,IAAI,MAAM,8BAA8B;EAChD,KAAK,OAAO,OAAO,WAAW;EAC9B,KAAK,WAAW,KAAK,UAAU,KAAK,UAAU,CAAC,UAAU,KAAK,EAAE,CAAC,IAAI;EACrE,OAAO,MAAM,KAAK;CACpB;AACF;AA1Dc,gBAAA,CAAX,SAAS,CAAA,GADC,gBACC,WAAA,YAAA,CAAA;AACiB,gBAAA,CAA5B,WAAW,eAAe,CAAA,GAFhB,gBAEkB,WAAA,WAAA,CAAA;AAIF,gBAAA,CAA1B,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GANd,gBAMgB,WAAA,YAAA,CAAA;AANhB,kBAAN,gBAAA,CAdN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,SAAS,CACP;EACE,MAAM;EACN,SAAS;GAAC;GAAY;GAAW;EAAU;EAC3C,QAAQ;CACV,CACF;CACA,KAAK,EAAE,SAAS,CAAC,QAAQ,KAAK,EAAE;CAChC,KAAK,EAAE,SAAS,CAAC,QAAQ,KAAK,EAAE;CAChC,KAAK,EAAE,SAAS,CAAC,QAAQ,KAAK,EAAE;AAClC,CAAC,CAAA,GACY,eAAA;AAoEb,SAAS,mBAAmB,OAAkD;CAC5E,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG,OAAO;CACxE,MAAM,SAAS;CACf,OACE,OAAO,OAAO,aAAa,YAC3B,OAAO,SAAS,SAAS,MACvB,OAAO,OAAO,YAAY,YAC1B,OAAO,QAAQ,SAAS,KACxB,OAAO,UAAU,KAAA,KAChB,OAAO,OAAO,UAAU,YACvB,OAAO,MAAM,SAAS,KACtB,OAAO,YAAY,KAAA;AAE3B;AAWO,IAAM,mBAAN,cAA+B,WAAW;CACnC,WAAW;CACkB,YAAY;CAC5B,UAAU;CACV,UAAU;;CAGnC,aAAsC;EACpC,MAAM,QAAQ,mBAA4B,KAAK,SAAS,IAAI;EAC5D,IAAI,CAAC,mBAAmB,KAAK,GAC3B,MAAM,IAAI,MAAM,2CAA2C;EAC7D,OAAO;CACT;;CAGA,WAAW,OAAsC;EAC/C,IAAI,CAAC,mBAAmB,KAAK,GAC3B,MAAM,IAAI,MAAM,oCAAoC;EACtD,KAAK,UAAU,KAAK,UAAU,KAAK;CACrC;CAEA,MAAe,OAAsB;EACnC,KAAK,WAAW;EAChB,OAAO,MAAM,KAAK;CACpB;AACF;AAxBc,gBAAA,CAAX,SAAS,CAAA,GADC,iBACC,WAAA,YAAA,CAAA;AAC6B,gBAAA,CAAxC,MAAM;CAAE,UAAU;CAAM,QAAQ;AAAK,CAAC,CAAA,GAF5B,iBAE8B,WAAA,aAAA,CAAA;AAChB,gBAAA,CAAxB,MAAM,EAAE,MAAM,OAAO,CAAC,CAAA,GAHZ,iBAGc,WAAA,WAAA,CAAA;AACA,gBAAA,CAAxB,MAAM,EAAE,MAAM,OAAO,CAAC,CAAA,GAJZ,iBAIc,WAAA,WAAA,CAAA;AAJd,mBAAN,gBAAA,CARN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,WAAW;CACX,KAAK,EAAE,SAAS,CAAC,EAAE;CACnB,KAAK,EAAE,SAAS,CAAC,EAAE;CACnB,KAAK,EAAE,SAAS,CAAC,EAAE;AACrB,CAAC,CAAA,GACY,gBAAA;AA4BN,IAAM,4BAAN,cAAwC,eAAgC;CAC7E,OAAgB,aAAa;AAC/B;AAEO,IAAM,4BAAN,cAAwC,eAAgC;CAC7E,OAAgB,aAAa;AAC/B;AAEO,IAAM,6BAAN,cAAyC,eAAiC;CAC/E,OAAgB,aAAa;AAC/B"}
1
+ {"version":3,"file":"models-Cgkkr2v5.js","names":[],"sources":["../../src/attendance/models.ts"],"sourcesContent":["import {\n crossPackageRef,\n field,\n foreignKey,\n isEmbeddedDatabase,\n isPostgresDatabase,\n SmrtCollection,\n SmrtObject,\n smrt,\n withEmbeddedWriteTransaction,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { parseTimesheetJson } from '../models/json.js';\n\n// Punch closes and break writes share one atomic parent boundary, including direct ORM saves.\nasync function saveWithPunchLock<T extends SmrtObject>(\n model: T,\n punchId: string | null | undefined,\n tenant: string,\n save: () => Promise<T>,\n): Promise<T> {\n return withEmbeddedWriteTransaction(\n model.db,\n isEmbeddedDatabase(model.db),\n (db) =>\n model.withDatabase(db, async () => {\n if (punchId && isPostgresDatabase(db))\n await db.query(\n 'SELECT id FROM attendance_punches WHERE id = $1 AND tenant_id = $2 FOR UPDATE',\n punchId,\n tenant,\n );\n return save();\n }),\n true,\n );\n}\n\n/** A tenant-scoped interval of attendance, independent of billable work. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'attendance_punches',\n indexes: [\n {\n name: 'attendance_punches_open_owner_key',\n columns: ['tenantId', 'profileId', 'openSlot'],\n unique: true,\n },\n ],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class AttendancePunch extends SmrtObject {\n @tenantId() tenantId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile') profileId = '';\n startedAt: Date = new Date();\n endedAt: Date | null = null;\n durationSeconds = 0;\n unpaidBreakSeconds = 0;\n reviewRequired = false;\n recordedOffline = false;\n // Resolve the active table family, including smrt-support's same-named subtype.\n @foreignKey('ServiceTimeEntry', { nullable: true }) serviceTimeEntryId:\n | string\n | null = null;\n /** Unique while open; closed rows retain independent non-null slots on every dialect. */\n @field({ required: true }) openSlot = '';\n\n override async save(): Promise<this> {\n return saveWithPunchLock(this, this.id, this.tenantId, () =>\n this.saveConsistent(),\n );\n }\n\n private async saveConsistent(): Promise<this> {\n if (!this.tenantId || !this.profileId)\n throw new Error('Attendance requires tenantId and profileId.');\n if (\n !Number.isFinite(this.startedAt?.getTime()) ||\n (this.endedAt &&\n (!Number.isFinite(this.endedAt.getTime()) ||\n this.endedAt < this.startedAt))\n )\n throw new Error('Invalid attendance interval.');\n if (\n ![this.durationSeconds, this.unpaidBreakSeconds].every(\n (value) => Number.isSafeInteger(value) && value >= 0,\n )\n )\n throw new Error(\n 'Attendance durations must be nonnegative safe integer seconds.',\n );\n const prior = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (\n prior &&\n (prior.tenant_id !== this.tenantId ||\n prior.profile_id !== this.profileId ||\n new Date(prior.started_at as string).getTime() !==\n this.startedAt.getTime())\n )\n throw new Error('Attendance ownership and start are immutable.');\n if (\n prior?.ended_at &&\n (new Date(prior.ended_at as string).getTime() !==\n this.endedAt?.getTime() ||\n Number(prior.duration_seconds) !== this.durationSeconds ||\n Number(prior.unpaid_break_seconds) !== this.unpaidBreakSeconds)\n )\n throw new Error('Closed attendance evidence is immutable.');\n if (this.id && this.endedAt) {\n const breaks = await this.db.list('attendance_breaks', {\n tenant_id: this.tenantId,\n punch_id: this.id,\n });\n if (\n breaks.some(\n (item) =>\n !item.ended_at ||\n new Date(item.started_at as string).getTime() <\n this.startedAt.getTime() ||\n new Date(item.ended_at as string).getTime() >\n this.endedAt!.getTime(),\n )\n )\n throw new Error('Break must be inside its tenant-owned punch.');\n }\n this.id ??= crypto.randomUUID();\n this.openSlot = this.endedAt ? JSON.stringify(['closed', this.id]) : 'open';\n return super.save();\n }\n}\n\n/** A paid or unpaid break inside one attendance punch. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'attendance_breaks',\n indexes: [\n {\n name: 'attendance_breaks_open_punch_key',\n columns: ['tenantId', 'punchId', 'openSlot'],\n unique: true,\n },\n ],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class AttendanceBreak extends SmrtObject {\n @tenantId() tenantId = '';\n @foreignKey(AttendancePunch) punchId = '';\n startedAt: Date = new Date();\n endedAt: Date | null = null;\n paid = false;\n @field({ required: true }) openSlot = '';\n\n override async save(): Promise<this> {\n return saveWithPunchLock(this, this.punchId, this.tenantId, () =>\n this.saveConsistent(),\n );\n }\n\n private async saveConsistent(): Promise<this> {\n if (!this.tenantId || !this.punchId || typeof this.paid !== 'boolean')\n throw new Error('Invalid attendance break.');\n if (\n !Number.isFinite(this.startedAt?.getTime()) ||\n (this.endedAt &&\n (!Number.isFinite(this.endedAt.getTime()) ||\n this.endedAt < this.startedAt))\n )\n throw new Error('Invalid attendance break interval.');\n const parent = await this.db.get('attendance_punches', {\n id: this.punchId,\n tenant_id: this.tenantId,\n });\n if (\n !parent ||\n this.startedAt.getTime() <\n new Date(parent.started_at as string).getTime() ||\n (parent.ended_at &&\n (!this.endedAt ||\n this.endedAt.getTime() >\n new Date(parent.ended_at as string).getTime()))\n )\n throw new Error('Break must be inside its tenant-owned punch.');\n const prior = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (\n prior &&\n (prior.tenant_id !== this.tenantId ||\n prior.punch_id !== this.punchId ||\n new Date(prior.started_at as string).getTime() !==\n this.startedAt.getTime() ||\n Boolean(prior.paid) !== this.paid)\n )\n throw new Error('Break ownership, start and pay policy are immutable.');\n if (\n prior?.ended_at &&\n new Date(prior.ended_at as string).getTime() !== this.endedAt?.getTime()\n )\n throw new Error('Closed breaks are immutable.');\n this.id ??= crypto.randomUUID();\n this.openSlot = this.endedAt ? JSON.stringify(['closed', this.id]) : 'open';\n return super.save();\n }\n}\n\n/** Durable success or conflict; conflicts do not mutate attendance. */\nexport interface AttendanceReplayOutcome {\n clientId: string;\n punchId?: string;\n error?: string;\n}\n\nfunction validReplayOutcome(value: unknown): value is AttendanceReplayOutcome {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const result = value as Record<string, unknown>;\n return (\n typeof result.clientId === 'string' &&\n result.clientId.length > 0 &&\n ((typeof result.punchId === 'string' &&\n result.punchId.length > 0 &&\n result.error === undefined) ||\n (typeof result.error === 'string' &&\n result.error.length > 0 &&\n result.punchId === undefined))\n );\n}\n\n/** Durable offline-tap outcome; never exposed through generated operations. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'attendance_replays',\n sensitive: true,\n api: { include: [] },\n cli: { include: [] },\n mcp: { include: [] },\n})\nexport class AttendanceReplay extends SmrtObject {\n @tenantId() tenantId = '';\n @field({ required: true, unique: true }) replayKey = '';\n @field({ type: 'text' }) content = '';\n @field({ type: 'text' }) outcome = '{}';\n\n /** Read a durable receipt, failing closed rather than re-executing a corrupt tap. */\n getOutcome(): AttendanceReplayOutcome {\n const value = parseTimesheetJson<unknown>(this.outcome, null);\n if (!validReplayOutcome(value))\n throw new Error('Invalid stored attendance replay outcome.');\n return value;\n }\n\n /** Store the JSON representation of a validated success or refusal. */\n setOutcome(value: AttendanceReplayOutcome): void {\n if (!validReplayOutcome(value))\n throw new Error('Invalid attendance replay outcome.');\n this.outcome = JSON.stringify(value);\n }\n\n override async save(): Promise<this> {\n this.getOutcome();\n return super.save();\n }\n}\n\n/** Punches for attendance and period rollup. */\nexport class AttendancePunchCollection extends SmrtCollection<AttendancePunch> {\n static readonly _itemClass = AttendancePunch;\n}\n/** Break intervals for net duration and period clipping. */\nexport class AttendanceBreakCollection extends SmrtCollection<AttendanceBreak> {\n static readonly _itemClass = AttendanceBreak;\n}\n/** Internal durable replay ledger. */\nexport class AttendanceReplayCollection extends SmrtCollection<AttendanceReplay> {\n static readonly _itemClass = AttendanceReplay;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { i as ServiceTimeEntryCollection } from "./service-time-entry-Bq8C9-2d.js";
1
+ import { i as ServiceTimeEntryCollection } from "./service-time-entry-d-7DR8p_.js";
2
2
  import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, isEmbeddedDatabase, isPostgresDatabase, smrt, withEmbeddedWriteTransaction } from "@happyvertical/smrt-core";
3
3
  import { TenantScoped, getTenantId, tenantId, withTenant } from "@happyvertical/smrt-tenancy";
4
4
  import { createHash } from "node:crypto";
@@ -263,7 +263,7 @@ var PeriodRollupService = class {
263
263
  let sources = [];
264
264
  let linkedEntryIds = /* @__PURE__ */ new Set();
265
265
  if (this.options.attendance) {
266
- const { attendanceSources } = await import("./attendance-Bxfh35rv.js");
266
+ const { attendanceSources } = await import("./attendance-Ct1c5N7f.js");
267
267
  ({sources, linkedEntryIds} = await attendanceSources(db, this.actor, period));
268
268
  }
269
269
  const evidence = await (await ServiceTimeEntryCollection.create({ db })).list({ where: {
@@ -423,4 +423,4 @@ var PeriodRollupService = class {
423
423
  //#endregion
424
424
  export { PeriodTimecard as a, TimecardAdjustmentCollection as c, integer as i, clipSource as n, PeriodTimecardCollection as o, instant as r, TimecardAdjustment as s, PeriodRollupService as t };
425
425
 
426
- //# sourceMappingURL=rollup-fHN5k25K.js.map
426
+ //# sourceMappingURL=rollup-CSLT1xrA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rollup-fHN5k25K.js","names":["id"],"sources":["../../src/rollup/write.ts","../../src/rollup/models.ts","../../src/rollup/calculation.ts","../../src/rollup/service.ts"],"sourcesContent":["import type { SmrtObject } from '@happyvertical/smrt-core';\n\n// Per-instance capability, deliberately absent from the package export surface.\nconst permitted = new WeakSet<SmrtObject>();\nexport function assertRollupWrite(object: SmrtObject): void {\n if (!permitted.has(object))\n throw new Error(\n 'Timecards and adjustments are writable only through PeriodRollupService.',\n );\n}\nexport async function persistRollup<T extends SmrtObject>(\n object: T,\n): Promise<T> {\n permitted.add(object);\n try {\n await object.save();\n return object;\n } finally {\n permitted.delete(object);\n }\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { TimecardSource } from './types.js';\nimport { assertRollupWrite } from './write.js';\n\n/** One person's immutable-on-confirmation period snapshot, in integer seconds. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'period_timecards',\n sensitive: true,\n api: { include: [] },\n cli: { include: [] },\n mcp: { include: [] },\n})\nexport class PeriodTimecard extends SmrtObject {\n @tenantId() tenantId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n onDelete: 'RESTRICT',\n })\n profileId = '';\n startsAt: Date = new Date(0);\n endsAt: Date = new Date(0);\n timezone = '';\n rulesVersion = '';\n @field({ type: 'text' }) rulesSnapshot = '{}';\n @field({ type: 'text' }) sourceSnapshot = '[]';\n regularSeconds = 0;\n overtimeSeconds = 0;\n totalSeconds = 0;\n @field({ type: 'text' }) status: 'open' | 'confirmed' = 'open';\n confirmedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n nullable: true,\n onDelete: 'RESTRICT',\n })\n confirmedByProfileId: string | null = null;\n\n /** Return a detached source snapshot; corrupt persisted JSON fails closed. */\n getSources(): TimecardSource[] {\n const result: unknown = JSON.parse(this.sourceSnapshot);\n if (!Array.isArray(result))\n throw new Error('Invalid timecard source snapshot.');\n return result as TimecardSource[];\n }\n /** Return the consumer policy frozen with this rollup. */\n getRules(): Record<string, unknown> {\n const result: unknown = JSON.parse(this.rulesSnapshot);\n if (!result || typeof result !== 'object' || Array.isArray(result))\n throw new Error('Invalid timecard rules snapshot.');\n return result as Record<string, unknown>;\n }\n override async save(): Promise<this> {\n assertRollupWrite(this);\n const prior = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (prior?.status === 'confirmed')\n throw new Error(\n 'Confirmed timecards are immutable; append an adjustment.',\n );\n if (\n prior &&\n (prior.tenant_id !== this.tenantId ||\n prior.profile_id !== this.profileId ||\n new Date(prior.starts_at as string).getTime() !==\n this.startsAt.getTime())\n )\n throw new Error('Timecard identity is immutable.');\n return (await super.save()) as this;\n }\n override async delete(): Promise<void> {\n throw new Error('Timecard history cannot be deleted.');\n }\n}\n\n/** Attributed append-only signed seconds; the confirmed base card never changes. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'timecard_adjustments',\n sensitive: true,\n api: { include: [] },\n cli: { include: [] },\n mcp: { include: [] },\n})\nexport class TimecardAdjustment extends SmrtObject {\n @tenantId() tenantId = '';\n @foreignKey(PeriodTimecard, { onDelete: 'RESTRICT' }) timecardId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n onDelete: 'RESTRICT',\n })\n profileId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n onDelete: 'RESTRICT',\n })\n actorProfileId = '';\n operationId = '';\n regularSeconds = 0;\n overtimeSeconds = 0;\n reason = '';\n override async save(): Promise<this> {\n assertRollupWrite(this);\n if (this.id && (await this.db.get(this.tableName, { id: this.id })))\n throw new Error('Timecard adjustments are append-only.');\n this.requireInsertOnSave();\n return (await super.save()) as this;\n }\n override async delete(): Promise<void> {\n throw new Error('Timecard adjustments cannot be deleted.');\n }\n}\n/** Scoped persistence collection; mutations must use PeriodRollupService. */\nexport class PeriodTimecardCollection extends SmrtCollection<PeriodTimecard> {\n static readonly _itemClass = PeriodTimecard;\n}\n/** Scoped append-only adjustment collection. */\nexport class TimecardAdjustmentCollection extends SmrtCollection<TimecardAdjustment> {\n static readonly _itemClass = TimecardAdjustment;\n}\n","import type { TimecardPeriod, TimecardSource } from './types.js';\n\nexport function integer(value: number, signed = false): number {\n if (!Number.isSafeInteger(value) || (!signed && value < 0))\n throw new Error('Timecard seconds must be safe integers and nonnegative.');\n return value;\n}\nexport function instant(value: Date): number {\n if (!(value instanceof Date) || !Number.isFinite(value.getTime()))\n throw new Error('Timecard timestamps must be valid dates.');\n return value.getTime();\n}\nexport function validatePeriod(\n value: TimecardPeriod,\n at: Date,\n): TimecardPeriod {\n if (\n !value ||\n instant(value.startsAt) > instant(at) ||\n instant(value.endsAt) <= instant(at) ||\n instant(value.startsAt) >= instant(value.endsAt)\n )\n throw new Error('Resolver period must contain the requested instant.');\n if (!value.timezone || !value.version?.trim())\n throw new Error('Resolver must supply a timezone and policy version.');\n new Intl.DateTimeFormat('en', { timeZone: value.timezone });\n if (\n !value.rules ||\n typeof value.rules !== 'object' ||\n Array.isArray(value.rules)\n )\n throw new Error('Resolver rules must be a JSON object.');\n // JSON round-trip detaches consumer-owned state; fail rather than silently lose non-JSON values.\n const json = JSON.stringify(value.rules, (_key, item) => {\n if (\n typeof item === 'function' ||\n typeof item === 'undefined' ||\n typeof item === 'symbol' ||\n (typeof item === 'number' && !Number.isFinite(item))\n )\n throw new Error('Resolver rules must be JSON serializable.');\n return item;\n });\n const rules: unknown = JSON.parse(json);\n if (!rules || typeof rules !== 'object' || Array.isArray(rules))\n throw new Error('Resolver rules must serialize to a JSON object.');\n return {\n startsAt: new Date(value.startsAt),\n endsAt: new Date(value.endsAt),\n timezone: value.timezone,\n version: value.version,\n rules: rules as Record<string, unknown>,\n };\n}\n/** Prefix allocation preserves integer seconds across adjacent half-open periods. */\nexport function clipSource(\n source: TimecardSource,\n period: TimecardPeriod,\n): TimecardSource | null {\n const start = instant(new Date(source.startsAt));\n const end = instant(new Date(source.endsAt));\n integer(source.seconds);\n if (end < start) throw new Error('Invalid source interval.');\n const left = Math.max(start, period.startsAt.getTime());\n const right = Math.min(end, period.endsAt.getTime());\n if (start === end)\n return start >= period.startsAt.getTime() && start < period.endsAt.getTime()\n ? { ...source }\n : null;\n if (left >= right) return null;\n const span = integer(end - start);\n const prefix = (elapsed: number) =>\n Number((BigInt(source.seconds) * BigInt(integer(elapsed))) / BigInt(span));\n const seconds = prefix(right - start) - prefix(left - start);\n return {\n ...source,\n startsAt: new Date(left).toISOString(),\n endsAt: new Date(right).toISOString(),\n seconds: integer(seconds),\n };\n}\n","import { createHash } from 'node:crypto';\nimport {\n isEmbeddedDatabase,\n isPostgresDatabase,\n withEmbeddedWriteTransaction,\n} from '@happyvertical/smrt-core';\nimport { getTenantId, withTenant } from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { ServiceTimeEntryCollection } from '../models/service-time-entry.js';\nimport { clipSource, instant, integer, validatePeriod } from './calculation.js';\nimport {\n PeriodTimecard,\n PeriodTimecardCollection,\n TimecardAdjustment,\n TimecardAdjustmentCollection,\n} from './models.js';\nimport type {\n PeriodRulesResolver,\n TimecardActor,\n TimecardAdjustmentInput,\n TimecardSource,\n} from './types.js';\nimport { persistRollup } from './write.js';\n\nfunction identity(parts: string[]): string {\n const bytes = createHash('sha256').update(JSON.stringify(parts)).digest();\n bytes[6] = (bytes[6] & 15) | 80;\n bytes[8] = (bytes[8] & 63) | 128;\n const hex = bytes.subarray(0, 16).toString('hex');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction adjustedSeconds(\n base: number,\n rows: TimecardAdjustment[],\n field: 'regularSeconds' | 'overtimeSeconds',\n): number {\n const total = rows.reduce(\n (sum, row) => sum + BigInt(integer(row[field], true)),\n BigInt(integer(base)),\n );\n return integer(Number(total));\n}\n\n/**\n * Server-side, trusted tenant/person capability. Consumers authorize this scope\n * before construction. Reads and writes reject conflicting ambient tenancy.\n * SQLite and PostgreSQL are supported; policy and payroll remain consumer-owned.\n */\nexport class PeriodRollupService {\n constructor(\n private readonly db: DatabaseInterface,\n private readonly actor: TimecardActor,\n private readonly resolver: PeriodRulesResolver,\n private readonly options: {\n attendance?: boolean;\n actorProfileId?: string;\n } = {},\n ) {\n if (!actor.tenantId?.trim() || !actor.profileId?.trim())\n throw new Error('Timecards require a trusted tenant/profile actor.');\n this.actor = Object.freeze({\n tenantId: this.identity(actor.tenantId),\n profileId: this.identity(actor.profileId),\n });\n if (options.actorProfileId !== undefined && !options.actorProfileId.trim())\n throw new Error('Actor attribution must be a nonempty profile id.');\n this.options = {\n attendance: options.attendance,\n actorProfileId: this.identity(\n options.actorProfileId ?? this.actor.profileId,\n ),\n };\n }\n\n private identity(value: string): string {\n if (!isPostgresDatabase(this.db)) return value;\n const hex = value.replace(/[{}-]/g, '').toLowerCase();\n if (!/^[0-9a-f]{32}$/.test(hex))\n throw new Error('PostgreSQL timecard identities must be UUIDs.');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n private scope<T>(run: () => Promise<T>): Promise<T> {\n const active = getTenantId();\n if (active && this.identity(active) !== this.actor.tenantId)\n throw new Error('Timecard actor differs from active tenant.');\n return withTenant({ tenantId: this.actor.tenantId }, run);\n }\n private transact<T>(run: (db: DatabaseInterface) => Promise<T>): Promise<T> {\n return this.scope(() =>\n withEmbeddedWriteTransaction(\n this.db,\n isEmbeddedDatabase(this.db),\n async (db) => {\n if (isPostgresDatabase(db))\n await db.query(\n 'SELECT pg_advisory_xact_lock(hashtextextended($1, 0))',\n JSON.stringify([\n 'smrt.rollup',\n this.actor.tenantId,\n this.actor.profileId,\n ]),\n );\n if (this.options.attendance && isPostgresDatabase(db))\n await db.query(\n 'SELECT pg_advisory_xact_lock(hashtextextended($1, 0))',\n JSON.stringify([\n 'smrt.attendance',\n this.actor.tenantId,\n this.actor.profileId,\n ]),\n );\n return run(db);\n },\n true,\n ),\n );\n }\n private async card(\n db: DatabaseInterface,\n id: string,\n ): Promise<PeriodTimecard> {\n const collection = await PeriodTimecardCollection.create({ db });\n const [card] = await collection.list({\n where: { ...this.actor, id },\n limit: 1,\n });\n if (!card) throw new Error('Timecard not found in actor scope.');\n return card;\n }\n /** Scoped read on the root executor, including after transaction completion. */\n async get(id: string): Promise<PeriodTimecard> {\n return this.scope(() => this.card(this.db, id));\n }\n /** Rebuild one open card from a consistent transaction-bound source snapshot. */\n async rollup(at: Date): Promise<PeriodTimecard> {\n at = new Date(instant(at));\n const id = await this.transact(async (db) => {\n const period = validatePeriod(\n await this.resolver.periodFor(new Date(at), this.actor),\n at,\n );\n const id = identity([\n 'smrt.period',\n this.actor.tenantId,\n this.actor.profileId,\n period.startsAt.toISOString(),\n ]);\n const collection = await PeriodTimecardCollection.create({ db });\n const [prior] = await collection.list({\n where: { ...this.actor, id },\n limit: 1,\n });\n if (prior?.status === 'confirmed')\n throw new Error(\n 'Confirmed timecards are immutable; append an adjustment.',\n );\n // A policy change must not create overlapping cards for the same person.\n for (const other of await collection.list({ where: { ...this.actor } })) {\n if (\n other.id !== id &&\n other.startsAt < period.endsAt &&\n other.endsAt > period.startsAt\n )\n throw new Error('Resolver period overlaps an existing timecard.');\n }\n let sources: TimecardSource[] = [];\n let linkedEntryIds = new Set<string>();\n if (this.options.attendance) {\n const { attendanceSources } = await import('./attendance.js');\n ({ sources, linkedEntryIds } = await attendanceSources(\n db,\n this.actor,\n period,\n ));\n }\n const entries = await ServiceTimeEntryCollection.create({ db });\n const evidence = await entries.list({\n where: {\n tenantId: this.actor.tenantId,\n participantProfileId: this.actor.profileId,\n participantKind: 'human',\n },\n });\n const byId = new Map(evidence.map((entry) => [String(entry.id), entry]));\n const approvedRoots = new Set<string>();\n for (const entry of evidence) {\n if (entry.status !== 'approved') continue;\n let linked = linkedEntryIds.has(String(entry.id));\n let ancestor = entry;\n const seen = new Set([String(entry.id)]);\n while (ancestor.correctionOfId) {\n const parentId = ancestor.correctionOfId;\n if (seen.has(parentId))\n throw new Error('Cyclic evidence correction chain.');\n seen.add(parentId);\n const parent = byId.get(parentId);\n if (!parent || parent.status !== 'corrected')\n throw new Error(\n 'Correction requires corrected evidence in the same actor scope.',\n );\n linked ||= linkedEntryIds.has(parentId);\n ancestor = parent;\n }\n const rootId = String(ancestor.id);\n if (approvedRoots.has(rootId))\n throw new Error('Ambiguous approved evidence correction chain.');\n approvedRoots.add(rootId);\n if (linked) continue;\n // Duration-only manual evidence belongs to its approval instant. A\n // bounded interval allocates its actual duration by elapsed fraction.\n const start = entry.startedAt ?? entry.approvedAt;\n if (!start)\n throw new Error(\n 'Approved evidence needs a start or approval timestamp.',\n );\n // Hours-only sources are unbounded and attributed at approval. An\n // unsupported quantity in another period must not block this one.\n if (\n entry.durationSeconds === null &&\n (instant(start) < period.startsAt.getTime() ||\n instant(start) >= period.endsAt.getTime())\n )\n continue;\n const end = entry.startedAt && entry.endedAt ? entry.endedAt : start;\n const source = clipSource(\n {\n kind: 'entry',\n id: String(entry.id),\n startsAt: new Date(instant(start)).toISOString(),\n endsAt: new Date(instant(end)).toISOString(),\n seconds: integer(entry.requireDurationSeconds()),\n },\n period,\n );\n if (source?.seconds) sources.push(source);\n }\n sources.sort(\n (a, b) =>\n a.startsAt.localeCompare(b.startsAt) ||\n a.kind.localeCompare(b.kind) ||\n a.id.localeCompare(b.id),\n );\n const totalSeconds = sources.reduce(\n (sum, source) => integer(sum + source.seconds),\n 0,\n );\n // Resolver receives detached snapshots so it cannot alter persisted evidence.\n const classified = await this.resolver.classify(\n structuredClone(period),\n structuredClone(sources),\n this.actor,\n );\n const regularSeconds = integer(classified?.regularSeconds);\n const overtimeSeconds = integer(classified?.overtimeSeconds);\n if (integer(regularSeconds + overtimeSeconds) !== totalSeconds)\n throw new Error('Resolver classification must conserve total seconds.');\n const card =\n prior ??\n (await new PeriodTimecard({ db, id, _skipLoad: true }).initialize());\n if (!prior) card.requireInsertOnSave();\n Object.assign(card, this.actor, {\n startsAt: period.startsAt,\n endsAt: period.endsAt,\n timezone: period.timezone,\n rulesVersion: period.version,\n rulesSnapshot: JSON.stringify(period.rules),\n sourceSnapshot: JSON.stringify(sources),\n regularSeconds,\n overtimeSeconds,\n totalSeconds,\n });\n await persistRollup(card);\n return id;\n });\n return this.get(id);\n }\n /** Confirm the current snapshot; repeated confirmation is idempotent. */\n async confirm(id: string): Promise<PeriodTimecard> {\n await this.transact(async (db) => {\n const card = await this.card(db, id);\n if (card.status === 'confirmed') return;\n card.status = 'confirmed';\n card.confirmedAt = new Date();\n card.confirmedByProfileId = this.options.actorProfileId!;\n await persistRollup(card);\n });\n return this.get(id);\n }\n /** Append a correction. An operation key retry must have exactly the same payload. */\n async adjust(\n id: string,\n input: TimecardAdjustmentInput,\n ): Promise<TimecardAdjustment> {\n id = this.identity(id);\n input = {\n operationId: input.operationId,\n reason: input.reason,\n regularSeconds: input.regularSeconds,\n overtimeSeconds: input.overtimeSeconds,\n };\n integer(input.regularSeconds, true);\n integer(input.overtimeSeconds, true);\n if (!input.operationId?.trim() || !input.reason?.trim())\n throw new Error('Adjustment requires an operationId and reason.');\n const adjustmentId = identity([\n 'smrt.adjustment',\n this.actor.tenantId,\n this.actor.profileId,\n id,\n input.operationId,\n ]);\n await this.transact(async (db) => {\n const card = await this.card(db, id);\n if (card.status !== 'confirmed')\n throw new Error('Adjustments require a confirmed timecard.');\n const collection = await TimecardAdjustmentCollection.create({ db });\n const rows = await collection.list({\n where: { ...this.actor, timecardId: id },\n });\n const prior = rows.find((row) => row.id === adjustmentId);\n if (prior) {\n if (\n prior.regularSeconds !== input.regularSeconds ||\n prior.overtimeSeconds !== input.overtimeSeconds ||\n prior.reason !== input.reason ||\n prior.actorProfileId !== this.options.actorProfileId\n )\n throw new Error(\n 'Adjustment operationId reused with a different payload.',\n );\n return;\n }\n const regular = adjustedSeconds(\n card.regularSeconds,\n rows,\n 'regularSeconds',\n );\n const overtime = adjustedSeconds(\n card.overtimeSeconds,\n rows,\n 'overtimeSeconds',\n );\n integer(\n integer(regular + input.regularSeconds) +\n integer(overtime + input.overtimeSeconds),\n );\n const adjustment = await new TimecardAdjustment({\n db,\n id: adjustmentId,\n _skipLoad: true,\n }).initialize();\n Object.assign(adjustment, this.actor, {\n timecardId: id,\n actorProfileId: this.options.actorProfileId!,\n ...input,\n });\n await persistRollup(adjustment);\n });\n return this.scope(async () => {\n const collection = await TimecardAdjustmentCollection.create({\n db: this.db,\n });\n const [row] = await collection.list({\n where: { ...this.actor, id: adjustmentId },\n limit: 1,\n });\n if (!row) throw new Error('Committed adjustment disappeared.');\n return row;\n });\n }\n /** Effective totals combine the frozen base with append-only corrections. */\n async totals(id: string): Promise<{\n regularSeconds: number;\n overtimeSeconds: number;\n totalSeconds: number;\n }> {\n return this.transact(async (db) => {\n const card = await this.card(db, id);\n const collection = await TimecardAdjustmentCollection.create({ db });\n const rows = await collection.list({\n where: { ...this.actor, timecardId: id },\n });\n const regularSeconds = adjustedSeconds(\n card.regularSeconds,\n rows,\n 'regularSeconds',\n );\n const overtimeSeconds = adjustedSeconds(\n card.overtimeSeconds,\n rows,\n 'overtimeSeconds',\n );\n return {\n regularSeconds,\n overtimeSeconds,\n totalSeconds: integer(regularSeconds + overtimeSeconds),\n };\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rollup-CSLT1xrA.js","names":["id"],"sources":["../../src/rollup/write.ts","../../src/rollup/models.ts","../../src/rollup/calculation.ts","../../src/rollup/service.ts"],"sourcesContent":["import type { SmrtObject } from '@happyvertical/smrt-core';\n\n// Per-instance capability, deliberately absent from the package export surface.\nconst permitted = new WeakSet<SmrtObject>();\nexport function assertRollupWrite(object: SmrtObject): void {\n if (!permitted.has(object))\n throw new Error(\n 'Timecards and adjustments are writable only through PeriodRollupService.',\n );\n}\nexport async function persistRollup<T extends SmrtObject>(\n object: T,\n): Promise<T> {\n permitted.add(object);\n try {\n await object.save();\n return object;\n } finally {\n permitted.delete(object);\n }\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { TimecardSource } from './types.js';\nimport { assertRollupWrite } from './write.js';\n\n/** One person's immutable-on-confirmation period snapshot, in integer seconds. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'period_timecards',\n sensitive: true,\n api: { include: [] },\n cli: { include: [] },\n mcp: { include: [] },\n})\nexport class PeriodTimecard extends SmrtObject {\n @tenantId() tenantId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n onDelete: 'RESTRICT',\n })\n profileId = '';\n startsAt: Date = new Date(0);\n endsAt: Date = new Date(0);\n timezone = '';\n rulesVersion = '';\n @field({ type: 'text' }) rulesSnapshot = '{}';\n @field({ type: 'text' }) sourceSnapshot = '[]';\n regularSeconds = 0;\n overtimeSeconds = 0;\n totalSeconds = 0;\n @field({ type: 'text' }) status: 'open' | 'confirmed' = 'open';\n confirmedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n nullable: true,\n onDelete: 'RESTRICT',\n })\n confirmedByProfileId: string | null = null;\n\n /** Return a detached source snapshot; corrupt persisted JSON fails closed. */\n getSources(): TimecardSource[] {\n const result: unknown = JSON.parse(this.sourceSnapshot);\n if (!Array.isArray(result))\n throw new Error('Invalid timecard source snapshot.');\n return result as TimecardSource[];\n }\n /** Return the consumer policy frozen with this rollup. */\n getRules(): Record<string, unknown> {\n const result: unknown = JSON.parse(this.rulesSnapshot);\n if (!result || typeof result !== 'object' || Array.isArray(result))\n throw new Error('Invalid timecard rules snapshot.');\n return result as Record<string, unknown>;\n }\n override async save(): Promise<this> {\n assertRollupWrite(this);\n const prior = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (prior?.status === 'confirmed')\n throw new Error(\n 'Confirmed timecards are immutable; append an adjustment.',\n );\n if (\n prior &&\n (prior.tenant_id !== this.tenantId ||\n prior.profile_id !== this.profileId ||\n new Date(prior.starts_at as string).getTime() !==\n this.startsAt.getTime())\n )\n throw new Error('Timecard identity is immutable.');\n return (await super.save()) as this;\n }\n override async delete(): Promise<void> {\n throw new Error('Timecard history cannot be deleted.');\n }\n}\n\n/** Attributed append-only signed seconds; the confirmed base card never changes. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'timecard_adjustments',\n sensitive: true,\n api: { include: [] },\n cli: { include: [] },\n mcp: { include: [] },\n})\nexport class TimecardAdjustment extends SmrtObject {\n @tenantId() tenantId = '';\n @foreignKey(PeriodTimecard, { onDelete: 'RESTRICT' }) timecardId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n onDelete: 'RESTRICT',\n })\n profileId = '';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', {\n onDelete: 'RESTRICT',\n })\n actorProfileId = '';\n operationId = '';\n regularSeconds = 0;\n overtimeSeconds = 0;\n reason = '';\n override async save(): Promise<this> {\n assertRollupWrite(this);\n if (this.id && (await this.db.get(this.tableName, { id: this.id })))\n throw new Error('Timecard adjustments are append-only.');\n this.requireInsertOnSave();\n return (await super.save()) as this;\n }\n override async delete(): Promise<void> {\n throw new Error('Timecard adjustments cannot be deleted.');\n }\n}\n/** Scoped persistence collection; mutations must use PeriodRollupService. */\nexport class PeriodTimecardCollection extends SmrtCollection<PeriodTimecard> {\n static readonly _itemClass = PeriodTimecard;\n}\n/** Scoped append-only adjustment collection. */\nexport class TimecardAdjustmentCollection extends SmrtCollection<TimecardAdjustment> {\n static readonly _itemClass = TimecardAdjustment;\n}\n","import type { TimecardPeriod, TimecardSource } from './types.js';\n\nexport function integer(value: number, signed = false): number {\n if (!Number.isSafeInteger(value) || (!signed && value < 0))\n throw new Error('Timecard seconds must be safe integers and nonnegative.');\n return value;\n}\nexport function instant(value: Date): number {\n if (!(value instanceof Date) || !Number.isFinite(value.getTime()))\n throw new Error('Timecard timestamps must be valid dates.');\n return value.getTime();\n}\nexport function validatePeriod(\n value: TimecardPeriod,\n at: Date,\n): TimecardPeriod {\n if (\n !value ||\n instant(value.startsAt) > instant(at) ||\n instant(value.endsAt) <= instant(at) ||\n instant(value.startsAt) >= instant(value.endsAt)\n )\n throw new Error('Resolver period must contain the requested instant.');\n if (!value.timezone || !value.version?.trim())\n throw new Error('Resolver must supply a timezone and policy version.');\n new Intl.DateTimeFormat('en', { timeZone: value.timezone });\n if (\n !value.rules ||\n typeof value.rules !== 'object' ||\n Array.isArray(value.rules)\n )\n throw new Error('Resolver rules must be a JSON object.');\n // JSON round-trip detaches consumer-owned state; fail rather than silently lose non-JSON values.\n const json = JSON.stringify(value.rules, (_key, item) => {\n if (\n typeof item === 'function' ||\n typeof item === 'undefined' ||\n typeof item === 'symbol' ||\n (typeof item === 'number' && !Number.isFinite(item))\n )\n throw new Error('Resolver rules must be JSON serializable.');\n return item;\n });\n const rules: unknown = JSON.parse(json);\n if (!rules || typeof rules !== 'object' || Array.isArray(rules))\n throw new Error('Resolver rules must serialize to a JSON object.');\n return {\n startsAt: new Date(value.startsAt),\n endsAt: new Date(value.endsAt),\n timezone: value.timezone,\n version: value.version,\n rules: rules as Record<string, unknown>,\n };\n}\n/** Prefix allocation preserves integer seconds across adjacent half-open periods. */\nexport function clipSource(\n source: TimecardSource,\n period: TimecardPeriod,\n): TimecardSource | null {\n const start = instant(new Date(source.startsAt));\n const end = instant(new Date(source.endsAt));\n integer(source.seconds);\n if (end < start) throw new Error('Invalid source interval.');\n const left = Math.max(start, period.startsAt.getTime());\n const right = Math.min(end, period.endsAt.getTime());\n if (start === end)\n return start >= period.startsAt.getTime() && start < period.endsAt.getTime()\n ? { ...source }\n : null;\n if (left >= right) return null;\n const span = integer(end - start);\n const prefix = (elapsed: number) =>\n Number((BigInt(source.seconds) * BigInt(integer(elapsed))) / BigInt(span));\n const seconds = prefix(right - start) - prefix(left - start);\n return {\n ...source,\n startsAt: new Date(left).toISOString(),\n endsAt: new Date(right).toISOString(),\n seconds: integer(seconds),\n };\n}\n","import { createHash } from 'node:crypto';\nimport {\n isEmbeddedDatabase,\n isPostgresDatabase,\n withEmbeddedWriteTransaction,\n} from '@happyvertical/smrt-core';\nimport { getTenantId, withTenant } from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { ServiceTimeEntryCollection } from '../models/service-time-entry.js';\nimport { clipSource, instant, integer, validatePeriod } from './calculation.js';\nimport {\n PeriodTimecard,\n PeriodTimecardCollection,\n TimecardAdjustment,\n TimecardAdjustmentCollection,\n} from './models.js';\nimport type {\n PeriodRulesResolver,\n TimecardActor,\n TimecardAdjustmentInput,\n TimecardSource,\n} from './types.js';\nimport { persistRollup } from './write.js';\n\nfunction identity(parts: string[]): string {\n const bytes = createHash('sha256').update(JSON.stringify(parts)).digest();\n bytes[6] = (bytes[6] & 15) | 80;\n bytes[8] = (bytes[8] & 63) | 128;\n const hex = bytes.subarray(0, 16).toString('hex');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction adjustedSeconds(\n base: number,\n rows: TimecardAdjustment[],\n field: 'regularSeconds' | 'overtimeSeconds',\n): number {\n const total = rows.reduce(\n (sum, row) => sum + BigInt(integer(row[field], true)),\n BigInt(integer(base)),\n );\n return integer(Number(total));\n}\n\n/**\n * Server-side, trusted tenant/person capability. Consumers authorize this scope\n * before construction. Reads and writes reject conflicting ambient tenancy.\n * SQLite and PostgreSQL are supported; policy and payroll remain consumer-owned.\n */\nexport class PeriodRollupService {\n constructor(\n private readonly db: DatabaseInterface,\n private readonly actor: TimecardActor,\n private readonly resolver: PeriodRulesResolver,\n private readonly options: {\n attendance?: boolean;\n actorProfileId?: string;\n } = {},\n ) {\n if (!actor.tenantId?.trim() || !actor.profileId?.trim())\n throw new Error('Timecards require a trusted tenant/profile actor.');\n this.actor = Object.freeze({\n tenantId: this.identity(actor.tenantId),\n profileId: this.identity(actor.profileId),\n });\n if (options.actorProfileId !== undefined && !options.actorProfileId.trim())\n throw new Error('Actor attribution must be a nonempty profile id.');\n this.options = {\n attendance: options.attendance,\n actorProfileId: this.identity(\n options.actorProfileId ?? this.actor.profileId,\n ),\n };\n }\n\n private identity(value: string): string {\n if (!isPostgresDatabase(this.db)) return value;\n const hex = value.replace(/[{}-]/g, '').toLowerCase();\n if (!/^[0-9a-f]{32}$/.test(hex))\n throw new Error('PostgreSQL timecard identities must be UUIDs.');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n private scope<T>(run: () => Promise<T>): Promise<T> {\n const active = getTenantId();\n if (active && this.identity(active) !== this.actor.tenantId)\n throw new Error('Timecard actor differs from active tenant.');\n return withTenant({ tenantId: this.actor.tenantId }, run);\n }\n private transact<T>(run: (db: DatabaseInterface) => Promise<T>): Promise<T> {\n return this.scope(() =>\n withEmbeddedWriteTransaction(\n this.db,\n isEmbeddedDatabase(this.db),\n async (db) => {\n if (isPostgresDatabase(db))\n await db.query(\n 'SELECT pg_advisory_xact_lock(hashtextextended($1, 0))',\n JSON.stringify([\n 'smrt.rollup',\n this.actor.tenantId,\n this.actor.profileId,\n ]),\n );\n if (this.options.attendance && isPostgresDatabase(db))\n await db.query(\n 'SELECT pg_advisory_xact_lock(hashtextextended($1, 0))',\n JSON.stringify([\n 'smrt.attendance',\n this.actor.tenantId,\n this.actor.profileId,\n ]),\n );\n return run(db);\n },\n true,\n ),\n );\n }\n private async card(\n db: DatabaseInterface,\n id: string,\n ): Promise<PeriodTimecard> {\n const collection = await PeriodTimecardCollection.create({ db });\n const [card] = await collection.list({\n where: { ...this.actor, id },\n limit: 1,\n });\n if (!card) throw new Error('Timecard not found in actor scope.');\n return card;\n }\n /** Scoped read on the root executor, including after transaction completion. */\n async get(id: string): Promise<PeriodTimecard> {\n return this.scope(() => this.card(this.db, id));\n }\n /** Rebuild one open card from a consistent transaction-bound source snapshot. */\n async rollup(at: Date): Promise<PeriodTimecard> {\n at = new Date(instant(at));\n const id = await this.transact(async (db) => {\n const period = validatePeriod(\n await this.resolver.periodFor(new Date(at), this.actor),\n at,\n );\n const id = identity([\n 'smrt.period',\n this.actor.tenantId,\n this.actor.profileId,\n period.startsAt.toISOString(),\n ]);\n const collection = await PeriodTimecardCollection.create({ db });\n const [prior] = await collection.list({\n where: { ...this.actor, id },\n limit: 1,\n });\n if (prior?.status === 'confirmed')\n throw new Error(\n 'Confirmed timecards are immutable; append an adjustment.',\n );\n // A policy change must not create overlapping cards for the same person.\n for (const other of await collection.list({ where: { ...this.actor } })) {\n if (\n other.id !== id &&\n other.startsAt < period.endsAt &&\n other.endsAt > period.startsAt\n )\n throw new Error('Resolver period overlaps an existing timecard.');\n }\n let sources: TimecardSource[] = [];\n let linkedEntryIds = new Set<string>();\n if (this.options.attendance) {\n const { attendanceSources } = await import('./attendance.js');\n ({ sources, linkedEntryIds } = await attendanceSources(\n db,\n this.actor,\n period,\n ));\n }\n const entries = await ServiceTimeEntryCollection.create({ db });\n const evidence = await entries.list({\n where: {\n tenantId: this.actor.tenantId,\n participantProfileId: this.actor.profileId,\n participantKind: 'human',\n },\n });\n const byId = new Map(evidence.map((entry) => [String(entry.id), entry]));\n const approvedRoots = new Set<string>();\n for (const entry of evidence) {\n if (entry.status !== 'approved') continue;\n let linked = linkedEntryIds.has(String(entry.id));\n let ancestor = entry;\n const seen = new Set([String(entry.id)]);\n while (ancestor.correctionOfId) {\n const parentId = ancestor.correctionOfId;\n if (seen.has(parentId))\n throw new Error('Cyclic evidence correction chain.');\n seen.add(parentId);\n const parent = byId.get(parentId);\n if (!parent || parent.status !== 'corrected')\n throw new Error(\n 'Correction requires corrected evidence in the same actor scope.',\n );\n linked ||= linkedEntryIds.has(parentId);\n ancestor = parent;\n }\n const rootId = String(ancestor.id);\n if (approvedRoots.has(rootId))\n throw new Error('Ambiguous approved evidence correction chain.');\n approvedRoots.add(rootId);\n if (linked) continue;\n // Duration-only manual evidence belongs to its approval instant. A\n // bounded interval allocates its actual duration by elapsed fraction.\n const start = entry.startedAt ?? entry.approvedAt;\n if (!start)\n throw new Error(\n 'Approved evidence needs a start or approval timestamp.',\n );\n // Hours-only sources are unbounded and attributed at approval. An\n // unsupported quantity in another period must not block this one.\n if (\n entry.durationSeconds === null &&\n (instant(start) < period.startsAt.getTime() ||\n instant(start) >= period.endsAt.getTime())\n )\n continue;\n const end = entry.startedAt && entry.endedAt ? entry.endedAt : start;\n const source = clipSource(\n {\n kind: 'entry',\n id: String(entry.id),\n startsAt: new Date(instant(start)).toISOString(),\n endsAt: new Date(instant(end)).toISOString(),\n seconds: integer(entry.requireDurationSeconds()),\n },\n period,\n );\n if (source?.seconds) sources.push(source);\n }\n sources.sort(\n (a, b) =>\n a.startsAt.localeCompare(b.startsAt) ||\n a.kind.localeCompare(b.kind) ||\n a.id.localeCompare(b.id),\n );\n const totalSeconds = sources.reduce(\n (sum, source) => integer(sum + source.seconds),\n 0,\n );\n // Resolver receives detached snapshots so it cannot alter persisted evidence.\n const classified = await this.resolver.classify(\n structuredClone(period),\n structuredClone(sources),\n this.actor,\n );\n const regularSeconds = integer(classified?.regularSeconds);\n const overtimeSeconds = integer(classified?.overtimeSeconds);\n if (integer(regularSeconds + overtimeSeconds) !== totalSeconds)\n throw new Error('Resolver classification must conserve total seconds.');\n const card =\n prior ??\n (await new PeriodTimecard({ db, id, _skipLoad: true }).initialize());\n if (!prior) card.requireInsertOnSave();\n Object.assign(card, this.actor, {\n startsAt: period.startsAt,\n endsAt: period.endsAt,\n timezone: period.timezone,\n rulesVersion: period.version,\n rulesSnapshot: JSON.stringify(period.rules),\n sourceSnapshot: JSON.stringify(sources),\n regularSeconds,\n overtimeSeconds,\n totalSeconds,\n });\n await persistRollup(card);\n return id;\n });\n return this.get(id);\n }\n /** Confirm the current snapshot; repeated confirmation is idempotent. */\n async confirm(id: string): Promise<PeriodTimecard> {\n await this.transact(async (db) => {\n const card = await this.card(db, id);\n if (card.status === 'confirmed') return;\n card.status = 'confirmed';\n card.confirmedAt = new Date();\n card.confirmedByProfileId = this.options.actorProfileId!;\n await persistRollup(card);\n });\n return this.get(id);\n }\n /** Append a correction. An operation key retry must have exactly the same payload. */\n async adjust(\n id: string,\n input: TimecardAdjustmentInput,\n ): Promise<TimecardAdjustment> {\n id = this.identity(id);\n input = {\n operationId: input.operationId,\n reason: input.reason,\n regularSeconds: input.regularSeconds,\n overtimeSeconds: input.overtimeSeconds,\n };\n integer(input.regularSeconds, true);\n integer(input.overtimeSeconds, true);\n if (!input.operationId?.trim() || !input.reason?.trim())\n throw new Error('Adjustment requires an operationId and reason.');\n const adjustmentId = identity([\n 'smrt.adjustment',\n this.actor.tenantId,\n this.actor.profileId,\n id,\n input.operationId,\n ]);\n await this.transact(async (db) => {\n const card = await this.card(db, id);\n if (card.status !== 'confirmed')\n throw new Error('Adjustments require a confirmed timecard.');\n const collection = await TimecardAdjustmentCollection.create({ db });\n const rows = await collection.list({\n where: { ...this.actor, timecardId: id },\n });\n const prior = rows.find((row) => row.id === adjustmentId);\n if (prior) {\n if (\n prior.regularSeconds !== input.regularSeconds ||\n prior.overtimeSeconds !== input.overtimeSeconds ||\n prior.reason !== input.reason ||\n prior.actorProfileId !== this.options.actorProfileId\n )\n throw new Error(\n 'Adjustment operationId reused with a different payload.',\n );\n return;\n }\n const regular = adjustedSeconds(\n card.regularSeconds,\n rows,\n 'regularSeconds',\n );\n const overtime = adjustedSeconds(\n card.overtimeSeconds,\n rows,\n 'overtimeSeconds',\n );\n integer(\n integer(regular + input.regularSeconds) +\n integer(overtime + input.overtimeSeconds),\n );\n const adjustment = await new TimecardAdjustment({\n db,\n id: adjustmentId,\n _skipLoad: true,\n }).initialize();\n Object.assign(adjustment, this.actor, {\n timecardId: id,\n actorProfileId: this.options.actorProfileId!,\n ...input,\n });\n await persistRollup(adjustment);\n });\n return this.scope(async () => {\n const collection = await TimecardAdjustmentCollection.create({\n db: this.db,\n });\n const [row] = await collection.list({\n where: { ...this.actor, id: adjustmentId },\n limit: 1,\n });\n if (!row) throw new Error('Committed adjustment disappeared.');\n return row;\n });\n }\n /** Effective totals combine the frozen base with append-only corrections. */\n async totals(id: string): Promise<{\n regularSeconds: number;\n overtimeSeconds: number;\n totalSeconds: number;\n }> {\n return this.transact(async (db) => {\n const card = await this.card(db, id);\n const collection = await TimecardAdjustmentCollection.create({ db });\n const rows = await collection.list({\n where: { ...this.actor, timecardId: id },\n });\n const regularSeconds = adjustedSeconds(\n card.regularSeconds,\n rows,\n 'regularSeconds',\n );\n const overtimeSeconds = adjustedSeconds(\n card.overtimeSeconds,\n rows,\n 'overtimeSeconds',\n );\n return {\n regularSeconds,\n overtimeSeconds,\n totalSeconds: integer(regularSeconds + overtimeSeconds),\n };\n });\n }\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { SERVICE_TIME_ENTRY_STATUS_TRANSITIONS } from "../types.js";
2
2
  import { ObjectRegistry, SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, smrt } from "@happyvertical/smrt-core";
3
3
  import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
4
4
  //#region src/__smrt-register__.ts
5
- ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-timesheets\",\"packageVersion\":\"0.53.5\",\"objects\":{\"@happyvertical/smrt-timesheets:AttendancePunch\":{\"name\":\"attendancepunch\",\"className\":\"AttendancePunch\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendancePunch\",\"collection\":\"attendancepunches\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\"},\"startedAt\":{\"type\":\"datetime\",\"required\":false},\"endedAt\":{\"type\":\"datetime\",\"required\":false},\"durationSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"unpaidBreakSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"reviewRequired\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"recordedOffline\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"serviceTimeEntryId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ServiceTimeEntry\",\"_meta\":{\"nullable\":true}},\"openSlot\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"attendance_punches\",\"indexes\":[{\"name\":\"attendance_punches_open_owner_key\",\"columns\":[\"tenantId\",\"profileId\",\"openSlot\"],\"unique\":true}],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"AttendancePunch\",\"collectionExportName\":\"AttendancePunchCollection\",\"validationRules\":[{\"field\":\"durationSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"unpaidBreakSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"reviewRequired\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"recordedOffline\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"openSlot\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"attendance_punches\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_punches\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"unpaid_break_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"review_required\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"recorded_offline\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"service_time_entry_id\\\" UUID,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"unpaid_break_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"review_required\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"recorded_offline\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"service_time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_punches_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_punches_open_owner_key\",\"columns\":[\"tenant_id\",\"profile_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_punches_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_punches_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"attendance_punches_service_time_entry_id_idx\",\"columns\":[\"service_time_entry_id\"]}],\"version\":\"eeca63b1\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceBreak\":{\"name\":\"attendancebreak\",\"className\":\"AttendanceBreak\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceBreak\",\"collection\":\"attendancebreaks\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"punchId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"AttendancePunch\"},\"startedAt\":{\"type\":\"datetime\",\"required\":false},\"endedAt\":{\"type\":\"datetime\",\"required\":false},\"paid\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"openSlot\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"attendance_breaks\",\"indexes\":[{\"name\":\"attendance_breaks_open_punch_key\",\"columns\":[\"tenantId\",\"punchId\",\"openSlot\"],\"unique\":true}],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"AttendanceBreak\",\"collectionExportName\":\"AttendanceBreakCollection\",\"validationRules\":[{\"field\":\"paid\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"openSlot\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"attendance_breaks\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_breaks\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"punch_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"paid\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"punch_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"attendance_punches\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"paid\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_breaks_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_breaks_open_punch_key\",\"columns\":[\"tenant_id\",\"punch_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_breaks_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_breaks_punch_id_idx\",\"columns\":[\"punch_id\"]}],\"version\":\"00cb739e\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceReplay\":{\"name\":\"attendancereplay\",\"className\":\"AttendanceReplay\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceReplay\",\"collection\":\"attendancereplays\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"replayKey\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true,\"unique\":true}},\"content\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"outcome\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"getOutcome\":{\"name\":\"getOutcome\",\"async\":false,\"parameters\":[],\"returnType\":\"AttendanceReplayOutcome\",\"isStatic\":false,\"isPublic\":true},\"setOutcome\":{\"name\":\"setOutcome\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"AttendanceReplayOutcome\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"attendance_replays\",\"sensitive\":true,\"api\":{\"include\":[]},\"cli\":{\"include\":[]},\"mcp\":{\"include\":[]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"AttendanceReplay\",\"collectionExportName\":\"AttendanceReplayCollection\",\"validationRules\":[{\"field\":\"replayKey\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"attendance_replays\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_replays\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"replay_key\\\" TEXT NOT NULL UNIQUE,\\n \\\"content\\\" TEXT,\\n \\\"outcome\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"replay_key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"content\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"outcome\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_replays_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_replays_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"f051b7b6\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendancePunchCollection\":{\"name\":\"attendancepunchcollection\",\"className\":\"AttendancePunchCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendancePunchCollection\",\"collection\":\"attendancepunches\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"attendance_punches\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AttendancePunch\",\"exportName\":\"AttendancePunchCollection\",\"collectionExportName\":\"AttendancePunchCollectionCollection\",\"schema\":{\"tableName\":\"attendance_punches\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_punches\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"unpaid_break_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"review_required\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"recorded_offline\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"service_time_entry_id\\\" UUID,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"unpaid_break_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"review_required\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"recorded_offline\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"service_time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_punches_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_punches_open_owner_key\",\"columns\":[\"tenant_id\",\"profile_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_punches_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_punches_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"attendance_punches_service_time_entry_id_idx\",\"columns\":[\"service_time_entry_id\"]}],\"version\":\"eeca63b1\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceBreakCollection\":{\"name\":\"attendancebreakcollection\",\"className\":\"AttendanceBreakCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceBreakCollection\",\"collection\":\"attendancebreaks\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"attendance_breaks\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AttendanceBreak\",\"exportName\":\"AttendanceBreakCollection\",\"collectionExportName\":\"AttendanceBreakCollectionCollection\",\"schema\":{\"tableName\":\"attendance_breaks\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_breaks\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"punch_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"paid\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"punch_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"attendance_punches\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"paid\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_breaks_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_breaks_open_punch_key\",\"columns\":[\"tenant_id\",\"punch_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_breaks_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_breaks_punch_id_idx\",\"columns\":[\"punch_id\"]}],\"version\":\"00cb739e\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceReplayCollection\":{\"name\":\"attendancereplaycollection\",\"className\":\"AttendanceReplayCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceReplayCollection\",\"collection\":\"attendancereplays\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"attendance_replays\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AttendanceReplay\",\"exportName\":\"AttendanceReplayCollection\",\"collectionExportName\":\"AttendanceReplayCollectionCollection\",\"schema\":{\"tableName\":\"attendance_replays\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_replays\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"replay_key\\\" TEXT NOT NULL UNIQUE,\\n \\\"content\\\" TEXT,\\n \\\"outcome\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"replay_key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"content\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"outcome\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_replays_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_replays_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"f051b7b6\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:ServiceChargeSnapshot\":{\"name\":\"servicechargesnapshot\",\"className\":\"ServiceChargeSnapshot\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceChargeSnapshot\",\"collection\":\"servicechargesnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"timeEntryId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ServiceTimeEntry\",\"_meta\":{\"required\":true}},\"amount\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"currency\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"pricingVersion\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"strategy\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rateSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"sourceChargeRef\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"createdAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_charge_snapshots\",\"previousQualifiedNames\":[\"@happyvertical/smrt-projects:ServiceChargeSnapshot\"],\"conflictColumns\":[\"time_entry_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ServiceChargeSnapshot\",\"collectionExportName\":\"ServiceChargeSnapshotCollection\",\"validationRules\":[{\"field\":\"timeEntryId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"service_charge_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_charge_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"pricing_version\\\" TEXT,\\n \\\"strategy\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT,\\n \\\"source_charge_ref\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"pricing_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"strategy\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_charge_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_charge_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_charge_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_charge_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"1393a1e2\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshot\":{\"name\":\"servicecompensationsnapshot\",\"className\":\"ServiceCompensationSnapshot\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshot\",\"collection\":\"servicecompensationsnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"timeEntryId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ServiceTimeEntry\",\"_meta\":{\"required\":true}},\"amount\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"currency\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"termsVersion\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rateSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"createdAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_compensation_snapshots\",\"previousQualifiedNames\":[\"@happyvertical/smrt-projects:ServiceCompensationSnapshot\"],\"conflictColumns\":[\"time_entry_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ServiceCompensationSnapshot\",\"collectionExportName\":\"ServiceCompensationSnapshotCollection\",\"validationRules\":[{\"field\":\"timeEntryId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"service_compensation_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_compensation_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"terms_version\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"terms_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_compensation_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_compensation_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_compensation_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cd8670e5\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceChargeSnapshotCollection\":{\"name\":\"servicechargesnapshotcollection\",\"className\":\"ServiceChargeSnapshotCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceChargeSnapshotCollection\",\"collection\":\"servicechargesnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"service_charge_snapshots\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ServiceChargeSnapshot\",\"exportName\":\"ServiceChargeSnapshotCollection\",\"collectionExportName\":\"ServiceChargeSnapshotCollectionCollection\",\"schema\":{\"tableName\":\"service_charge_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_charge_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"pricing_version\\\" TEXT,\\n \\\"strategy\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT,\\n \\\"source_charge_ref\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"pricing_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"strategy\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_charge_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_charge_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_charge_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_charge_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"1393a1e2\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshotCollection\":{\"name\":\"servicecompensationsnapshotcollection\",\"className\":\"ServiceCompensationSnapshotCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshotCollection\",\"collection\":\"servicecompensationsnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"service_compensation_snapshots\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ServiceCompensationSnapshot\",\"exportName\":\"ServiceCompensationSnapshotCollection\",\"collectionExportName\":\"ServiceCompensationSnapshotCollectionCollection\",\"schema\":{\"tableName\":\"service_compensation_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_compensation_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"terms_version\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"terms_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_compensation_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_compensation_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_compensation_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cd8670e5\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceTimeEntry\":{\"name\":\"servicetimeentry\",\"className\":\"ServiceTimeEntry\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceTimeEntry\",\"collection\":\"servicetimeentries\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-time-entry.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"workRefType\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"workRefId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"participantKind\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"participantProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"agentRef\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"source\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"description\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"startedAt\":{\"type\":\"datetime\",\"required\":false},\"endedAt\":{\"type\":\"datetime\",\"required\":false},\"durationSeconds\":{\"type\":\"integer\",\"required\":false,\"_meta\":{\"nullable\":true}},\"evidence\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"submittedAt\":{\"type\":\"datetime\",\"required\":false},\"submittedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"approvedAt\":{\"type\":\"datetime\",\"required\":false},\"approvedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"approvalPath\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rejectedAt\":{\"type\":\"datetime\",\"required\":false},\"rejectedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"rejectionReason\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"correctionOfId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ServiceTimeEntry\"},\"metadata\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"getEvidence\":{\"name\":\"getEvidence\",\"async\":false,\"parameters\":[],\"returnType\":\"ServiceEvidence[]\",\"isStatic\":false,\"isPublic\":true},\"setEvidence\":{\"name\":\"setEvidence\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"ServiceEvidence[]\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"durationHoursExact\":{\"name\":\"durationHoursExact\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"durationHours\":{\"name\":\"durationHours\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true},\"requireDurationSeconds\":{\"name\":\"requireDurationSeconds\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true},\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_time_entries\",\"previousQualifiedNames\":[\"@happyvertical/smrt-projects:ServiceTimeEntry\"],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ServiceTimeEntry\",\"collectionExportName\":\"ServiceTimeEntryCollection\",\"schema\":{\"tableName\":\"service_time_entries\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_time_entries\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"work_ref_type\\\" TEXT,\\n \\\"work_ref_id\\\" TEXT,\\n \\\"participant_kind\\\" TEXT,\\n \\\"participant_profile_id\\\" UUID,\\n \\\"agent_ref\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER,\\n \\\"evidence\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"submitted_at\\\" TIMESTAMP,\\n \\\"submitted_by_profile_id\\\" UUID,\\n \\\"approved_at\\\" TIMESTAMP,\\n \\\"approved_by_profile_id\\\" UUID,\\n \\\"approval_path\\\" TEXT,\\n \\\"rejected_at\\\" TIMESTAMP,\\n \\\"rejected_by_profile_id\\\" UUID,\\n \\\"rejection_reason\\\" TEXT,\\n \\\"correction_of_id\\\" UUID,\\n \\\"metadata\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"work_ref_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"work_ref_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_kind\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"agent_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false},\"evidence\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"submitted_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"submitted_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approved_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"approved_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approval_path\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rejected_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"rejected_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"rejection_reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"correction_of_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_time_entries_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"service_time_entries_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"service_time_entries_participant_profile_id_idx\",\"columns\":[\"participant_profile_id\"]},{\"name\":\"service_time_entries_submitted_by_profile_id_idx\",\"columns\":[\"submitted_by_profile_id\"]},{\"name\":\"service_time_entries_approved_by_profile_id_idx\",\"columns\":[\"approved_by_profile_id\"]},{\"name\":\"service_time_entries_rejected_by_profile_id_idx\",\"columns\":[\"rejected_by_profile_id\"]},{\"name\":\"service_time_entries_correction_of_id_idx\",\"columns\":[\"correction_of_id\"]}],\"version\":\"05578ed7\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceTimeEntryCollection\":{\"name\":\"servicetimeentrycollection\",\"className\":\"ServiceTimeEntryCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceTimeEntryCollection\",\"collection\":\"servicetimeentries\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-time-entry.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{\"forWork\":{\"name\":\"forWork\",\"async\":true,\"parameters\":[{\"name\":\"workRefType\",\"type\":\"string\",\"optional\":false},{\"name\":\"workRefId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ServiceTimeEntry[]>\",\"isStatic\":false,\"isPublic\":true},\"pendingApproval\":{\"name\":\"pendingApproval\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ServiceTimeEntry[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_time_entries\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ServiceTimeEntry\",\"exportName\":\"ServiceTimeEntryCollection\",\"collectionExportName\":\"ServiceTimeEntryCollectionCollection\",\"schema\":{\"tableName\":\"service_time_entries\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_time_entries\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"work_ref_type\\\" TEXT,\\n \\\"work_ref_id\\\" TEXT,\\n \\\"participant_kind\\\" TEXT,\\n \\\"participant_profile_id\\\" UUID,\\n \\\"agent_ref\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER,\\n \\\"evidence\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"submitted_at\\\" TIMESTAMP,\\n \\\"submitted_by_profile_id\\\" UUID,\\n \\\"approved_at\\\" TIMESTAMP,\\n \\\"approved_by_profile_id\\\" UUID,\\n \\\"approval_path\\\" TEXT,\\n \\\"rejected_at\\\" TIMESTAMP,\\n \\\"rejected_by_profile_id\\\" UUID,\\n \\\"rejection_reason\\\" TEXT,\\n \\\"correction_of_id\\\" UUID,\\n \\\"metadata\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"work_ref_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"work_ref_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_kind\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"agent_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false},\"evidence\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"submitted_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"submitted_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approved_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"approved_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approval_path\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rejected_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"rejected_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"rejection_reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"correction_of_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_time_entries_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"service_time_entries_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"service_time_entries_participant_profile_id_idx\",\"columns\":[\"participant_profile_id\"]},{\"name\":\"service_time_entries_submitted_by_profile_id_idx\",\"columns\":[\"submitted_by_profile_id\"]},{\"name\":\"service_time_entries_approved_by_profile_id_idx\",\"columns\":[\"approved_by_profile_id\"]},{\"name\":\"service_time_entries_rejected_by_profile_id_idx\",\"columns\":[\"rejected_by_profile_id\"]},{\"name\":\"service_time_entries_correction_of_id_idx\",\"columns\":[\"correction_of_id\"]}],\"version\":\"05578ed7\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:PeriodTimecard\":{\"name\":\"periodtimecard\",\"className\":\"PeriodTimecard\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:PeriodTimecard\",\"collection\":\"periodtimecards\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"startsAt\":{\"type\":\"datetime\",\"required\":false},\"endsAt\":{\"type\":\"datetime\",\"required\":false},\"timezone\":{\"type\":\"text\",\"required\":false},\"rulesVersion\":{\"type\":\"text\",\"required\":false},\"rulesSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"sourceSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"regularSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"overtimeSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"totalSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"confirmedAt\":{\"type\":\"datetime\",\"required\":false},\"confirmedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true,\"onDelete\":\"RESTRICT\"}}},\"methods\":{\"getSources\":{\"name\":\"getSources\",\"async\":false,\"parameters\":[],\"returnType\":\"TimecardSource[]\",\"isStatic\":false,\"isPublic\":true},\"getRules\":{\"name\":\"getRules\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"period_timecards\",\"sensitive\":true,\"api\":{\"include\":[]},\"cli\":{\"include\":[]},\"mcp\":{\"include\":[]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"PeriodTimecard\",\"collectionExportName\":\"PeriodTimecardCollection\",\"validationRules\":[{\"field\":\"regularSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"overtimeSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"totalSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"period_timecards\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"period_timecards\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"starts_at\\\" TIMESTAMP,\\n \\\"ends_at\\\" TIMESTAMP,\\n \\\"timezone\\\" TEXT,\\n \\\"rules_version\\\" TEXT,\\n \\\"rules_snapshot\\\" TEXT,\\n \\\"source_snapshot\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"total_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"status\\\" TEXT,\\n \\\"confirmed_at\\\" TIMESTAMP,\\n \\\"confirmed_by_profile_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"starts_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ends_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"timezone\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"total_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"confirmed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"confirmed_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"period_timecards_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"period_timecards_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"period_timecards_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"period_timecards_confirmed_by_profile_id_idx\",\"columns\":[\"confirmed_by_profile_id\"]}],\"version\":\"8153dc2a\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"},\"@happyvertical/smrt-timesheets:TimecardAdjustment\":{\"name\":\"timecardadjustment\",\"className\":\"TimecardAdjustment\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:TimecardAdjustment\",\"collection\":\"timecardadjustments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"timecardId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"PeriodTimecard\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"actorProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"operationId\":{\"type\":\"text\",\"required\":false},\"regularSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"overtimeSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"reason\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"timecard_adjustments\",\"sensitive\":true,\"api\":{\"include\":[]},\"cli\":{\"include\":[]},\"mcp\":{\"include\":[]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"TimecardAdjustment\",\"collectionExportName\":\"TimecardAdjustmentCollection\",\"validationRules\":[{\"field\":\"regularSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"overtimeSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"timecard_adjustments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"timecard_adjustments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"timecard_id\\\" UUID,\\n \\\"profile_id\\\" UUID,\\n \\\"actor_profile_id\\\" UUID,\\n \\\"operation_id\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"reason\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"timecard_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"period_timecards\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"actor_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"operation_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"timecard_adjustments_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"timecard_adjustments_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"timecard_adjustments_timecard_id_idx\",\"columns\":[\"timecard_id\"]},{\"name\":\"timecard_adjustments_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"timecard_adjustments_actor_profile_id_idx\",\"columns\":[\"actor_profile_id\"]}],\"version\":\"582afe16\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"},\"@happyvertical/smrt-timesheets:PeriodTimecardCollection\":{\"name\":\"periodtimecardcollection\",\"className\":\"PeriodTimecardCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:PeriodTimecardCollection\",\"collection\":\"periodtimecards\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"period_timecards\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"PeriodTimecard\",\"exportName\":\"PeriodTimecardCollection\",\"collectionExportName\":\"PeriodTimecardCollectionCollection\",\"schema\":{\"tableName\":\"period_timecards\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"period_timecards\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"starts_at\\\" TIMESTAMP,\\n \\\"ends_at\\\" TIMESTAMP,\\n \\\"timezone\\\" TEXT,\\n \\\"rules_version\\\" TEXT,\\n \\\"rules_snapshot\\\" TEXT,\\n \\\"source_snapshot\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"total_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"status\\\" TEXT,\\n \\\"confirmed_at\\\" TIMESTAMP,\\n \\\"confirmed_by_profile_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"starts_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ends_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"timezone\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"total_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"confirmed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"confirmed_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"period_timecards_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"period_timecards_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"period_timecards_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"period_timecards_confirmed_by_profile_id_idx\",\"columns\":[\"confirmed_by_profile_id\"]}],\"version\":\"8153dc2a\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"},\"@happyvertical/smrt-timesheets:TimecardAdjustmentCollection\":{\"name\":\"timecardadjustmentcollection\",\"className\":\"TimecardAdjustmentCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:TimecardAdjustmentCollection\",\"collection\":\"timecardadjustments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"timecard_adjustments\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"TimecardAdjustment\",\"exportName\":\"TimecardAdjustmentCollection\",\"collectionExportName\":\"TimecardAdjustmentCollectionCollection\",\"schema\":{\"tableName\":\"timecard_adjustments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"timecard_adjustments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"timecard_id\\\" UUID,\\n \\\"profile_id\\\" UUID,\\n \\\"actor_profile_id\\\" UUID,\\n \\\"operation_id\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"reason\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"timecard_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"period_timecards\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"actor_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"operation_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"timecard_adjustments_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"timecard_adjustments_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"timecard_adjustments_timecard_id_idx\",\"columns\":[\"timecard_id\"]},{\"name\":\"timecard_adjustments_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"timecard_adjustments_actor_profile_id_idx\",\"columns\":[\"actor_profile_id\"]}],\"version\":\"582afe16\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-tenancy\"]}"));
5
+ ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-timesheets\",\"packageVersion\":\"0.54.0\",\"objects\":{\"@happyvertical/smrt-timesheets:AttendancePunch\":{\"name\":\"attendancepunch\",\"className\":\"AttendancePunch\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendancePunch\",\"collection\":\"attendancepunches\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\"},\"startedAt\":{\"type\":\"datetime\",\"required\":false},\"endedAt\":{\"type\":\"datetime\",\"required\":false},\"durationSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"unpaidBreakSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"reviewRequired\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"recordedOffline\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"serviceTimeEntryId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ServiceTimeEntry\",\"_meta\":{\"nullable\":true}},\"openSlot\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"attendance_punches\",\"indexes\":[{\"name\":\"attendance_punches_open_owner_key\",\"columns\":[\"tenantId\",\"profileId\",\"openSlot\"],\"unique\":true}],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"AttendancePunch\",\"collectionExportName\":\"AttendancePunchCollection\",\"validationRules\":[{\"field\":\"durationSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"unpaidBreakSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"reviewRequired\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"recordedOffline\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"openSlot\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"attendance_punches\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_punches\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"unpaid_break_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"review_required\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"recorded_offline\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"service_time_entry_id\\\" UUID,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"unpaid_break_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"review_required\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"recorded_offline\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"service_time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_punches_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_punches_open_owner_key\",\"columns\":[\"tenant_id\",\"profile_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_punches_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_punches_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"attendance_punches_service_time_entry_id_idx\",\"columns\":[\"service_time_entry_id\"]}],\"version\":\"eeca63b1\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceBreak\":{\"name\":\"attendancebreak\",\"className\":\"AttendanceBreak\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceBreak\",\"collection\":\"attendancebreaks\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"punchId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"AttendancePunch\"},\"startedAt\":{\"type\":\"datetime\",\"required\":false},\"endedAt\":{\"type\":\"datetime\",\"required\":false},\"paid\":{\"type\":\"boolean\",\"required\":true,\"default\":false},\"openSlot\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"attendance_breaks\",\"indexes\":[{\"name\":\"attendance_breaks_open_punch_key\",\"columns\":[\"tenantId\",\"punchId\",\"openSlot\"],\"unique\":true}],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"AttendanceBreak\",\"collectionExportName\":\"AttendanceBreakCollection\",\"validationRules\":[{\"field\":\"paid\",\"rule\":\"required\",\"fieldType\":\"boolean\"},{\"field\":\"openSlot\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"attendance_breaks\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_breaks\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"punch_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"paid\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"punch_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"attendance_punches\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"paid\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_breaks_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_breaks_open_punch_key\",\"columns\":[\"tenant_id\",\"punch_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_breaks_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_breaks_punch_id_idx\",\"columns\":[\"punch_id\"]}],\"version\":\"00cb739e\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceReplay\":{\"name\":\"attendancereplay\",\"className\":\"AttendanceReplay\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceReplay\",\"collection\":\"attendancereplays\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"replayKey\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true,\"unique\":true}},\"content\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"outcome\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"getOutcome\":{\"name\":\"getOutcome\",\"async\":false,\"parameters\":[],\"returnType\":\"AttendanceReplayOutcome\",\"isStatic\":false,\"isPublic\":true},\"setOutcome\":{\"name\":\"setOutcome\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"AttendanceReplayOutcome\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"attendance_replays\",\"sensitive\":true,\"api\":{\"include\":[]},\"cli\":{\"include\":[]},\"mcp\":{\"include\":[]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"AttendanceReplay\",\"collectionExportName\":\"AttendanceReplayCollection\",\"validationRules\":[{\"field\":\"replayKey\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"attendance_replays\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_replays\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"replay_key\\\" TEXT NOT NULL UNIQUE,\\n \\\"content\\\" TEXT,\\n \\\"outcome\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"replay_key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"content\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"outcome\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_replays_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_replays_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"f051b7b6\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendancePunchCollection\":{\"name\":\"attendancepunchcollection\",\"className\":\"AttendancePunchCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendancePunchCollection\",\"collection\":\"attendancepunches\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"attendance_punches\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AttendancePunch\",\"exportName\":\"AttendancePunchCollection\",\"collectionExportName\":\"AttendancePunchCollectionCollection\",\"schema\":{\"tableName\":\"attendance_punches\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_punches\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"unpaid_break_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"review_required\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"recorded_offline\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"service_time_entry_id\\\" UUID,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"unpaid_break_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"review_required\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"recorded_offline\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"service_time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_punches_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_punches_open_owner_key\",\"columns\":[\"tenant_id\",\"profile_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_punches_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_punches_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"attendance_punches_service_time_entry_id_idx\",\"columns\":[\"service_time_entry_id\"]}],\"version\":\"eeca63b1\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceBreakCollection\":{\"name\":\"attendancebreakcollection\",\"className\":\"AttendanceBreakCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceBreakCollection\",\"collection\":\"attendancebreaks\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"attendance_breaks\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AttendanceBreak\",\"exportName\":\"AttendanceBreakCollection\",\"collectionExportName\":\"AttendanceBreakCollectionCollection\",\"schema\":{\"tableName\":\"attendance_breaks\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_breaks\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"punch_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"paid\\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\\"open_slot\\\" TEXT NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"punch_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"attendance_punches\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"paid\":{\"type\":\"BOOLEAN\",\"notNull\":true,\"unique\":false,\"default\":false},\"open_slot\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_breaks_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_breaks_open_punch_key\",\"columns\":[\"tenant_id\",\"punch_id\",\"open_slot\"],\"unique\":true},{\"name\":\"attendance_breaks_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"attendance_breaks_punch_id_idx\",\"columns\":[\"punch_id\"]}],\"version\":\"00cb739e\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:AttendanceReplayCollection\":{\"name\":\"attendancereplaycollection\",\"className\":\"AttendanceReplayCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:AttendanceReplayCollection\",\"collection\":\"attendancereplays\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"attendance_replays\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AttendanceReplay\",\"exportName\":\"AttendanceReplayCollection\",\"collectionExportName\":\"AttendanceReplayCollectionCollection\",\"schema\":{\"tableName\":\"attendance_replays\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"attendance_replays\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"replay_key\\\" TEXT NOT NULL UNIQUE,\\n \\\"content\\\" TEXT,\\n \\\"outcome\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"replay_key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"content\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"outcome\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"attendance_replays_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"attendance_replays_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"f051b7b6\"},\"importPath\":\"@happyvertical/smrt-timesheets/attendance\"},\"@happyvertical/smrt-timesheets:ServiceChargeSnapshot\":{\"name\":\"servicechargesnapshot\",\"className\":\"ServiceChargeSnapshot\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceChargeSnapshot\",\"collection\":\"servicechargesnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"timeEntryId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ServiceTimeEntry\",\"_meta\":{\"required\":true}},\"amount\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"currency\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"pricingVersion\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"strategy\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rateSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"sourceChargeRef\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"createdAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_charge_snapshots\",\"previousQualifiedNames\":[\"@happyvertical/smrt-projects:ServiceChargeSnapshot\"],\"conflictColumns\":[\"time_entry_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ServiceChargeSnapshot\",\"collectionExportName\":\"ServiceChargeSnapshotCollection\",\"validationRules\":[{\"field\":\"timeEntryId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"service_charge_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_charge_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"pricing_version\\\" TEXT,\\n \\\"strategy\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT,\\n \\\"source_charge_ref\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"pricing_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"strategy\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_charge_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_charge_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_charge_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_charge_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"1393a1e2\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshot\":{\"name\":\"servicecompensationsnapshot\",\"className\":\"ServiceCompensationSnapshot\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshot\",\"collection\":\"servicecompensationsnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"timeEntryId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ServiceTimeEntry\",\"_meta\":{\"required\":true}},\"amount\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"currency\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"termsVersion\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rateSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"createdAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_compensation_snapshots\",\"previousQualifiedNames\":[\"@happyvertical/smrt-projects:ServiceCompensationSnapshot\"],\"conflictColumns\":[\"time_entry_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ServiceCompensationSnapshot\",\"collectionExportName\":\"ServiceCompensationSnapshotCollection\",\"validationRules\":[{\"field\":\"timeEntryId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"service_compensation_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_compensation_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"terms_version\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"terms_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_compensation_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_compensation_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_compensation_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cd8670e5\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceChargeSnapshotCollection\":{\"name\":\"servicechargesnapshotcollection\",\"className\":\"ServiceChargeSnapshotCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceChargeSnapshotCollection\",\"collection\":\"servicechargesnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"service_charge_snapshots\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ServiceChargeSnapshot\",\"exportName\":\"ServiceChargeSnapshotCollection\",\"collectionExportName\":\"ServiceChargeSnapshotCollectionCollection\",\"schema\":{\"tableName\":\"service_charge_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_charge_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"pricing_version\\\" TEXT,\\n \\\"strategy\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT,\\n \\\"source_charge_ref\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"pricing_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"strategy\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_charge_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_charge_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_charge_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_charge_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"1393a1e2\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshotCollection\":{\"name\":\"servicecompensationsnapshotcollection\",\"className\":\"ServiceCompensationSnapshotCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceCompensationSnapshotCollection\",\"collection\":\"servicecompensationsnapshots\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"service_compensation_snapshots\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ServiceCompensationSnapshot\",\"exportName\":\"ServiceCompensationSnapshotCollection\",\"collectionExportName\":\"ServiceCompensationSnapshotCollectionCollection\",\"schema\":{\"tableName\":\"service_compensation_snapshots\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_compensation_snapshots\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"time_entry_id\\\" UUID NOT NULL,\\n \\\"amount\\\" INTEGER DEFAULT 0,\\n \\\"currency\\\" TEXT,\\n \\\"terms_version\\\" TEXT,\\n \\\"rate_snapshot\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"time_entry_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"amount\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"terms_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rate_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_compensation_snapshots_time_entry_id_idx\",\"columns\":[\"time_entry_id\"],\"unique\":true},{\"name\":\"service_compensation_snapshots_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"service_compensation_snapshots_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cd8670e5\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceTimeEntry\":{\"name\":\"servicetimeentry\",\"className\":\"ServiceTimeEntry\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceTimeEntry\",\"collection\":\"servicetimeentries\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-time-entry.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"workRefType\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"workRefId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"participantKind\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"participantProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"agentRef\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"source\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"description\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"startedAt\":{\"type\":\"datetime\",\"required\":false},\"endedAt\":{\"type\":\"datetime\",\"required\":false},\"durationSeconds\":{\"type\":\"integer\",\"required\":false,\"_meta\":{\"nullable\":true}},\"evidence\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"submittedAt\":{\"type\":\"datetime\",\"required\":false},\"submittedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"approvedAt\":{\"type\":\"datetime\",\"required\":false},\"approvedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"approvalPath\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rejectedAt\":{\"type\":\"datetime\",\"required\":false},\"rejectedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"rejectionReason\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"correctionOfId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ServiceTimeEntry\"},\"metadata\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"getEvidence\":{\"name\":\"getEvidence\",\"async\":false,\"parameters\":[],\"returnType\":\"ServiceEvidence[]\",\"isStatic\":false,\"isPublic\":true},\"setEvidence\":{\"name\":\"setEvidence\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"ServiceEvidence[]\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"durationHoursExact\":{\"name\":\"durationHoursExact\",\"async\":false,\"parameters\":[],\"returnType\":\"string | null\",\"isStatic\":false,\"isPublic\":true},\"durationHours\":{\"name\":\"durationHours\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true},\"requireDurationSeconds\":{\"name\":\"requireDurationSeconds\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true},\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_time_entries\",\"previousQualifiedNames\":[\"@happyvertical/smrt-projects:ServiceTimeEntry\"],\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ServiceTimeEntry\",\"collectionExportName\":\"ServiceTimeEntryCollection\",\"schema\":{\"tableName\":\"service_time_entries\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_time_entries\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"work_ref_type\\\" TEXT,\\n \\\"work_ref_id\\\" TEXT,\\n \\\"participant_kind\\\" TEXT,\\n \\\"participant_profile_id\\\" UUID,\\n \\\"agent_ref\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER,\\n \\\"evidence\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"submitted_at\\\" TIMESTAMP,\\n \\\"submitted_by_profile_id\\\" UUID,\\n \\\"approved_at\\\" TIMESTAMP,\\n \\\"approved_by_profile_id\\\" UUID,\\n \\\"approval_path\\\" TEXT,\\n \\\"rejected_at\\\" TIMESTAMP,\\n \\\"rejected_by_profile_id\\\" UUID,\\n \\\"rejection_reason\\\" TEXT,\\n \\\"correction_of_id\\\" UUID,\\n \\\"metadata\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"work_ref_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"work_ref_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_kind\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"agent_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false},\"evidence\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"submitted_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"submitted_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approved_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"approved_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approval_path\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rejected_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"rejected_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"rejection_reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"correction_of_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_time_entries_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"service_time_entries_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"service_time_entries_participant_profile_id_idx\",\"columns\":[\"participant_profile_id\"]},{\"name\":\"service_time_entries_submitted_by_profile_id_idx\",\"columns\":[\"submitted_by_profile_id\"]},{\"name\":\"service_time_entries_approved_by_profile_id_idx\",\"columns\":[\"approved_by_profile_id\"]},{\"name\":\"service_time_entries_rejected_by_profile_id_idx\",\"columns\":[\"rejected_by_profile_id\"]},{\"name\":\"service_time_entries_correction_of_id_idx\",\"columns\":[\"correction_of_id\"]}],\"version\":\"05578ed7\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:ServiceTimeEntryCollection\":{\"name\":\"servicetimeentrycollection\",\"className\":\"ServiceTimeEntryCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:ServiceTimeEntryCollection\",\"collection\":\"servicetimeentries\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-time-entry.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{\"forWork\":{\"name\":\"forWork\",\"async\":true,\"parameters\":[{\"name\":\"workRefType\",\"type\":\"string\",\"optional\":false},{\"name\":\"workRefId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ServiceTimeEntry[]>\",\"isStatic\":false,\"isPublic\":true},\"pendingApproval\":{\"name\":\"pendingApproval\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ServiceTimeEntry[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"service_time_entries\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ServiceTimeEntry\",\"exportName\":\"ServiceTimeEntryCollection\",\"collectionExportName\":\"ServiceTimeEntryCollectionCollection\",\"schema\":{\"tableName\":\"service_time_entries\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"service_time_entries\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"work_ref_type\\\" TEXT,\\n \\\"work_ref_id\\\" TEXT,\\n \\\"participant_kind\\\" TEXT,\\n \\\"participant_profile_id\\\" UUID,\\n \\\"agent_ref\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP,\\n \\\"duration_seconds\\\" INTEGER,\\n \\\"evidence\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"submitted_at\\\" TIMESTAMP,\\n \\\"submitted_by_profile_id\\\" UUID,\\n \\\"approved_at\\\" TIMESTAMP,\\n \\\"approved_by_profile_id\\\" UUID,\\n \\\"approval_path\\\" TEXT,\\n \\\"rejected_at\\\" TIMESTAMP,\\n \\\"rejected_by_profile_id\\\" UUID,\\n \\\"rejection_reason\\\" TEXT,\\n \\\"correction_of_id\\\" UUID,\\n \\\"metadata\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"work_ref_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"work_ref_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_kind\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"participant_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"agent_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"duration_seconds\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false},\"evidence\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"submitted_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"submitted_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approved_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"approved_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"approval_path\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rejected_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"rejected_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"rejection_reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"correction_of_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"service_time_entries\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"service_time_entries_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"service_time_entries_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"service_time_entries_participant_profile_id_idx\",\"columns\":[\"participant_profile_id\"]},{\"name\":\"service_time_entries_submitted_by_profile_id_idx\",\"columns\":[\"submitted_by_profile_id\"]},{\"name\":\"service_time_entries_approved_by_profile_id_idx\",\"columns\":[\"approved_by_profile_id\"]},{\"name\":\"service_time_entries_rejected_by_profile_id_idx\",\"columns\":[\"rejected_by_profile_id\"]},{\"name\":\"service_time_entries_correction_of_id_idx\",\"columns\":[\"correction_of_id\"]}],\"version\":\"05578ed7\"},\"importPath\":\"@happyvertical/smrt-timesheets\"},\"@happyvertical/smrt-timesheets:PeriodTimecard\":{\"name\":\"periodtimecard\",\"className\":\"PeriodTimecard\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:PeriodTimecard\",\"collection\":\"periodtimecards\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"startsAt\":{\"type\":\"datetime\",\"required\":false},\"endsAt\":{\"type\":\"datetime\",\"required\":false},\"timezone\":{\"type\":\"text\",\"required\":false},\"rulesVersion\":{\"type\":\"text\",\"required\":false},\"rulesSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"sourceSnapshot\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"regularSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"overtimeSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"totalSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"confirmedAt\":{\"type\":\"datetime\",\"required\":false},\"confirmedByProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true,\"onDelete\":\"RESTRICT\"}}},\"methods\":{\"getSources\":{\"name\":\"getSources\",\"async\":false,\"parameters\":[],\"returnType\":\"TimecardSource[]\",\"isStatic\":false,\"isPublic\":true},\"getRules\":{\"name\":\"getRules\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"period_timecards\",\"sensitive\":true,\"api\":{\"include\":[]},\"cli\":{\"include\":[]},\"mcp\":{\"include\":[]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"PeriodTimecard\",\"collectionExportName\":\"PeriodTimecardCollection\",\"validationRules\":[{\"field\":\"regularSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"overtimeSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"totalSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"period_timecards\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"period_timecards\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"starts_at\\\" TIMESTAMP,\\n \\\"ends_at\\\" TIMESTAMP,\\n \\\"timezone\\\" TEXT,\\n \\\"rules_version\\\" TEXT,\\n \\\"rules_snapshot\\\" TEXT,\\n \\\"source_snapshot\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"total_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"status\\\" TEXT,\\n \\\"confirmed_at\\\" TIMESTAMP,\\n \\\"confirmed_by_profile_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"starts_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ends_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"timezone\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"total_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"confirmed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"confirmed_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"period_timecards_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"period_timecards_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"period_timecards_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"period_timecards_confirmed_by_profile_id_idx\",\"columns\":[\"confirmed_by_profile_id\"]}],\"version\":\"8153dc2a\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"},\"@happyvertical/smrt-timesheets:TimecardAdjustment\":{\"name\":\"timecardadjustment\",\"className\":\"TimecardAdjustment\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:TimecardAdjustment\",\"collection\":\"timecardadjustments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"timecardId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"PeriodTimecard\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"actorProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"onDelete\":\"RESTRICT\"}},\"operationId\":{\"type\":\"text\",\"required\":false},\"regularSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"overtimeSeconds\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"reason\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"timecard_adjustments\",\"sensitive\":true,\"api\":{\"include\":[]},\"cli\":{\"include\":[]},\"mcp\":{\"include\":[]},\"tenantScoped\":{\"mode\":\"required\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"TimecardAdjustment\",\"collectionExportName\":\"TimecardAdjustmentCollection\",\"validationRules\":[{\"field\":\"regularSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"overtimeSeconds\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"timecard_adjustments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"timecard_adjustments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"timecard_id\\\" UUID,\\n \\\"profile_id\\\" UUID,\\n \\\"actor_profile_id\\\" UUID,\\n \\\"operation_id\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"reason\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"timecard_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"period_timecards\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"actor_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"operation_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"timecard_adjustments_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"timecard_adjustments_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"timecard_adjustments_timecard_id_idx\",\"columns\":[\"timecard_id\"]},{\"name\":\"timecard_adjustments_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"timecard_adjustments_actor_profile_id_idx\",\"columns\":[\"actor_profile_id\"]}],\"version\":\"582afe16\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"},\"@happyvertical/smrt-timesheets:PeriodTimecardCollection\":{\"name\":\"periodtimecardcollection\",\"className\":\"PeriodTimecardCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:PeriodTimecardCollection\",\"collection\":\"periodtimecards\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"period_timecards\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"PeriodTimecard\",\"exportName\":\"PeriodTimecardCollection\",\"collectionExportName\":\"PeriodTimecardCollectionCollection\",\"schema\":{\"tableName\":\"period_timecards\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"period_timecards\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"profile_id\\\" UUID,\\n \\\"starts_at\\\" TIMESTAMP,\\n \\\"ends_at\\\" TIMESTAMP,\\n \\\"timezone\\\" TEXT,\\n \\\"rules_version\\\" TEXT,\\n \\\"rules_snapshot\\\" TEXT,\\n \\\"source_snapshot\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"total_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"status\\\" TEXT,\\n \\\"confirmed_at\\\" TIMESTAMP,\\n \\\"confirmed_by_profile_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"starts_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"ends_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"timezone\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_version\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rules_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source_snapshot\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"total_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"confirmed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"confirmed_by_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"period_timecards_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"period_timecards_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"period_timecards_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"period_timecards_confirmed_by_profile_id_idx\",\"columns\":[\"confirmed_by_profile_id\"]}],\"version\":\"8153dc2a\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"},\"@happyvertical/smrt-timesheets:TimecardAdjustmentCollection\":{\"name\":\"timecardadjustmentcollection\",\"className\":\"TimecardAdjustmentCollection\",\"qualifiedName\":\"@happyvertical/smrt-timesheets:TimecardAdjustmentCollection\",\"collection\":\"timecardadjustments\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts\",\"packageName\":\"@happyvertical/smrt-timesheets\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"timecard_adjustments\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"TimecardAdjustment\",\"exportName\":\"TimecardAdjustmentCollection\",\"collectionExportName\":\"TimecardAdjustmentCollectionCollection\",\"schema\":{\"tableName\":\"timecard_adjustments\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"timecard_adjustments\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"timecard_id\\\" UUID,\\n \\\"profile_id\\\" UUID,\\n \\\"actor_profile_id\\\" UUID,\\n \\\"operation_id\\\" TEXT,\\n \\\"regular_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"overtime_seconds\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"reason\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"timecard_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"period_timecards\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"actor_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"operation_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"regular_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"overtime_seconds\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"timecard_adjustments_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"timecard_adjustments_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"timecard_adjustments_timecard_id_idx\",\"columns\":[\"timecard_id\"]},{\"name\":\"timecard_adjustments_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"timecard_adjustments_actor_profile_id_idx\",\"columns\":[\"actor_profile_id\"]}],\"version\":\"582afe16\"},\"importPath\":\"@happyvertical/smrt-timesheets/rollup\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-tenancy\"]}"));
6
6
  //#endregion
7
7
  //#region src/models/json.ts
8
8
  function parseTimesheetJson(value, fallback) {
@@ -216,4 +216,4 @@ function validateDurationHours(value) {
216
216
  //#endregion
217
217
  export { validateDurationHours as a, ServiceTimeEntryCollection as i, SERVICE_TIME_ENTRY_FROZEN_FIELDS as n, parseTimesheetJson as o, ServiceTimeEntry as r, SERVICE_DURATION_HOURS_EVIDENCE as t };
218
218
 
219
- //# sourceMappingURL=service-time-entry-Bq8C9-2d.js.map
219
+ //# sourceMappingURL=service-time-entry-d-7DR8p_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-time-entry-Bq8C9-2d.js","names":[],"sources":["../../src/__smrt-register__.ts","../../src/models/json.ts","../../src/models/service-time-entry.ts"],"sourcesContent":["/**\n * Self-registers this package's build-time manifest before any @smrt() decorator\n * in the package fires. Fixes issue #1132: in consumer runtimes (tsx, SvelteKit\n * SSR, plain `vite dev`) the decorator's synchronous manifest lookup previously\n * missed because no step populated the global manifest cache — classes got\n * registered with zero fields and `save()` / `toJSON()` silently dropped every\n * declared property.\n *\n * Import this module as the first statement in `src/index.ts` so its top-level\n * side effect runs ahead of any class module's @smrt() decorator.\n *\n * Silent no-op in dev/test, where the vitest plugin already populates manifests\n * via a different path. Only needs to succeed in the published dist output.\n *\n * @see https://github.com/happyvertical/smrt/issues/1132\n */\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n// During library builds, smrtPlugin replaces this entire module with generated\n// code that embeds the scanned manifest inline (#1506/#1507) — published dists\n// never resolve this URL, so downstream bundlers cannot break registration by\n// relocating the compiled module away from dist/manifest.json. The runtime\n// lookup below is the fallback for source-mode runs without that transform.\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","/**\n * Parse a JSON value stored as text, returning `fallback` on malformed input.\n * Stored JSON may predate a schema change, so reads never throw.\n */\nexport function parseTimesheetJson<T>(value: string, fallback: T): T {\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n SERVICE_TIME_ENTRY_STATUS_TRANSITIONS,\n type ServiceEvidence,\n type ServiceParticipantKind,\n type ServiceTimeEntrySource,\n type ServiceTimeEntryStatus,\n} from '../types.js';\nimport { parseTimesheetJson } from './json.js';\n\n/**\n * Fields that may not change once an entry is approved (or corrected). A\n * subtype that adds its own work context extends the list through\n * {@link ServiceTimeEntry.frozenFieldNames}.\n */\nexport const SERVICE_TIME_ENTRY_FROZEN_FIELDS = [\n 'tenantId',\n 'workRefType',\n 'workRefId',\n 'participantKind',\n 'participantProfileId',\n 'agentRef',\n 'source',\n 'description',\n 'startedAt',\n 'endedAt',\n 'durationSeconds',\n 'evidence',\n 'correctionOfId',\n] as const;\n\nfunction toColumn(key: string): string {\n return key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n}\n\nfunction frozenView(\n source: Record<string, unknown>,\n fields: readonly string[],\n): string {\n const result: Record<string, unknown> = {};\n for (const key of fields) {\n let value = source[key] ?? null;\n if ((key === 'startedAt' || key === 'endedAt') && value) {\n const date = value instanceof Date ? value : new Date(String(value));\n value = Number.isNaN(date.getTime()) ? String(value) : date.toISOString();\n }\n if (key === 'durationSeconds' && value !== null) value = Number(value);\n result[key] = value === '' ? null : value;\n }\n return JSON.stringify(result);\n}\n\nconst loadedStatus = new WeakMap<ServiceTimeEntry, ServiceTimeEntryStatus>();\n\n/**\n * A person or agent worked this long on this thing, and someone approved it.\n *\n * The base entry carries a generic work reference (`workRefType` qualified\n * class name + `workRefId`) and no domain-specific foreign key; a domain adds\n * its own context by subclassing over the same `service_time_entries` table\n * (smrt-support's subtype adds `caseId` / `specialistId`). Entries carry no\n * rate: charge and compensation live on the immutable snapshot models.\n *\n * Status moves `draft → submitted → approved | rejected`; an approved entry\n * never changes, and a correction is a new row whose `correctionOfId` points\n * at the entry it corrects, which flips to `corrected`.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'service_time_entries',\n // Moved from smrt-projects in #3288; stored references keep resolving.\n previousQualifiedNames: ['@happyvertical/smrt-projects:ServiceTimeEntry'],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class ServiceTimeEntry extends SmrtObject {\n @tenantId({ nullable: true }) tenantId: string | null = null;\n @field({ type: 'text', nullable: true }) workRefType: string | null = null;\n @field({ type: 'text', nullable: true }) workRefId: string | null = null;\n @field({ type: 'text' }) participantKind: ServiceParticipantKind = 'human';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n participantProfileId: string | null = null;\n @field({ type: 'text' }) agentRef: string = '';\n @field({ type: 'text' }) source: ServiceTimeEntrySource = 'manual';\n @field({ type: 'text' }) description: string = '';\n startedAt: Date | null = null;\n endedAt: Date | null = null;\n /** Integer seconds, or null for an explicit decimal-hours-only source. */\n @field({ type: 'integer', nullable: true })\n durationSeconds: number | null = 0;\n @field({ type: 'text' }) evidence: string = '[]';\n @field({ type: 'text' }) status: ServiceTimeEntryStatus = 'draft';\n submittedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n submittedByProfileId: string | null = null;\n approvedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n approvedByProfileId: string | null = null;\n @field({ type: 'text' }) approvalPath: string = '';\n rejectedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n rejectedByProfileId: string | null = null;\n @field({ type: 'text' }) rejectionReason: string = '';\n @foreignKey('ServiceTimeEntry') correctionOfId: string | null = null;\n @field({ type: 'text' }) metadata: string = '{}';\n\n getEvidence(): ServiceEvidence[] {\n return parseTimesheetJson(this.evidence, []);\n }\n setEvidence(value: ServiceEvidence[]): void {\n this.evidence = JSON.stringify(value ?? []);\n }\n getMetadata(): Record<string, unknown> {\n return parseTimesheetJson(this.metadata, {});\n }\n setMetadata(value: Record<string, unknown>): void {\n this.metadata = JSON.stringify(value ?? {});\n }\n /** Original decimal-hours text, without binary floating-point conversion. */\n durationHoursExact(): string | null {\n const evidence = this.getEvidence();\n const quantities = (Array.isArray(evidence) ? evidence : []).filter(\n (item) => item?.kind === SERVICE_DURATION_HOURS_EVIDENCE,\n );\n if (quantities.length === 0) return null;\n if (quantities.length !== 1)\n throw new Error(\n 'Service time requires exactly one decimal-hours quantity.',\n );\n return validateDurationHours(quantities[0].hours);\n }\n\n /** Numeric convenience for display; use durationHoursExact() for exact terms. */\n durationHours(): number {\n if (this.durationSeconds !== null) return this.durationSeconds / 3600;\n const hours = this.durationHoursExact();\n if (hours === null)\n throw new Error('Service time has no supported duration quantity.');\n return Number(hours);\n }\n\n /** Guard for consumers whose policies require independently supplied seconds. */\n requireDurationSeconds(): number {\n if (this.durationSeconds === null)\n throw new Error(\n 'Decimal-hours-only service time has no measured durationSeconds; use durationHoursExact() with an hours-aware policy.',\n );\n return this.durationSeconds;\n }\n\n /**\n * Fields frozen once the entry is approved. Subtypes that add work context\n * (e.g. a support case) return `[...super.frozenFieldNames(), ...]`.\n */\n protected frozenFieldNames(): readonly string[] {\n return SERVICE_TIME_ENTRY_FROZEN_FIELDS;\n }\n\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved()) loadedStatus.set(this, this.status);\n return this;\n }\n\n override async save(): Promise<this> {\n const hours = this.durationHoursExact();\n if (hours !== null) {\n if (\n this.durationSeconds !== null ||\n this.startedAt ||\n this.endedAt ||\n this.source === 'timer'\n )\n throw new Error(\n 'Decimal-hours-only service time cannot also supply seconds or timestamps.',\n );\n } else if (this.durationSeconds === null) {\n throw new Error(\n 'Null durationSeconds requires explicit decimal-hours evidence.',\n );\n }\n const prior = await this.readPrior();\n if (\n prior &&\n prior.status !== this.status &&\n !SERVICE_TIME_ENTRY_STATUS_TRANSITIONS[prior.status].includes(this.status)\n ) {\n throw new Error(\n `ServiceTimeEntry ${this.id}: illegal status transition '${prior.status}' → '${this.status}'.`,\n );\n }\n if (\n prior &&\n (prior.status === 'approved' || prior.status === 'corrected')\n ) {\n const current = frozenView(\n this as unknown as Record<string, unknown>,\n this.frozenFieldNames(),\n );\n if (current !== prior.frozen) {\n throw new Error(\n 'Approved ServiceTimeEntry evidence is immutable; create a correction instead.',\n );\n }\n }\n const result = (await super.save()) as this;\n loadedStatus.set(this, this.status);\n return result;\n }\n\n private async readPrior(): Promise<{\n status: ServiceTimeEntryStatus;\n frozen: string;\n } | null> {\n if (!this.id) return null;\n const fields = this.frozenFieldNames();\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (!row?.status) return null;\n const values: Record<string, unknown> = {};\n for (const key of fields) {\n values[key] = row[toColumn(key)];\n }\n return {\n status: row.status as ServiceTimeEntryStatus,\n frozen: frozenView(values, fields),\n };\n } catch {\n const status = loadedStatus.get(this);\n return status\n ? {\n status,\n frozen: frozenView(\n this as unknown as Record<string, unknown>,\n fields,\n ),\n }\n : null;\n }\n }\n}\n\n/** Collection over `service_time_entries`. */\nexport class ServiceTimeEntryCollection extends SmrtCollection<ServiceTimeEntry> {\n static readonly _itemClass = ServiceTimeEntry;\n async forWork(\n workRefType: string,\n workRefId: string,\n ): Promise<ServiceTimeEntry[]> {\n return this.list({\n where: { workRefType, workRefId },\n orderBy: 'created_at ASC',\n });\n }\n async pendingApproval(): Promise<ServiceTimeEntry[]> {\n return this.list({\n where: { status: 'submitted' },\n orderBy: 'submitted_at ASC',\n });\n }\n}\n\n/** Reserved evidence kind for a source quantity with no measured elapsed seconds. */\nexport const SERVICE_DURATION_HOURS_EVIDENCE =\n '@happyvertical/smrt-timesheets:duration-hours';\n\n/** Validate without normalizing the original accepted decimal text. */\nexport function validateDurationHours(value: unknown): string {\n if (\n typeof value !== 'string' ||\n !/^\\d+(?:\\.\\d+)?$/.test(value) ||\n !Number.isFinite(Number(value)) ||\n Number(value) <= 0 ||\n Number(value) >= Number.MAX_SAFE_INTEGER\n )\n throw new Error(\n 'Service time durationHours must be positive plain decimal text within the supported numeric range.',\n );\n return value;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"service-time-entry-d-7DR8p_.js","names":[],"sources":["../../src/__smrt-register__.ts","../../src/models/json.ts","../../src/models/service-time-entry.ts"],"sourcesContent":["/**\n * Self-registers this package's build-time manifest before any @smrt() decorator\n * in the package fires. Fixes issue #1132: in consumer runtimes (tsx, SvelteKit\n * SSR, plain `vite dev`) the decorator's synchronous manifest lookup previously\n * missed because no step populated the global manifest cache — classes got\n * registered with zero fields and `save()` / `toJSON()` silently dropped every\n * declared property.\n *\n * Import this module as the first statement in `src/index.ts` so its top-level\n * side effect runs ahead of any class module's @smrt() decorator.\n *\n * Silent no-op in dev/test, where the vitest plugin already populates manifests\n * via a different path. Only needs to succeed in the published dist output.\n *\n * @see https://github.com/happyvertical/smrt/issues/1132\n */\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n// During library builds, smrtPlugin replaces this entire module with generated\n// code that embeds the scanned manifest inline (#1506/#1507) — published dists\n// never resolve this URL, so downstream bundlers cannot break registration by\n// relocating the compiled module away from dist/manifest.json. The runtime\n// lookup below is the fallback for source-mode runs without that transform.\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","/**\n * Parse a JSON value stored as text, returning `fallback` on malformed input.\n * Stored JSON may predate a schema change, so reads never throw.\n */\nexport function parseTimesheetJson<T>(value: string, fallback: T): T {\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n SERVICE_TIME_ENTRY_STATUS_TRANSITIONS,\n type ServiceEvidence,\n type ServiceParticipantKind,\n type ServiceTimeEntrySource,\n type ServiceTimeEntryStatus,\n} from '../types.js';\nimport { parseTimesheetJson } from './json.js';\n\n/**\n * Fields that may not change once an entry is approved (or corrected). A\n * subtype that adds its own work context extends the list through\n * {@link ServiceTimeEntry.frozenFieldNames}.\n */\nexport const SERVICE_TIME_ENTRY_FROZEN_FIELDS = [\n 'tenantId',\n 'workRefType',\n 'workRefId',\n 'participantKind',\n 'participantProfileId',\n 'agentRef',\n 'source',\n 'description',\n 'startedAt',\n 'endedAt',\n 'durationSeconds',\n 'evidence',\n 'correctionOfId',\n] as const;\n\nfunction toColumn(key: string): string {\n return key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n}\n\nfunction frozenView(\n source: Record<string, unknown>,\n fields: readonly string[],\n): string {\n const result: Record<string, unknown> = {};\n for (const key of fields) {\n let value = source[key] ?? null;\n if ((key === 'startedAt' || key === 'endedAt') && value) {\n const date = value instanceof Date ? value : new Date(String(value));\n value = Number.isNaN(date.getTime()) ? String(value) : date.toISOString();\n }\n if (key === 'durationSeconds' && value !== null) value = Number(value);\n result[key] = value === '' ? null : value;\n }\n return JSON.stringify(result);\n}\n\nconst loadedStatus = new WeakMap<ServiceTimeEntry, ServiceTimeEntryStatus>();\n\n/**\n * A person or agent worked this long on this thing, and someone approved it.\n *\n * The base entry carries a generic work reference (`workRefType` qualified\n * class name + `workRefId`) and no domain-specific foreign key; a domain adds\n * its own context by subclassing over the same `service_time_entries` table\n * (smrt-support's subtype adds `caseId` / `specialistId`). Entries carry no\n * rate: charge and compensation live on the immutable snapshot models.\n *\n * Status moves `draft → submitted → approved | rejected`; an approved entry\n * never changes, and a correction is a new row whose `correctionOfId` points\n * at the entry it corrects, which flips to `corrected`.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'service_time_entries',\n // Moved from smrt-projects in #3288; stored references keep resolving.\n previousQualifiedNames: ['@happyvertical/smrt-projects:ServiceTimeEntry'],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class ServiceTimeEntry extends SmrtObject {\n @tenantId({ nullable: true }) tenantId: string | null = null;\n @field({ type: 'text', nullable: true }) workRefType: string | null = null;\n @field({ type: 'text', nullable: true }) workRefId: string | null = null;\n @field({ type: 'text' }) participantKind: ServiceParticipantKind = 'human';\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n participantProfileId: string | null = null;\n @field({ type: 'text' }) agentRef: string = '';\n @field({ type: 'text' }) source: ServiceTimeEntrySource = 'manual';\n @field({ type: 'text' }) description: string = '';\n startedAt: Date | null = null;\n endedAt: Date | null = null;\n /** Integer seconds, or null for an explicit decimal-hours-only source. */\n @field({ type: 'integer', nullable: true })\n durationSeconds: number | null = 0;\n @field({ type: 'text' }) evidence: string = '[]';\n @field({ type: 'text' }) status: ServiceTimeEntryStatus = 'draft';\n submittedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n submittedByProfileId: string | null = null;\n approvedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n approvedByProfileId: string | null = null;\n @field({ type: 'text' }) approvalPath: string = '';\n rejectedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n rejectedByProfileId: string | null = null;\n @field({ type: 'text' }) rejectionReason: string = '';\n @foreignKey('ServiceTimeEntry') correctionOfId: string | null = null;\n @field({ type: 'text' }) metadata: string = '{}';\n\n getEvidence(): ServiceEvidence[] {\n return parseTimesheetJson(this.evidence, []);\n }\n setEvidence(value: ServiceEvidence[]): void {\n this.evidence = JSON.stringify(value ?? []);\n }\n getMetadata(): Record<string, unknown> {\n return parseTimesheetJson(this.metadata, {});\n }\n setMetadata(value: Record<string, unknown>): void {\n this.metadata = JSON.stringify(value ?? {});\n }\n /** Original decimal-hours text, without binary floating-point conversion. */\n durationHoursExact(): string | null {\n const evidence = this.getEvidence();\n const quantities = (Array.isArray(evidence) ? evidence : []).filter(\n (item) => item?.kind === SERVICE_DURATION_HOURS_EVIDENCE,\n );\n if (quantities.length === 0) return null;\n if (quantities.length !== 1)\n throw new Error(\n 'Service time requires exactly one decimal-hours quantity.',\n );\n return validateDurationHours(quantities[0].hours);\n }\n\n /** Numeric convenience for display; use durationHoursExact() for exact terms. */\n durationHours(): number {\n if (this.durationSeconds !== null) return this.durationSeconds / 3600;\n const hours = this.durationHoursExact();\n if (hours === null)\n throw new Error('Service time has no supported duration quantity.');\n return Number(hours);\n }\n\n /** Guard for consumers whose policies require independently supplied seconds. */\n requireDurationSeconds(): number {\n if (this.durationSeconds === null)\n throw new Error(\n 'Decimal-hours-only service time has no measured durationSeconds; use durationHoursExact() with an hours-aware policy.',\n );\n return this.durationSeconds;\n }\n\n /**\n * Fields frozen once the entry is approved. Subtypes that add work context\n * (e.g. a support case) return `[...super.frozenFieldNames(), ...]`.\n */\n protected frozenFieldNames(): readonly string[] {\n return SERVICE_TIME_ENTRY_FROZEN_FIELDS;\n }\n\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved()) loadedStatus.set(this, this.status);\n return this;\n }\n\n override async save(): Promise<this> {\n const hours = this.durationHoursExact();\n if (hours !== null) {\n if (\n this.durationSeconds !== null ||\n this.startedAt ||\n this.endedAt ||\n this.source === 'timer'\n )\n throw new Error(\n 'Decimal-hours-only service time cannot also supply seconds or timestamps.',\n );\n } else if (this.durationSeconds === null) {\n throw new Error(\n 'Null durationSeconds requires explicit decimal-hours evidence.',\n );\n }\n const prior = await this.readPrior();\n if (\n prior &&\n prior.status !== this.status &&\n !SERVICE_TIME_ENTRY_STATUS_TRANSITIONS[prior.status].includes(this.status)\n ) {\n throw new Error(\n `ServiceTimeEntry ${this.id}: illegal status transition '${prior.status}' → '${this.status}'.`,\n );\n }\n if (\n prior &&\n (prior.status === 'approved' || prior.status === 'corrected')\n ) {\n const current = frozenView(\n this as unknown as Record<string, unknown>,\n this.frozenFieldNames(),\n );\n if (current !== prior.frozen) {\n throw new Error(\n 'Approved ServiceTimeEntry evidence is immutable; create a correction instead.',\n );\n }\n }\n const result = (await super.save()) as this;\n loadedStatus.set(this, this.status);\n return result;\n }\n\n private async readPrior(): Promise<{\n status: ServiceTimeEntryStatus;\n frozen: string;\n } | null> {\n if (!this.id) return null;\n const fields = this.frozenFieldNames();\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (!row?.status) return null;\n const values: Record<string, unknown> = {};\n for (const key of fields) {\n values[key] = row[toColumn(key)];\n }\n return {\n status: row.status as ServiceTimeEntryStatus,\n frozen: frozenView(values, fields),\n };\n } catch {\n const status = loadedStatus.get(this);\n return status\n ? {\n status,\n frozen: frozenView(\n this as unknown as Record<string, unknown>,\n fields,\n ),\n }\n : null;\n }\n }\n}\n\n/** Collection over `service_time_entries`. */\nexport class ServiceTimeEntryCollection extends SmrtCollection<ServiceTimeEntry> {\n static readonly _itemClass = ServiceTimeEntry;\n async forWork(\n workRefType: string,\n workRefId: string,\n ): Promise<ServiceTimeEntry[]> {\n return this.list({\n where: { workRefType, workRefId },\n orderBy: 'created_at ASC',\n });\n }\n async pendingApproval(): Promise<ServiceTimeEntry[]> {\n return this.list({\n where: { status: 'submitted' },\n orderBy: 'submitted_at ASC',\n });\n }\n}\n\n/** Reserved evidence kind for a source quantity with no measured elapsed seconds. */\nexport const SERVICE_DURATION_HOURS_EVIDENCE =\n '@happyvertical/smrt-timesheets:duration-hours';\n\n/** Validate without normalizing the original accepted decimal text. */\nexport function validateDurationHours(value: unknown): string {\n if (\n typeof value !== 'string' ||\n !/^\\d+(?:\\.\\d+)?$/.test(value) ||\n !Number.isFinite(Number(value)) ||\n Number(value) <= 0 ||\n Number(value) >= Number.MAX_SAFE_INTEGER\n )\n throw new Error(\n 'Service time durationHours must be positive plain decimal text within the supported numeric range.',\n );\n return value;\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { a as validateDurationHours, i as ServiceTimeEntryCollection, n as SERVICE_TIME_ENTRY_FROZEN_FIELDS, r as ServiceTimeEntry, t as SERVICE_DURATION_HOURS_EVIDENCE } from "./chunks/service-time-entry-Bq8C9-2d.js";
2
- import { a as AttendanceReplay, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, t as AttendanceBreak } from "./chunks/models-DYz8H_CQ.js";
1
+ import { a as validateDurationHours, i as ServiceTimeEntryCollection, n as SERVICE_TIME_ENTRY_FROZEN_FIELDS, r as ServiceTimeEntry, t as SERVICE_DURATION_HOURS_EVIDENCE } from "./chunks/service-time-entry-d-7DR8p_.js";
2
+ import { a as AttendanceReplay, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, t as AttendanceBreak } from "./chunks/models-Cgkkr2v5.js";
3
3
  import { SERVICE_TIME_ENTRY_STATUS_TRANSITIONS } from "./types.js";
4
4
  import { AttendanceConflict, AttendanceService } from "./attendance.js";
5
- import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-fHN5k25K.js";
5
+ import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-CSLT1xrA.js";
6
6
  import { TIMESHEETS_MODULE_META, TIMESHEETS_UI_SLOTS } from "./ui.js";
7
7
  import { SmrtCollection, SmrtObject, ValidationError, field, foreignKey, smrt } from "@happyvertical/smrt-core";
8
8
  import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-timesheets",
5
- "packageVersion": "0.53.5",
5
+ "packageVersion": "0.54.0",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-timesheets:AttendancePunch": {
8
8
  "name": "attendancepunch",
package/dist/rollup.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-fHN5k25K.js";
1
+ import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-CSLT1xrA.js";
2
2
  export { PeriodRollupService, PeriodTimecard, PeriodTimecardCollection, TimecardAdjustment, TimecardAdjustmentCollection };
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-timesheets",
6
- "packageVersion": "0.53.5",
6
+ "packageVersion": "0.54.0",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "7f37884540f9cfdd6564010044224859fbedcfcb02614260ad48efdcf17ff2eb",
11
- "packageJson": "ebf979879f5cbc635ba574e52416232134779f2e89b988cdaafc0d5d9ea7f801",
10
+ "manifest": "0435c4dbbfc064d21325c0972aa5ff0e72b71129fbead37236c180a2e9b87ac1",
11
+ "packageJson": "b895a5fef17ea86f32a4ff35ffa7134ca0db16337e4c9785fd2a7559ced9ced8",
12
12
  "agents": "21421ad5f02335e4c994227122c13b881d10e9f9d55ae09c3ac8ffa4bc2a7e09",
13
13
  "moduleDoc:agents/period-rollup.md": "5fb741659d81dbef2e4850c10c2d65f09e3f5a83e8a88e2e0f19585f25158a6a"
14
14
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-timesheets",
3
- "version": "0.53.5",
3
+ "version": "0.54.0",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Shared time entries for the SMRT framework: who worked how long on what, approval and correction, with immutable charge and compensation snapshots",
6
6
  "type": "module",
@@ -39,10 +39,10 @@
39
39
  }
40
40
  },
41
41
  "dependencies": {
42
- "@happyvertical/smrt-core": "0.53.5",
43
- "@happyvertical/smrt-tenancy": "0.53.5",
44
- "@happyvertical/smrt-types": "0.53.5",
45
- "@happyvertical/smrt-ui": "0.53.5",
42
+ "@happyvertical/smrt-core": "0.54.0",
43
+ "@happyvertical/smrt-tenancy": "0.54.0",
44
+ "@happyvertical/smrt-types": "0.54.0",
45
+ "@happyvertical/smrt-ui": "0.54.0",
46
46
  "@happyvertical/sql": "^0.100.3"
47
47
  },
48
48
  "peerDependencies": {
@@ -54,7 +54,7 @@
54
54
  }
55
55
  },
56
56
  "devDependencies": {
57
- "@happyvertical/smrt-vitest": "0.53.5",
57
+ "@happyvertical/smrt-vitest": "0.54.0",
58
58
  "@sveltejs/package": "^2.5.8",
59
59
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
60
60
  "@types/node": "24.13.6",