@happyvertical/smrt-support 0.39.2

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.
Files changed (96) hide show
  1. package/AGENTS.md +270 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/dist/__smrt-register__.d.ts +2 -0
  5. package/dist/__smrt-register__.d.ts.map +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +4358 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/manifest.json +6770 -0
  11. package/dist/models/index.d.ts +17 -0
  12. package/dist/models/index.d.ts.map +1 -0
  13. package/dist/models/service-time-entry.d.ts +75 -0
  14. package/dist/models/service-time-entry.d.ts.map +1 -0
  15. package/dist/models/support-ai-run.d.ts +45 -0
  16. package/dist/models/support-ai-run.d.ts.map +1 -0
  17. package/dist/models/support-case-event.d.ts +25 -0
  18. package/dist/models/support-case-event.d.ts.map +1 -0
  19. package/dist/models/support-case.d.ts +125 -0
  20. package/dist/models/support-case.d.ts.map +1 -0
  21. package/dist/models/support-channel-binding.d.ts +47 -0
  22. package/dist/models/support-channel-binding.d.ts.map +1 -0
  23. package/dist/models/support-compensation-plan.d.ts +42 -0
  24. package/dist/models/support-compensation-plan.d.ts.map +1 -0
  25. package/dist/models/support-interaction.d.ts +49 -0
  26. package/dist/models/support-interaction.d.ts.map +1 -0
  27. package/dist/models/support-plan.d.ts +92 -0
  28. package/dist/models/support-plan.d.ts.map +1 -0
  29. package/dist/models/support-policy.d.ts +84 -0
  30. package/dist/models/support-policy.d.ts.map +1 -0
  31. package/dist/models/support-service-target.d.ts +90 -0
  32. package/dist/models/support-service-target.d.ts.map +1 -0
  33. package/dist/models/support-settlement.d.ts +58 -0
  34. package/dist/models/support-settlement.d.ts.map +1 -0
  35. package/dist/models/support-specialist.d.ts +71 -0
  36. package/dist/models/support-specialist.d.ts.map +1 -0
  37. package/dist/models/support-work-link.d.ts +31 -0
  38. package/dist/models/support-work-link.d.ts.map +1 -0
  39. package/dist/permissions.d.ts +32 -0
  40. package/dist/permissions.d.ts.map +1 -0
  41. package/dist/services/coverage-calendar.d.ts +53 -0
  42. package/dist/services/coverage-calendar.d.ts.map +1 -0
  43. package/dist/services/human-handoff-service.d.ts +113 -0
  44. package/dist/services/human-handoff-service.d.ts.map +1 -0
  45. package/dist/services/index.d.ts +15 -0
  46. package/dist/services/index.d.ts.map +1 -0
  47. package/dist/services/keyed-mutex.d.ts +22 -0
  48. package/dist/services/keyed-mutex.d.ts.map +1 -0
  49. package/dist/services/service-target-engine.d.ts +133 -0
  50. package/dist/services/service-target-engine.d.ts.map +1 -0
  51. package/dist/services/service-time-entry-service.d.ts +73 -0
  52. package/dist/services/service-time-entry-service.d.ts.map +1 -0
  53. package/dist/services/support-ai-workflow.d.ts +178 -0
  54. package/dist/services/support-ai-workflow.d.ts.map +1 -0
  55. package/dist/services/support-case-service.d.ts +162 -0
  56. package/dist/services/support-case-service.d.ts.map +1 -0
  57. package/dist/services/support-intake-service.d.ts +106 -0
  58. package/dist/services/support-intake-service.d.ts.map +1 -0
  59. package/dist/services/support-plan-admin-service.d.ts +45 -0
  60. package/dist/services/support-plan-admin-service.d.ts.map +1 -0
  61. package/dist/services/support-routing-service.d.ts +117 -0
  62. package/dist/services/support-routing-service.d.ts.map +1 -0
  63. package/dist/services/time-entry-approval-service.d.ts +162 -0
  64. package/dist/services/time-entry-approval-service.d.ts.map +1 -0
  65. package/dist/smrt-knowledge.json +4242 -0
  66. package/dist/svelte/components/CaseDetail.svelte +277 -0
  67. package/dist/svelte/components/CaseDetail.svelte.d.ts +10 -0
  68. package/dist/svelte/components/CaseDetail.svelte.d.ts.map +1 -0
  69. package/dist/svelte/components/CaseQueue.svelte +148 -0
  70. package/dist/svelte/components/CaseQueue.svelte.d.ts +12 -0
  71. package/dist/svelte/components/CaseQueue.svelte.d.ts.map +1 -0
  72. package/dist/svelte/components/RoutingRationale.svelte +131 -0
  73. package/dist/svelte/components/RoutingRationale.svelte.d.ts +11 -0
  74. package/dist/svelte/components/RoutingRationale.svelte.d.ts.map +1 -0
  75. package/dist/svelte/components/TargetList.svelte +127 -0
  76. package/dist/svelte/components/TargetList.svelte.d.ts +9 -0
  77. package/dist/svelte/components/TargetList.svelte.d.ts.map +1 -0
  78. package/dist/svelte/components/TimeEntryApprovalQueue.svelte +226 -0
  79. package/dist/svelte/components/TimeEntryApprovalQueue.svelte.d.ts +11 -0
  80. package/dist/svelte/components/TimeEntryApprovalQueue.svelte.d.ts.map +1 -0
  81. package/dist/svelte/components/__tests__/CaseDetail.test.js +86 -0
  82. package/dist/svelte/components/__tests__/CaseQueue.test.js +67 -0
  83. package/dist/svelte/components/__tests__/RoutingRationale.test.js +69 -0
  84. package/dist/svelte/components/__tests__/TargetList.test.js +84 -0
  85. package/dist/svelte/components/__tests__/TimeEntryApprovalQueue.test.js +105 -0
  86. package/dist/svelte/index.d.ts +25 -0
  87. package/dist/svelte/index.d.ts.map +1 -0
  88. package/dist/svelte/index.js +18 -0
  89. package/dist/svelte/types.d.ts +129 -0
  90. package/dist/svelte/types.d.ts.map +1 -0
  91. package/dist/svelte/types.js +182 -0
  92. package/dist/types.d.ts +130 -0
  93. package/dist/types.d.ts.map +1 -0
  94. package/dist/types.js +109 -0
  95. package/dist/types.js.map +1 -0
  96. package/package.json +86 -0
@@ -0,0 +1,84 @@
1
+ import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
+ /**
3
+ * Conservative defaults applied when no SupportPolicy row matches: the AI
4
+ * acknowledges, classifies, and answers, but never closes a case or executes
5
+ * tools until a policy explicitly enables it. Handoff triggers are always
6
+ * active regardless of policy.
7
+ */
8
+ export declare const DEFAULT_SUPPORT_POLICY: {
9
+ readonly autoAcknowledge: true;
10
+ readonly autoClassify: true;
11
+ readonly autoAnswer: true;
12
+ readonly autoTroubleshoot: false;
13
+ readonly autoResolve: false;
14
+ readonly autoResolveMaxSeverity: "";
15
+ readonly confidenceThreshold: 0.7;
16
+ readonly maxAutoAttempts: 1;
17
+ readonly autoSendEmailReplies: false;
18
+ readonly sensitiveCategories: string[];
19
+ readonly allowedTools: string[];
20
+ };
21
+ export declare class SupportPolicy extends SmrtObject {
22
+ tenantId: string | null;
23
+ /** Policy name, unique per tenant (`conflictColumns`). */
24
+ name: string;
25
+ /** Scope: applies to cases under this plan (null = any plan). */
26
+ planId: string | null;
27
+ /** Scope: applies to cases for this app-defined project (null = any). */
28
+ projectId: string | null;
29
+ enabled: boolean;
30
+ /** Immediately acknowledge new inbound cases. */
31
+ autoAcknowledge: boolean;
32
+ /** Classify severity/category/sensitivity on intake. */
33
+ autoClassify: boolean;
34
+ /** Post an automated answer using scoped knowledge. */
35
+ autoAnswer: boolean;
36
+ /** Run tool-executing troubleshooting (gated OFF by default). */
37
+ autoTroubleshoot: boolean;
38
+ /** Allow the AI to resolve (close out) low-risk cases (OFF by default). */
39
+ autoResolve: boolean;
40
+ /**
41
+ * Highest severity the AI may auto-resolve (e.g. `sev4` = questions only).
42
+ * Empty means "no severity is eligible" even when `autoResolve` is true.
43
+ */
44
+ autoResolveMaxSeverity: string;
45
+ /**
46
+ * Confidence floor for automated answers/resolutions; below it the workflow
47
+ * triggers a `low_confidence` Human Handoff.
48
+ */
49
+ confidenceThreshold: number;
50
+ /** Max automated resolution attempts before a `failed_resolution` handoff. */
51
+ maxAutoAttempts: number;
52
+ /** Whether automated email replies may be sent (vs drafted) — OFF default. */
53
+ autoSendEmailReplies: boolean;
54
+ /**
55
+ * Categories considered sensitive: classification into one of these always
56
+ * triggers a Human Handoff (FR-28b). JSON array of category keys.
57
+ */
58
+ sensitiveCategories: string;
59
+ /** Tool ids the troubleshooting phase may execute. JSON array, fail-closed. */
60
+ allowedTools: string;
61
+ metadata: string;
62
+ getSensitiveCategories(): string[];
63
+ setSensitiveCategories(categories: string[]): void;
64
+ getAllowedTools(): string[];
65
+ setAllowedTools(tools: string[]): void;
66
+ getMetadata(): Record<string, unknown>;
67
+ setMetadata(value: Record<string, unknown>): void;
68
+ /** Specificity rank for resolution: exact scope wins over partial. */
69
+ scopeRank(): number;
70
+ }
71
+ export declare class SupportPolicyCollection extends SmrtCollection<SupportPolicy> {
72
+ static readonly _itemClass: typeof SupportPolicy;
73
+ /**
74
+ * Resolve the effective policy for a case scope, most-specific-wins.
75
+ * Returns `null` when no enabled policy matches (callers then apply
76
+ * {@link DEFAULT_SUPPORT_POLICY}).
77
+ */
78
+ resolveForScope(options: {
79
+ planId?: string | null;
80
+ projectId?: string | null;
81
+ }): Promise<SupportPolicy | null>;
82
+ }
83
+ export default SupportPolicy;
84
+ //# sourceMappingURL=support-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support-policy.d.ts","sourceRoot":"","sources":["../../src/models/support-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAGL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAIlC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;kCAUN,MAAM,EAAE;2BACf,MAAM,EAAE;CACpB,CAAC;AAEX,qBAQa,aAAc,SAAQ,UAAU;IAE3C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAM;IAElB,iEAAiE;IAEjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE7B,yEAAyE;IAEzE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGhC,OAAO,EAAE,OAAO,CAAQ;IAExB,iDAAiD;IAEjD,eAAe,EAAE,OAAO,CAAQ;IAEhC,wDAAwD;IAExD,YAAY,EAAE,OAAO,CAAQ;IAE7B,uDAAuD;IAEvD,UAAU,EAAE,OAAO,CAAQ;IAE3B,iEAAiE;IAEjE,gBAAgB,EAAE,OAAO,CAAS;IAElC,2EAA2E;IAE3E,WAAW,EAAE,OAAO,CAAS;IAE7B;;;OAGG;IAEH,sBAAsB,EAAE,MAAM,CAAM;IAEpC;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAO;IAElC,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAK;IAE5B,8EAA8E;IAE9E,oBAAoB,EAAE,OAAO,CAAS;IAEtC;;;OAGG;IAEH,mBAAmB,EAAE,MAAM,CAAQ;IAEnC,+EAA+E;IAE/E,YAAY,EAAE,MAAM,CAAQ;IAG5B,QAAQ,EAAE,MAAM,CAAQ;IAExB,sBAAsB,IAAI,MAAM,EAAE;IAIlC,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI;IAIlD,eAAe,IAAI,MAAM,EAAE;IAI3B,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAItC,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAItC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIjD,sEAAsE;IACtE,SAAS,IAAI,MAAM;CAMpB;AAED,qBAAa,uBAAwB,SAAQ,cAAc,CAAC,aAAa,CAAC;IACxE,MAAM,CAAC,QAAQ,CAAC,UAAU,uBAAiB;IAE3C;;;;OAIG;IACG,eAAe,CAAC,OAAO,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;CAYlC;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,90 @@
1
+ import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
+ import { ServiceTargetStatus, ServiceTargetType, SupportEscalationReason } from '../types.js';
3
+ /** Outcome of one {@link SupportServiceTarget.checkAndEscalate} delivery. */
4
+ export interface CheckAndEscalateResult {
5
+ outcome: 'breached' | 'escalated' | 'rescheduled' | 'noop' | 'missing';
6
+ }
7
+ export declare class SupportServiceTarget extends SmrtObject {
8
+ tenantId: string | null;
9
+ caseId: string;
10
+ targetType: ServiceTargetType;
11
+ /**
12
+ * Recurrence cycle for repeating clocks (`update` restarts after each
13
+ * update). One-shot clocks stay at cycle 0.
14
+ */
15
+ cycle: number;
16
+ /** Severity key the minutes were derived from (audit). */
17
+ severity: string;
18
+ /** Configured clock length in covered minutes. */
19
+ baseMinutes: number;
20
+ /** When the clock started running. */
21
+ startedAt: Date;
22
+ /** Current deadline, in wall-clock time (recomputed on pause/resume). */
23
+ dueAt: Date;
24
+ status: ServiceTargetStatus;
25
+ /** Set while the clock is paused (plan pause rules). */
26
+ pausedAt: Date | null;
27
+ /** Accumulated paused time, excluded from the clock. */
28
+ pausedTotalSeconds: number;
29
+ satisfiedAt: Date | null;
30
+ breachedAt: Date | null;
31
+ cancelledAt: Date | null;
32
+ /** One-shot `_smrt_jobs` id scheduled for `dueAt` (cancel on satisfy). */
33
+ escalationJobId: string;
34
+ metadata: string;
35
+ getMetadata(): Record<string, unknown>;
36
+ setMetadata(value: Record<string, unknown>): void;
37
+ isRunning(): boolean;
38
+ /**
39
+ * One-shot escalation job entry point, delivered at-least-once by the
40
+ * jobs runner at `dueAt` (and again for delayed policy steps). Reloads its
41
+ * own persisted state first, so stale deliveries are harmless:
42
+ *
43
+ * - not `pending` and no due pending-escalation marker → no-op (already
44
+ * satisfied/cancelled/paused, or an already-breached clock without a due
45
+ * follow-up step);
46
+ * - `pending` with `dueAt` in the future → no-op (the clock was
47
+ * rescheduled after this job was enqueued);
48
+ * - `pending` and overdue → mark breached and escalate through the plan's
49
+ * escalation policy;
50
+ * - `breached` with a due pending-escalation marker → continue with the
51
+ * next policy step.
52
+ *
53
+ * The engine is imported dynamically to avoid a static model → service
54
+ * cycle. `args.at` (ISO string or `Date`) pins "now" for deterministic
55
+ * tests; the runner passes no args, so production uses wall-clock time.
56
+ */
57
+ checkAndEscalate(args?: Record<string, unknown>, _context?: unknown): Promise<CheckAndEscalateResult>;
58
+ }
59
+ export declare class SupportServiceTargetCollection extends SmrtCollection<SupportServiceTarget> {
60
+ static readonly _itemClass: typeof SupportServiceTarget;
61
+ forCase(caseId: string): Promise<SupportServiceTarget[]>;
62
+ /** Active clock of a type on a case (highest cycle wins). */
63
+ activeTarget(caseId: string, targetType: ServiceTargetType): Promise<SupportServiceTarget | null>;
64
+ }
65
+ export declare class SupportEscalation extends SmrtObject {
66
+ tenantId: string | null;
67
+ caseId: string;
68
+ /** Escalation level applied (1-based, follows the plan's policy steps). */
69
+ level: number;
70
+ reason: SupportEscalationReason;
71
+ /** Breached/at-risk target that triggered this, when applicable. */
72
+ targetId: string | null;
73
+ targetType: string;
74
+ /** Escalation action taken: `notify` | `reassign`. */
75
+ action: string;
76
+ fromSpecialistId: string | null;
77
+ toSpecialistId: string | null;
78
+ /** Profiles notified (JSON array of profile ids). */
79
+ notifiedProfileIds: string;
80
+ occurredAt: Date;
81
+ note: string;
82
+ getNotifiedProfileIds(): string[];
83
+ setNotifiedProfileIds(ids: string[]): void;
84
+ }
85
+ export declare class SupportEscalationCollection extends SmrtCollection<SupportEscalation> {
86
+ static readonly _itemClass: typeof SupportEscalation;
87
+ forCase(caseId: string): Promise<SupportEscalation[]>;
88
+ }
89
+ export default SupportServiceTarget;
90
+ //# sourceMappingURL=support-service-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support-service-target.d.ts","sourceRoot":"","sources":["../../src/models/support-service-target.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
+ import { SupportSettlementStatus } from '../types.js';
3
+ export declare class SupportCharge extends SmrtObject {
4
+ tenantId: string | null;
5
+ timeEntryId: string;
6
+ caseId: string | null;
7
+ /** Plan the pricing derived from (null = no plan; zero-amount charge). */
8
+ planId: string | null;
9
+ /** Client charge amount for the billable time. */
10
+ amount: number;
11
+ currency: string;
12
+ /** Seconds priced at the metered rate (after included-time consumption). */
13
+ billableSeconds: number;
14
+ /** Seconds absorbed by the plan's included support time. */
15
+ includedSecondsApplied: number;
16
+ /**
17
+ * JSON snapshot of the pricing terms used: hourly rate, rate source
18
+ * (`overage` | `on_call` | `none`), plan key, included-time state,
19
+ * derivation timestamp. Never rewritten by later plan edits.
20
+ */
21
+ rateSnapshot: string;
22
+ status: SupportSettlementStatus;
23
+ finalizedAt: Date | null;
24
+ metadata: string;
25
+ getRateSnapshot(): Record<string, unknown>;
26
+ setRateSnapshot(value: Record<string, unknown>): void;
27
+ }
28
+ export declare class SupportChargeCollection extends SmrtCollection<SupportCharge> {
29
+ static readonly _itemClass: typeof SupportCharge;
30
+ forTimeEntry(timeEntryId: string): Promise<SupportCharge | null>;
31
+ forCase(caseId: string): Promise<SupportCharge[]>;
32
+ }
33
+ export declare class SupportCompensation extends SmrtObject {
34
+ tenantId: string | null;
35
+ timeEntryId: string;
36
+ specialistId: string | null;
37
+ /** Compensation plan the earning derived from (null = no plan resolved). */
38
+ compensationPlanId: string | null;
39
+ /** Provider earning amount for the payable time. */
40
+ amount: number;
41
+ currency: string;
42
+ /** Seconds compensated. */
43
+ payableSeconds: number;
44
+ /** JSON snapshot of the earning terms used at derivation time. */
45
+ rateSnapshot: string;
46
+ status: SupportSettlementStatus;
47
+ finalizedAt: Date | null;
48
+ metadata: string;
49
+ getRateSnapshot(): Record<string, unknown>;
50
+ setRateSnapshot(value: Record<string, unknown>): void;
51
+ }
52
+ export declare class SupportCompensationCollection extends SmrtCollection<SupportCompensation> {
53
+ static readonly _itemClass: typeof SupportCompensation;
54
+ forTimeEntry(timeEntryId: string): Promise<SupportCompensation | null>;
55
+ forSpecialist(specialistId: string): Promise<SupportCompensation[]>;
56
+ }
57
+ export default SupportCharge;
58
+ //# sourceMappingURL=support-settlement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support-settlement.d.ts","sourceRoot":"","sources":["../../src/models/support-settlement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAGL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAkB,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3E,qBAQa,aAAc,SAAQ,UAAU;IAE3C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAG/B,WAAW,EAAE,MAAM,CAAM;IAGzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE7B,0EAA0E;IAE1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE7B,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAO;IAGrB,QAAQ,EAAE,MAAM,CAAS;IAEzB,4EAA4E;IAC5E,eAAe,EAAE,MAAM,CAAK;IAE5B,4DAA4D;IAC5D,sBAAsB,EAAE,MAAM,CAAK;IAEnC;;;;OAIG;IAEH,YAAY,EAAE,MAAM,CAAQ;IAG5B,MAAM,EAAE,uBAAuB,CAAa;IAE5C,WAAW,EAAE,IAAI,GAAG,IAAI,CAAQ;IAGhC,QAAQ,EAAE,MAAM,CAAQ;IAExB,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI1C,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGtD;AAED,qBAAa,uBAAwB,SAAQ,cAAc,CAAC,aAAa,CAAC;IACxE,MAAM,CAAC,QAAQ,CAAC,UAAU,uBAAiB;IAErC,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKhE,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CAGxD;AAED,qBAQa,mBAAoB,SAAQ,UAAU;IAEjD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAG/B,WAAW,EAAE,MAAM,CAAM;IAGzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEnC,4EAA4E;IAE5E,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEzC,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAO;IAGrB,QAAQ,EAAE,MAAM,CAAS;IAEzB,2BAA2B;IAC3B,cAAc,EAAE,MAAM,CAAK;IAE3B,kEAAkE;IAElE,YAAY,EAAE,MAAM,CAAQ;IAG5B,MAAM,EAAE,uBAAuB,CAAa;IAE5C,WAAW,EAAE,IAAI,GAAG,IAAI,CAAQ;IAGhC,QAAQ,EAAE,MAAM,CAAQ;IAExB,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI1C,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGtD;AAED,qBAAa,6BAA8B,SAAQ,cAAc,CAAC,mBAAmB,CAAC;IACpF,MAAM,CAAC,QAAQ,CAAC,UAAU,6BAAuB;IAE3C,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAKtE,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;CAG1E;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,71 @@
1
+ import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
+ import { SupportAvailabilityKind, SupportQualificationLevel, SupportSpecialistStatus } from '../types.js';
3
+ export declare class SupportSpecialist extends SmrtObject {
4
+ tenantId: string | null;
5
+ /** The Participant (Person profile) this specialist role belongs to. */
6
+ profileId: string;
7
+ /** Display name for queues/routing rationale (denormalized from Profile). */
8
+ displayName: string;
9
+ status: SupportSpecialistStatus;
10
+ /** Languages the specialist supports (JSON array of BCP-47-ish codes). */
11
+ languages: string;
12
+ /** IANA timezone the weekly availability windows are expressed in. */
13
+ timezone: string;
14
+ /** Routing workload cap: open cases beyond this exclude the specialist. */
15
+ maxConcurrentCases: number;
16
+ /** Tie-break priority for on-call ranking (higher = preferred). */
17
+ onCallPriority: number;
18
+ notes: string;
19
+ metadata: string;
20
+ getLanguages(): string[];
21
+ setLanguages(languages: string[]): void;
22
+ getMetadata(): Record<string, unknown>;
23
+ setMetadata(value: Record<string, unknown>): void;
24
+ isActive(): boolean;
25
+ }
26
+ export declare class SupportSpecialistCollection extends SmrtCollection<SupportSpecialist> {
27
+ static readonly _itemClass: typeof SupportSpecialist;
28
+ findActive(): Promise<SupportSpecialist[]>;
29
+ byProfile(profileId: string): Promise<SupportSpecialist | null>;
30
+ }
31
+ export declare class SupportQualification extends SmrtObject {
32
+ tenantId: string | null;
33
+ specialistId: string;
34
+ /** App-defined Project this qualification covers. */
35
+ projectId: string;
36
+ level: SupportQualificationLevel;
37
+ /** Effective-dating: null bounds mean open-ended. */
38
+ effectiveFrom: Date | null;
39
+ effectiveTo: Date | null;
40
+ grantedByProfileId: string | null;
41
+ notes: string;
42
+ /** Whether the qualification is effective at the given instant. */
43
+ isEffectiveAt(at?: Date): boolean;
44
+ }
45
+ export declare class SupportQualificationCollection extends SmrtCollection<SupportQualification> {
46
+ static readonly _itemClass: typeof SupportQualification;
47
+ forSpecialist(specialistId: string): Promise<SupportQualification[]>;
48
+ forProject(projectId: string): Promise<SupportQualification[]>;
49
+ }
50
+ export declare class SupportAvailability extends SmrtObject {
51
+ tenantId: string | null;
52
+ specialistId: string;
53
+ kind: SupportAvailabilityKind;
54
+ /** Weekly windows: 0 = Sunday … 6 = Saturday. Null for span kinds. */
55
+ weekday: number | null;
56
+ /** Weekly windows: minutes from midnight, inclusive start. */
57
+ startMinute: number;
58
+ /** Weekly windows: minutes from midnight, exclusive end. */
59
+ endMinute: number;
60
+ /** Span kinds (`on_call`, `time_off`): absolute start. */
61
+ startsAt: Date | null;
62
+ /** Span kinds (`on_call`, `time_off`): absolute end. */
63
+ endsAt: Date | null;
64
+ notes: string;
65
+ }
66
+ export declare class SupportAvailabilityCollection extends SmrtCollection<SupportAvailability> {
67
+ static readonly _itemClass: typeof SupportAvailability;
68
+ forSpecialist(specialistId: string): Promise<SupportAvailability[]>;
69
+ }
70
+ export default SupportSpecialist;
71
+ //# sourceMappingURL=support-specialist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support-specialist.d.ts","sourceRoot":"","sources":["../../src/models/support-specialist.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
2
+ import { SupportWorkLinkKind } from '../types.js';
3
+ export declare class SupportWorkLink extends SmrtObject {
4
+ tenantId: string | null;
5
+ caseId: string;
6
+ linkKind: SupportWorkLinkKind;
7
+ /**
8
+ * Qualified class of the linked work item, e.g.
9
+ * `@happyvertical/smrt-projects:Issue`.
10
+ */
11
+ targetType: string;
12
+ targetId: string;
13
+ /** Display label for the case timeline (e.g. `repo#123: fix login`). */
14
+ targetLabel: string;
15
+ externalUrl: string;
16
+ /**
17
+ * Status echo reported back from the owning domain (`open`,
18
+ * `in_progress`, `done`, …). Informational only.
19
+ */
20
+ status: string;
21
+ lastStatusAt: Date | null;
22
+ metadata: string;
23
+ getMetadata(): Record<string, unknown>;
24
+ setMetadata(value: Record<string, unknown>): void;
25
+ }
26
+ export declare class SupportWorkLinkCollection extends SmrtCollection<SupportWorkLink> {
27
+ static readonly _itemClass: typeof SupportWorkLink;
28
+ forCase(caseId: string): Promise<SupportWorkLink[]>;
29
+ }
30
+ export default SupportWorkLink;
31
+ //# sourceMappingURL=support-work-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support-work-link.d.ts","sourceRoot":"","sources":["../../src/models/support-work-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAGL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvE,qBAQa,eAAgB,SAAQ,UAAU;IAE7C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAG/B,MAAM,EAAE,MAAM,CAAM;IAGpB,QAAQ,EAAE,mBAAmB,CAAuB;IAEpD;;;OAGG;IAEH,UAAU,EAAE,MAAM,CAAM;IAGxB,QAAQ,EAAE,MAAM,CAAM;IAEtB,wEAAwE;IAExE,WAAW,EAAE,MAAM,CAAM;IAGzB,WAAW,EAAE,MAAM,CAAM;IAEzB;;;OAGG;IAEH,MAAM,EAAE,MAAM,CAAU;IAExB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAQ;IAGjC,QAAQ,EAAE,MAAM,CAAQ;IAExB,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAItC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlD;AAED,qBAAa,yBAA0B,SAAQ,cAAc,CAAC,eAAe,CAAC;IAC5E,MAAM,CAAC,QAAQ,CAAC,UAAU,yBAAmB;IAEvC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAG1D;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { PermissionDefinition } from '@happyvertical/smrt-users';
2
+ /** Authorizes manual case reassignment overriding automatic routing. */
3
+ export declare const REASSIGN_CASE_PERMISSION = "support.reassign-case";
4
+ /** Authorizes operator approval/rejection of Service Time Entries. */
5
+ export declare const APPROVE_TIME_ENTRY_PERMISSION = "support.approve-time-entry";
6
+ /** Authorizes plan administration (support + compensation plans). */
7
+ export declare const MANAGE_PLANS_PERMISSION = "support.manage-plans";
8
+ export declare const SUPPORT_PERMISSION_DEFS: PermissionDefinition[];
9
+ /**
10
+ * An actor whose authority is expressed as held permission slugs. Minimal on
11
+ * purpose — the gate depends on the permission model only (personas idiom).
12
+ */
13
+ export interface SupportPrincipal {
14
+ /** Stable id recorded as the acting reviewer/assigner. */
15
+ readonly id?: string;
16
+ /** Tenant the authority was resolved for (cross-tenant acts are refused). */
17
+ readonly tenantId?: string;
18
+ can(slug: string): boolean;
19
+ }
20
+ /** Build a {@link SupportPrincipal} from explicit granted slugs. */
21
+ export declare function supportPrincipalFromPermissions(permissions: Iterable<string>, options?: {
22
+ id?: string;
23
+ tenantId?: string;
24
+ }): SupportPrincipal;
25
+ /** Register the support permissions (returns an unregister fn for tests). */
26
+ export declare function registerSupportPermissions(): () => void;
27
+ /**
28
+ * Register the support permissions once per process. Called as a package
29
+ * entry side effect so any consumer sees the slugs in the catalog.
30
+ */
31
+ export declare function ensureSupportPermissionsRegistered(): void;
32
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAC;AAEnC,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAEhE,sEAAsE;AACtE,eAAO,MAAM,6BAA6B,+BAA+B,CAAC;AAE1E,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAE9D,eAAO,MAAM,uBAAuB,EAAE,oBAAoB,EAsBzD,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AAED,oEAAoE;AACpE,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC7B,OAAO,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,gBAAgB,CAOlB;AAID,6EAA6E;AAC7E,wBAAgB,0BAA0B,IAAI,MAAM,IAAI,CAEvD;AAED;;;GAGG;AACH,wBAAgB,kCAAkC,IAAI,IAAI,CAMzD"}
@@ -0,0 +1,53 @@
1
+ import { CoverageWindow } from '../types.js';
2
+ /** The coverage terms a Service Target clock runs against. */
3
+ export interface CoverageCalendar {
4
+ /** Weekly coverage windows; empty means 24×7 coverage. */
5
+ windows: CoverageWindow[];
6
+ /** Holiday dates excluded from coverage (`YYYY-MM-DD`). */
7
+ holidays: string[];
8
+ /** IANA timezone the windows and holidays are expressed in. */
9
+ timezone: string;
10
+ }
11
+ /** Wall-clock projection of a UTC instant in a target timezone. */
12
+ export interface ZonedParts {
13
+ /** Calendar year in the target timezone. */
14
+ year: number;
15
+ /** Calendar month in the target timezone (1–12). */
16
+ month: number;
17
+ /** Calendar day of month in the target timezone (1–31). */
18
+ day: number;
19
+ /** 0 = Sunday … 6 = Saturday (matches {@link CoverageWindow} docs). */
20
+ weekday: number;
21
+ /** Minutes from local midnight (0–1439). */
22
+ minuteOfDay: number;
23
+ /** `YYYY-MM-DD` date key in the target timezone (holiday comparisons). */
24
+ dateKey: string;
25
+ }
26
+ /**
27
+ * Hard ceiling on how many calendar days {@link addCoveredMinutes} will walk
28
+ * forward looking for coverage before failing loudly (a plan whose calendar
29
+ * never covers anything would otherwise loop forever).
30
+ */
31
+ export declare const MAX_COVERAGE_SCAN_DAYS = 400;
32
+ /**
33
+ * Project a UTC instant onto a timezone's wall clock via
34
+ * `Intl.DateTimeFormat#formatToParts`. Throws a `RangeError` for an invalid
35
+ * IANA timezone name (surfacing plan misconfiguration immediately).
36
+ */
37
+ export declare function zonedParts(date: Date, timeZone: string): ZonedParts;
38
+ /**
39
+ * Covered minutes between two instants (fractional; `0` when `to <= from`).
40
+ *
41
+ * Walks forward day by day through the calendar timezone, summing the overlap
42
+ * of `[from, to)` with each day's covered spans.
43
+ */
44
+ export declare function coveredMinutesBetween(calendar: CoverageCalendar, from: Date, to: Date): number;
45
+ /**
46
+ * The instant at which `minutes` of covered time have elapsed from `from` —
47
+ * the Service Target due-time computation. Walks forward day by day through
48
+ * coverage windows, skipping holidays; throws a descriptive error after
49
+ * {@link MAX_COVERAGE_SCAN_DAYS} days without accumulating enough coverage
50
+ * (an effectively-empty calendar).
51
+ */
52
+ export declare function addCoveredMinutes(calendar: CoverageCalendar, from: Date, minutes: number): Date;
53
+ //# sourceMappingURL=coverage-calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage-calendar.d.ts","sourceRoot":"","sources":["../../src/services/coverage-calendar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAsC1C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAmBnE;AAiID;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,IAAI,GACP,MAAM,CAgCR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,GACd,IAAI,CAwCN"}
@@ -0,0 +1,113 @@
1
+ import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
+ import { SupportAiRunCollection } from '../models/support-ai-run.js';
3
+ import { SupportCase } from '../models/support-case.js';
4
+ import { HumanHandoffTrigger } from '../types.js';
5
+ import { SupportCaseService } from './support-case-service.js';
6
+ /** One compact timeline entry inside a {@link HandoffContextPackage}. */
7
+ export interface HandoffTimelineItem {
8
+ kind: 'interaction' | 'event';
9
+ /** ISO-8601 timestamp (the package is embedded in a JSON event payload). */
10
+ occurredAt: string;
11
+ actorKind: string;
12
+ summary: string;
13
+ /** Interaction body — the Client's own words travel with the handoff. */
14
+ body?: string;
15
+ }
16
+ /** One compact AI-run entry inside a {@link HandoffContextPackage}. */
17
+ export interface HandoffAiRunSummary {
18
+ phase: string;
19
+ outcome: string;
20
+ confidence: number | null;
21
+ classification: Record<string, unknown>;
22
+ error: string | null;
23
+ }
24
+ /**
25
+ * The lossless context a Human Handoff transfers (FR-28b): the case's current
26
+ * state plus the merged timeline and every prior automated-work audit row.
27
+ * This is what the assigned Support Specialist receives — the Client never
28
+ * repeats themselves.
29
+ */
30
+ export interface HandoffContextPackage {
31
+ caseNumber: string;
32
+ subject: string;
33
+ status: string;
34
+ severity: string;
35
+ category: string;
36
+ clientProfileId: string | null;
37
+ projectId: string | null;
38
+ planId: string | null;
39
+ timeline: HandoffTimelineItem[];
40
+ aiRuns: HandoffAiRunSummary[];
41
+ }
42
+ /**
43
+ * The routing seam (#1929): pick the Support Specialist for a handed-off
44
+ * case. Return `null` to leave the case in the queue for manual assignment.
45
+ */
46
+ export type SpecialistRouter = (supportCase: SupportCase, context: {
47
+ trigger: HumanHandoffTrigger;
48
+ }) => Promise<{
49
+ specialistId: string;
50
+ rationale?: Record<string, unknown>;
51
+ } | null>;
52
+ /** Options for {@link HumanHandoffService.create}. */
53
+ export interface HumanHandoffServiceOptions extends SmrtObjectOptions {
54
+ /** Routing seam; omitted → handed-off cases queue for manual assignment. */
55
+ assignSpecialist?: SpecialistRouter;
56
+ }
57
+ /** Input for one {@link HumanHandoffService.handoff} call. */
58
+ export interface HumanHandoffInput {
59
+ trigger: HumanHandoffTrigger;
60
+ /** Free-form context for the audit event (why the trigger fired). */
61
+ note?: string;
62
+ /** The requesting Client profile, for `client_request` triggers. */
63
+ requestedByProfileId?: string | null;
64
+ }
65
+ /** Result of one {@link HumanHandoffService.handoff} call. */
66
+ export interface HumanHandoffResult {
67
+ supportCase: SupportCase;
68
+ /** True when an earlier handoff was still active (no-repeat guarantee). */
69
+ alreadyActive: boolean;
70
+ }
71
+ /**
72
+ * The Human Handoff engine. Construct with {@link HumanHandoffService.create}.
73
+ */
74
+ export declare class HumanHandoffService {
75
+ readonly caseService: SupportCaseService;
76
+ readonly aiRuns: SupportAiRunCollection;
77
+ private readonly assignSpecialist?;
78
+ protected constructor(deps: {
79
+ caseService: SupportCaseService;
80
+ aiRuns: SupportAiRunCollection;
81
+ assignSpecialist?: SpecialistRouter;
82
+ });
83
+ static create(options: HumanHandoffServiceOptions): Promise<HumanHandoffService>;
84
+ /**
85
+ * Assemble the lossless context package for a case: current state, the
86
+ * merged interaction/event timeline, and every prior AI run (FR-28b).
87
+ */
88
+ buildContextPackage(caseId: string): Promise<HandoffContextPackage>;
89
+ /**
90
+ * Hand the case to a human: enforce the no-repeat guarantee, stamp
91
+ * `metadata.activeHandoff`, record the `handoff` audit event carrying the
92
+ * full context package, then route via the `assignSpecialist` seam (or
93
+ * queue the case as `triaged` when unrouted).
94
+ */
95
+ handoff(caseRef: SupportCase | string, input: HumanHandoffInput): Promise<HumanHandoffResult>;
96
+ /**
97
+ * Clear the active-handoff flag so a later trigger can hand off again.
98
+ * Apps call this when the handoff concludes (assignment accepted or the
99
+ * case resolves); a resolve-then-reopen also invalidates the flag
100
+ * automatically inside {@link handoff}.
101
+ */
102
+ releaseHandoff(caseRef: SupportCase | string): Promise<SupportCase>;
103
+ /**
104
+ * Whether a handoff is still pending on the case. A flag survives only
105
+ * while the case stays open; a resolve-and-reopen since the flag was set
106
+ * makes it stale (the new conversation may hand off afresh).
107
+ */
108
+ private isHandoffActive;
109
+ /** The persisted id of a saved case. */
110
+ private caseIdOf;
111
+ }
112
+ export default HumanHandoffService;
113
+ //# sourceMappingURL=human-handoff-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human-handoff-service.d.ts","sourceRoot":"","sources":["../../src/services/human-handoff-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Service barrel for `@happyvertical/smrt-support`.
3
+ */
4
+ export { addCoveredMinutes, type CoverageCalendar, coveredMinutesBetween, MAX_COVERAGE_SCAN_DAYS, type ZonedParts, zonedParts, } from './coverage-calendar.js';
5
+ export { type HandoffAiRunSummary, type HandoffContextPackage, type HandoffTimelineItem, type HumanHandoffInput, type HumanHandoffResult, HumanHandoffService, type HumanHandoffServiceOptions, type SpecialistRouter, } from './human-handoff-service.js';
6
+ export { KeyedMutex } from './keyed-mutex.js';
7
+ export { DEFAULT_SEVERITY_KEY, ESCALATION_JOB_PRIORITY, type ResolvedTargetPlanTerms, ServiceTargetEngine, type ServiceTargetEngineOptions, SUPPORT_JOB_QUEUE, } from './service-target-engine.js';
8
+ export { type RecordServiceTimeEntryInput, ServiceTimeEntryService, type ServiceTimeEntryServiceOptions, type SubmitServiceTimeEntryInput, } from './service-time-entry-service.js';
9
+ export { createDefaultAiBoundary, createNoopKnowledgeProvider, type KnowledgeSnippet, type SupportAiAnswerResult, type SupportAiBoundary, type SupportAiClassifyResult, SupportAiWorkflow, type SupportAiWorkflowOptions, type SupportHandoffNotice, type SupportKnowledgeProvider, severityRank, } from './support-ai-workflow.js';
10
+ export { type CaseActor, type CaseTimelineItem, type OpenCaseInput, type RecordInteractionInput, SupportCaseService, } from './support-case-service.js';
11
+ export { CHAT_MESSAGE_SOURCE_TYPE, CHAT_ROOM_TARGET_TYPE, EMAIL_ACCOUNT_TARGET_TYPE, EMAIL_SOURCE_TYPE, type InboundChatMessage, type InboundEmail, type IntakeResult, registerSupportIntake, SUPPORT_INTAKE_INTERCEPTOR, type SupportIntakeOptions, SupportIntakeService, } from './support-intake-service.js';
12
+ export { type PlanAdminActor, PlanAdminDeniedError, SupportPlanAdminService, } from './support-plan-admin-service.js';
13
+ export { type AutoAssignResult, type RankedSpecialist, ReassignDeniedError, ROUTING_WEIGHTS, SupportRoutingService, type SupportRoutingServiceOptions, } from './support-routing-service.js';
14
+ export { type ApproveTimeEntryInput, type ApproveTimeEntryResult, type CorrectTimeEntryInput, type CorrectTimeEntryResult, type RejectTimeEntryInput, type ResolvedPlanTerms, TimeEntryApprovalDeniedError, TimeEntryApprovalService, type TimeEntryApprovalServiceOptions, } from './time-entry-approval-service.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,UAAU,EACf,UAAU,GACX,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,GACtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,KAAK,2BAA2B,EAChC,uBAAuB,EACvB,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,GACjC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,oBAAoB,GACrB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,cAAc,EACnB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,4BAA4B,EAC5B,wBAAwB,EACxB,KAAK,+BAA+B,GACrC,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * KeyedMutex — serialize async work per key within one process.
3
+ *
4
+ * Used where a read-then-write decision must not interleave for the same
5
+ * logical resource: intake's create-or-join per conversation key, and
6
+ * included-time consumption per case during time-entry approval. Keys chain
7
+ * promises, so concurrent callers for the same key run strictly in arrival
8
+ * order while different keys stay fully parallel; entries clean up when the
9
+ * last waiter finishes.
10
+ *
11
+ * Scope: in-process only. It covers the deployment shape these paths run in
12
+ * (one app process owns intake interceptors / approval actions); multi-
13
+ * replica deployments serialize at the app layer (sticky routing or a
14
+ * DB-level claim), which composes above these seams.
15
+ */
16
+ export declare class KeyedMutex {
17
+ private readonly tails;
18
+ /** Run `fn` exclusively for `key`, after every earlier holder of it. */
19
+ run<T>(key: string, fn: () => Promise<T>): Promise<T>;
20
+ }
21
+ export default KeyedMutex;
22
+ //# sourceMappingURL=keyed-mutex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyed-mutex.d.ts","sourceRoot":"","sources":["../../src/services/keyed-mutex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAE7D,wEAAwE;IAClE,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAmB5D;AAED,eAAe,UAAU,CAAC"}