web-mojo 2.5.8 → 2.5.10

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 (58) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/admin-models.es.js +1 -1
  3. package/dist/admin.cjs.js +1 -1
  4. package/dist/admin.cjs.js.map +1 -1
  5. package/dist/admin.es.js +1 -1
  6. package/dist/admin.es.js.map +1 -1
  7. package/dist/auth.cjs.js +1 -1
  8. package/dist/auth.es.js +1 -1
  9. package/dist/charts.cjs.js +1 -1
  10. package/dist/charts.es.js +1 -1
  11. package/dist/chunks/{ChatView-C27ckVwL.js → ChatView-CPaBPG5C.js} +2 -2
  12. package/dist/chunks/{ChatView-C27ckVwL.js.map → ChatView-CPaBPG5C.js.map} +1 -1
  13. package/dist/chunks/{ContextMenu-xdLpFeau.js → ContextMenu-Dch7L988.js} +2 -2
  14. package/dist/chunks/{ContextMenu-xdLpFeau.js.map → ContextMenu-Dch7L988.js.map} +1 -1
  15. package/dist/chunks/{DataView-DBQUt_vV.js → DataView-DhhTCP0d.js} +2 -2
  16. package/dist/chunks/{DataView-DBQUt_vV.js.map → DataView-DhhTCP0d.js.map} +1 -1
  17. package/dist/chunks/{FormView-DaZFbDWr.js → FormView-C6XZFZ6s.js} +2 -2
  18. package/dist/chunks/{FormView-DaZFbDWr.js.map → FormView-C6XZFZ6s.js.map} +1 -1
  19. package/dist/chunks/{ListView-C-jiqALE.js → ListView-McEedPG8.js} +2 -2
  20. package/dist/chunks/{ListView-C-jiqALE.js.map → ListView-McEedPG8.js.map} +1 -1
  21. package/dist/chunks/{MetricsCountryMapView-5r0SeCQw.js → MetricsCountryMapView-B9hNrGIG.js} +2 -2
  22. package/dist/chunks/{MetricsCountryMapView-5r0SeCQw.js.map → MetricsCountryMapView-B9hNrGIG.js.map} +1 -1
  23. package/dist/chunks/{Modal-Dgtnpj85.js → Modal-DfAzkbgB.js} +3 -3
  24. package/dist/chunks/{Modal-Dgtnpj85.js.map → Modal-DfAzkbgB.js.map} +1 -1
  25. package/dist/chunks/{Passkeys-B4bndv5b.js → Passkeys-C7YPKCKQ.js} +2 -2
  26. package/dist/chunks/{Passkeys-B4bndv5b.js.map → Passkeys-C7YPKCKQ.js.map} +1 -1
  27. package/dist/chunks/{TokenManager-DR5zQikX.js → TokenManager-CIGfr9LQ.js} +2 -2
  28. package/dist/chunks/{TokenManager-DR5zQikX.js.map → TokenManager-CIGfr9LQ.js.map} +1 -1
  29. package/dist/chunks/{User-DNifTiFu.js → User-DgB81g6W.js} +2 -2
  30. package/dist/chunks/{User-DNifTiFu.js.map → User-DgB81g6W.js.map} +1 -1
  31. package/dist/chunks/{UserProfileView-DugtA_qG.js → UserProfileView-Cn4x_As0.js} +2 -2
  32. package/dist/chunks/{UserProfileView-DugtA_qG.js.map → UserProfileView-Cn4x_As0.js.map} +1 -1
  33. package/dist/chunks/{WebApp-CNhEZYYG.js → WebApp-BLO494WW.js} +2 -2
  34. package/dist/chunks/{WebApp-CNhEZYYG.js.map → WebApp-BLO494WW.js.map} +1 -1
  35. package/dist/chunks/{admin-models-CdOCWMEj.js → admin-models-C8VPjEPG.js} +2 -2
  36. package/dist/chunks/{admin-models-CdOCWMEj.js.map → admin-models-C8VPjEPG.js.map} +1 -1
  37. package/dist/chunks/{exportChart-QDe89jLV.js → exportChart-9xYMybEK.js} +2 -2
  38. package/dist/chunks/{exportChart-QDe89jLV.js.map → exportChart-9xYMybEK.js.map} +1 -1
  39. package/dist/chunks/{index-D-gO-M9M.js → index-D09iCOVq.js} +2 -2
  40. package/dist/chunks/{index-D-gO-M9M.js.map → index-D09iCOVq.js.map} +1 -1
  41. package/dist/chunks/version-Bs_8ymHO.js +2 -0
  42. package/dist/chunks/version-Bs_8ymHO.js.map +1 -0
  43. package/dist/chunks/version-DlzdKqY9.js +2 -0
  44. package/dist/chunks/version-DlzdKqY9.js.map +1 -0
  45. package/dist/docit.cjs.js +1 -1
  46. package/dist/docit.es.js +1 -1
  47. package/dist/index.cjs.js +1 -1
  48. package/dist/index.es.js +1 -1
  49. package/dist/lightbox.cjs.js +1 -1
  50. package/dist/lightbox.es.js +1 -1
  51. package/dist/map.es.js +1 -1
  52. package/dist/timeline.es.js +1 -1
  53. package/dist/user-profile.es.js +1 -1
  54. package/package.json +1 -1
  55. package/dist/chunks/version-CBPFfIng.js +0 -2
  56. package/dist/chunks/version-CBPFfIng.js.map +0 -1
  57. package/dist/chunks/version-D8Oyq5Pb.js +0 -2
  58. package/dist/chunks/version-D8Oyq5Pb.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{C as e,M as t,V as a,G as n,b as l,r as s}from"./User-DNifTiFu.js";import o from"./DataView-DBQUt_vV.js";class LoginEvent extends t{constructor(e={}){super(e,{endpoint:"/api/account/logins"})}}class LoginEventList extends e{constructor(e={}){super({ModelClass:LoginEvent,endpoint:"/api/account/logins",...e})}}class IncidentStats extends t{constructor(e={}){super(e,{endpoint:"/api/incident/stats",requiresId:!1})}}class IncidentEvent extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event"})}}class IncidentEventList extends e{constructor(e={}){super({ModelClass:IncidentEvent,endpoint:"/api/incident/event",size:10,...e})}}const i={edit:{title:"Edit Incident Event",fields:[{name:"category",type:"select",label:"Category",placeholder:"Select category",options:()=>Incident.COMPONENTS,editable:!0,force_top:!0,cols:6},{name:"incident",type:"text",label:"Incident",placeholder:"Enter Incident ID",cols:6},{name:"description",type:"textarea",label:"Description",placeholder:"Enter Description",cols:12},{name:"details",type:"textarea",label:"Details",placeholder:"Enter Details",cols:12},{name:"component",type:"text",label:"Component",placeholder:"Enter Component",cols:8},{name:"component_id",type:"text",label:"Component ID",placeholder:"Enter Component ID",cols:4}]}};class Incident extends t{constructor(e={}){super(e,{endpoint:"/api/incident/incident"})}}class IncidentList extends e{constructor(e={}){super({ModelClass:Incident,endpoint:"/api/incident/incident",size:10,...e})}}const r={create:{title:"Create Incident",fields:[{type:"tabset",name:"settingsTabs",tabs:[{label:"General",fields:[{name:"title",type:"text",label:"Title",required:!0,columns:12},{name:"details",type:"textarea",label:"Details",required:!0,columns:12}]},{label:"Advanced",fields:[{name:"priority",type:"select",label:"Priority",options:["1","2","3","4","5","6","7","8","9","10"],value:5,columns:6},{name:"status",type:"select",label:"Status",value:"open",options:["open","investigating","resolved","closed","paused","ignored"],columns:6},{name:"category",type:"text",label:"Category",value:"manual",columns:6}]},{label:"Metadata",fields:[{name:"metadata",type:"json",label:"Metadata",value:{example:"hello world"},rows:15,columns:12}]}]}]},edit:{title:"Edit Incident",fields:[{name:"category",type:"text",label:"Category",cols:6},{name:"status",type:"select",label:"Status",placeholder:"Select Status",options:["open","investigating","resolved","closed","paused","ignored"],cols:3},{name:"priority",type:"text",label:"Priority"},{name:"details",type:"textarea",label:"Description",placeholder:"Enter Name",cols:12},{name:"model_name",type:"text",label:"Model",placeholder:"Enter Model",cols:8},{name:"model_id",type:"text",label:"Model ID",placeholder:"Enter Model ID",cols:4}]}};class IncidentRuleSet extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset"})}}class IncidentRuleSetList extends e{constructor(e={}){super({ModelClass:IncidentRuleSet,endpoint:"/api/incident/event/ruleset",size:10,...e})}}class IncidentRule extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset/rule"})}}class IncidentRuleList extends e{constructor(e={}){super({ModelClass:IncidentRule,endpoint:"/api/incident/event/ruleset/rule",size:10,...e})}}class IncidentHistory extends t{constructor(e={}){super(e,{endpoint:"/api/incident/incident/history"})}}class IncidentHistoryList extends e{constructor(e={}){super({ModelClass:IncidentHistory,endpoint:"/api/incident/incident/history",size:10,...e})}}class RelatedIncidentsList extends IncidentList{constructor(e={}){const{sourceIp:t,ruleSet:a,group:n,hostname:l,category:s,status:o,params:i={},...r}=e;super({params:{ordering:"-modified",...null!=t?{source_ip:t}:{},...null!=a?{rule_set:a}:{},...null!=n?{group:n}:{},...null!=l?{hostname:l}:{},...null!=s?{category:s}:{},...null!=o?{status:o}:{},...i},...r})}}Incident.ADD_FORM=r.create,Incident.EDIT_FORM=r.edit,IncidentEvent.EDIT_FORM=i.edit;const c=[{value:0,label:"No Bundling"},{value:1,label:"By Hostname"},{value:2,label:"By Model Name"},{value:3,label:"By Model Name + ID"},{value:4,label:"By Source IP"},{value:5,label:"By Hostname + Model Name"},{value:6,label:"By Hostname + Model Name + ID"},{value:7,label:"By Source IP + Model Name"},{value:8,label:"By Source IP + Model Name + ID"},{value:9,label:"By Source IP + Hostname"}],u=[{value:0,label:"ALL (must match all rules)"},{value:1,label:"ANY (match any rule)"}],d=[{value:"==",label:"Equal (==)"},{value:"eq",label:"Equal (eq)"},{value:">",label:"Greater Than (>)"},{value:">=",label:"Greater Than or Equal (>=)"},{value:"<",label:"Less Than (<)"},{value:"<=",label:"Less Than or Equal (<=)"},{value:"contains",label:"Contains"},{value:"regex",label:"Regular Expression"}],p=[{value:"str",label:"String"},{value:"int",label:"Integer"},{value:"float",label:"Float"},{value:"bool",label:"Boolean"}],m=[{value:"level",label:"Level",description:"Event level (error, warning, info, debug)",meta:{type:"str"}},{value:"source_ip",label:"Source IP Address",description:"IP address of the event source",meta:{type:"str"}},{value:"rule_id",label:"Rule ID",description:"Numeric rule identifier",meta:{type:"int"}},{value:"hostname",label:"Hostname",description:"Hostname where event occurred",meta:{type:"str"}},{value:"component",label:"Component",description:"System component name",meta:{type:"str"}},{value:"component_id",label:"Component ID",description:"Component identifier",meta:{type:"str"}},{value:"category",label:"Category",description:"Event category (ossec, auth, api_error, etc.)",meta:{type:"str"}},{value:"description",label:"Description",description:"Event description text",meta:{type:"str"}},{value:"details",label:"Details",description:"Additional event details",meta:{type:"str"}},{value:"alert_id",label:"Alert ID",description:"Numeric alert identifier",meta:{type:"int"}},{value:"severity",label:"Severity",description:"Numeric severity level",meta:{type:"int"}},{value:"user",label:"User",description:"Username associated with event",meta:{type:"str"}},{value:"action",label:"Action",description:"Action that triggered the event",meta:{type:"str"}},{value:"status",label:"Status",description:"Status value or code",meta:{type:"str"}},{value:"status_code",label:"Status Code",description:"Numeric status code (e.g., HTTP status)",meta:{type:"int"}},{value:"message",label:"Message",description:"Event message text",meta:{type:"str"}},{value:"path",label:"Path",description:"File path or URL path",meta:{type:"str"}},{value:"title",label:"Title",description:"OSSEC Title",meta:{type:"str"}},{value:"country_code",label:"Country Code",description:"Country code associated with event",meta:{type:"str"}},{value:"region",label:"Region",description:"Region associated with event",meta:{type:"str"}},{value:"city",label:"City",description:"City associated with event",meta:{type:"str"}},{value:"http_user_agent",label:"HTTP User Agent",description:"User agent string associated with event",meta:{type:"str"}},{value:"request_path",label:"Request Path",description:"Request path associated with event",meta:{type:"str"}},{value:"method",label:"Method",description:"HTTP method or function name",meta:{type:"str"}}],b=["global","account","ossec","api","realtime","auth","login:unknown","invalid_password","sms:login_unknown","totp:login_unknown","reset:unknown","magic:unknown","token:unknown","api_denied","unauthenticated","view_permission_denied","edit_permission_denied","group_member_permission_denied","user_permission_denied","security_alert","totp:confirm_failed","totp:login_failed","totp:recovery_used","sms:otp_failed","email:no_mailbox","email:send_failed","sms:send_failed","email_change:bad_password","email_change:requested","account:deactivate_requested","phone_verify:invalid","email_verify:invalid","oauth:unlink_guard_error","rest_error","mojo_rest_error","rest_value_error"],h=b;class RuleSet extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset"})}}class RuleSetList extends e{constructor(e={}){super({ModelClass:RuleSet,endpoint:"/api/incident/event/ruleset",...e})}}const y=[{value:0,label:"Disabled — each event gets its own incident"},{value:5,label:"5 minutes"},{value:10,label:"10 minutes"},{value:15,label:"15 minutes"},{value:30,label:"30 minutes"},{value:60,label:"1 hour"},{value:120,label:"2 hours"},{value:360,label:"6 hours"},{value:720,label:"12 hours"},{value:1440,label:"1 day"},{value:null,label:"No limit — bundle forever"}],v={create:{title:"Create RuleSet",size:"lg",fields:[{type:"tabset",name:"rulesetTabs",tabs:[{label:"General",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"e.g., Brute Force Detection",columns:6},{name:"match_by",type:"select",label:"Match Logic",value:0,options:u,tooltip:"ALL = every condition must match. ANY = at least one",columns:6},{name:"category",type:"combo",label:"Scope / Category",required:!0,options:b,allowCustom:!0,placeholder:"Type or select...",tooltip:"Scope or event category to match. Use * as a catch-all",columns:6},{name:"priority",type:"number",label:"Evaluation Priority",value:10,required:!0,tooltip:"Lower number = evaluated first",columns:6},{name:"is_active",type:"switch",label:"Active",value:!0,tooltip:"Inactive rules are skipped during event processing",columns:6},{name:"metadata.delete_on_resolution",type:"switch",label:"Delete on Resolution",value:!1,tooltip:"Incidents are permanently deleted when resolved or closed (CASCADE)",columns:6}]},{label:"Bundling",fields:[{name:"bundle_by",type:"select",label:"Bundle By",value:4,options:c,tooltip:"How to group related events into one incident",columns:6},{name:"bundle_minutes",type:"select",label:"Bundle Window",value:30,options:y,tooltip:"Events outside this window create a new incident",columns:6},{name:"bundle_by_rule_set",type:"switch",label:"Bundle by RuleSet",value:!0,tooltip:"Group events matched by this rule into the same incident",columns:6}]},{label:"Thresholds",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-info-circle me-1"></i>\n <strong>How thresholds work:</strong> Events accumulate in "pending" status.\n Once trigger count is reached, the handler fires and the incident becomes "new".\n Leave empty to fire immediately on the first event.\n </div>'},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mb-1"><span class="badge bg-secondary me-1">1</span> Count — events before fire</div>'},{name:"trigger_count",type:"number",label:"",placeholder:"Empty = fire immediately on first event",tooltip:"Number of events before the handler fires",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">2</span> Within window — count only events in this many minutes</div>'},{name:"trigger_window",type:"number",label:"",placeholder:"Empty = count all events regardless of age",tooltip:"Only count events within this many minutes",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">3</span> Re-trigger — re-fire handler every N additional events</div>'},{name:"retrigger_every",type:"number",label:"",placeholder:"Empty = fire once only",tooltip:"Re-fire handler every N additional events after initial trigger",columns:12}]},{label:"Handler",fields:[{name:"handler",type:"text",label:"Handler Chain",placeholder:"e.g., block://?ttl=3600,ticket://?priority=8",tooltip:"Chain multiple handlers with commas",columns:12},{type:"html",columns:12,html:'<div class="alert alert-light border small mb-0">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>'}]},{label:"Agent",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-stars me-1"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>'},{name:"metadata.agent_prompt",type:"textarea",label:"Agent Prompt",rows:12,columns:12,placeholder:"You are a security analyst triaging…",tooltip:"Free-form prompt the LLM handler receives alongside the structured incident summary"}]}]}]},edit:{title:"Edit RuleSet",size:"lg",fields:[{type:"tabset",name:"rulesetTabs",tabs:[{label:"General",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"e.g., Brute Force Detection",columns:6},{name:"match_by",type:"select",label:"Match Logic",options:u,tooltip:"ALL = every condition must match. ANY = at least one",columns:6},{name:"category",type:"combo",label:"Scope / Category",options:b,allowCustom:!0,required:!0,placeholder:"Type or select...",tooltip:"Scope or event category to match. Use * as a catch-all",columns:6},{name:"priority",type:"number",label:"Evaluation Priority",required:!0,tooltip:"Lower number = evaluated first",columns:6},{name:"is_active",type:"switch",label:"Active",tooltip:"Inactive rules are skipped during event processing",columns:6},{name:"metadata.delete_on_resolution",type:"switch",label:"Delete on Resolution",tooltip:"Incidents are permanently deleted when resolved or closed (CASCADE)",columns:6}]},{label:"Bundling",fields:[{name:"bundle_by",type:"select",label:"Bundle By",options:c,tooltip:"How to group related events into one incident",columns:6},{name:"bundle_minutes",type:"select",label:"Bundle Window",options:y,tooltip:"Events outside this window create a new incident",columns:6},{name:"bundle_by_rule_set",type:"switch",label:"Bundle by RuleSet",tooltip:"Group events matched by this rule into the same incident",columns:6}]},{label:"Thresholds",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-info-circle me-1"></i>\n <strong>How thresholds work:</strong> Events accumulate in "pending" status.\n Once trigger count is reached, the handler fires and the incident becomes "new".\n Leave empty to fire immediately on the first event.\n </div>'},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mb-1"><span class="badge bg-secondary me-1">1</span> Count — events before fire</div>'},{name:"trigger_count",type:"number",label:"",placeholder:"Empty = fire immediately on first event",tooltip:"Number of events before the handler fires",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">2</span> Within window — count only events in this many minutes</div>'},{name:"trigger_window",type:"number",label:"",placeholder:"Empty = count all events regardless of age",tooltip:"Only count events within this window toward the trigger count",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">3</span> Re-trigger — re-fire handler every N additional events</div>'},{name:"retrigger_every",type:"number",label:"",placeholder:"Empty = fire once only",tooltip:"Re-fire handler every N additional events after initial trigger",columns:12}]},{label:"Handler",fields:[{name:"handler",type:"text",label:"Handler Chain",placeholder:"e.g., block://?ttl=3600,ticket://?priority=8",tooltip:"Chain multiple handlers with commas",columns:12},{type:"html",columns:12,html:'<div class="alert alert-light border small mb-0">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>'}]},{label:"Agent",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-stars me-1"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>'},{name:"metadata.agent_prompt",type:"textarea",label:"Agent Prompt",rows:12,columns:12,placeholder:"You are a security analyst triaging…",tooltip:"Free-form prompt the LLM handler receives alongside the structured incident summary"}]}]}]}};class Rule extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset/rule"})}}class RuleList extends e{constructor(e={}){super({ModelClass:Rule,endpoint:"/api/incident/event/ruleset/rule",...e})}}const g={create:{title:"Create Rule",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter rule name",cols:12},{name:"field_name",type:"combo",label:"Field Name",required:!0,placeholder:"Select or enter field name...",options:m,allowCustom:!0,showDescription:!0,help:"Select a common field or type a custom field name",cols:8},{name:"index",type:"select",label:"Index",required:!0,start:0,end:14,step:1,cols:4},{name:"comparator",type:"select",label:"Comparator",required:!0,options:d,cols:6},{name:"value_type",type:"select",label:"Value Type",required:!0,options:p,value:"str",cols:6},{name:"value",type:"textarea",label:"Value",required:!0,placeholder:"Enter comparison value",cols:12}]},edit:{title:"Edit Rule",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter rule name",cols:12},{name:"field_name",type:"combo",label:"Field Name",required:!0,placeholder:"Select or enter field name...",options:m,allowCustom:!0,showDescription:!0,help:"Select a common field or type a custom field name",cols:12},{name:"comparator",type:"select",label:"Comparator",required:!0,options:d,cols:6},{name:"value_type",type:"select",label:"Value Type",required:!0,options:p,cols:6},{name:"value",type:"text",label:"Value",required:!0,placeholder:"Enter comparison value",cols:12}]}};RuleSet.EDIT_FORM=v.edit,RuleSet.ADD_FORM=v.create,RuleSet.CREATE_FORM=v.create,RuleSet.BundleByOptions=c,RuleSet.MatchByOptions=u,Rule.EDIT_FORM=g.edit,Rule.ADD_FORM=g.create,Rule.CREATE_FORM=g.create,Rule.ComparatorOptions=d,Rule.ValueTypeOptions=p;class PushDeviceView extends a{constructor(e={}){super({className:"push-device-view",...e}),this.model=e.model}getTemplate(){return'\n <div class="p-3">\n <h3>{{model.device_name}}</h3>\n <p class="text-muted">{{model.user.display_name}}</p>\n <div data-container="data-view"></div>\n </div>\n '}onInit(){this.dataView=new o({containerId:"data-view",model:this.model,fields:[{name:"platform",label:"Platform",format:"badge"},{name:"push_enabled",label:"Push Enabled",format:"boolean"},{name:"app_version",label:"App Version"},{name:"os_version",label:"OS Version"},{name:"last_seen",label:"Last Seen",format:"datetime"},{name:"push_preferences",label:"Preferences",format:"json"}]}),this.addChild(this.dataView)}}class PushDevice extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push"})}}class PushDeviceList extends e{constructor(e={}){super({ModelClass:PushDevice,endpoint:"/api/account/devices/push",...e})}}class PushTemplate extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/templates"})}}class PushTemplateList extends e{constructor(e={}){super({ModelClass:PushTemplate,endpoint:"/api/account/devices/push/templates",...e})}}class PushConfig extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/config"})}}class PushConfigList extends e{constructor(e={}){super({ModelClass:PushConfig,endpoint:"/api/account/devices/push/config",...e})}}class PushDelivery extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/deliveries"})}}class PushDeliveryList extends e{constructor(e={}){super({ModelClass:PushDelivery,endpoint:"/api/account/devices/push/deliveries",...e})}}const f={create:{title:"Create Push Configuration",fields:[{name:"name",label:"Name",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id"},{name:"fcm_service_account",label:"Service Account",type:"textarea",rows:10}]},edit:{title:"Edit Push Configuration",fields:[{name:"name",label:"Name",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id"},{name:"fcm_service_account",label:"Service Account",type:"textarea",rows:10},{name:"is_active",label:"Is Active",type:"switch",value:!0}]}},w={edit:{title:"Edit Push Template",fields:[{name:"name",label:"Name",required:!0},{name:"category",label:"Category",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id",defaultParams:{is_active:!0}},{name:"title_template",label:"Title Template",required:!0},{name:"body_template",label:"Body Template",type:"textarea",required:!0},{name:"action_url",label:"Action URL"},{name:"priority",label:"Priority",type:"select",options:["high","normal"]},{name:"variables",label:"Variables",type:"json",help:"JSON format"},{name:"is_active",label:"Is Active",type:"switch"}]}};f.create=f.edit,w.create=w.edit,PushConfig.ADD_FORM=f.create,PushConfig.EDIT_FORM=f.edit,PushTemplate.ADD_FORM=w.create,PushTemplate.EDIT_FORM=w.edit,PushDevice.VIEW_CLASS=PushDeviceView;class Ticket extends t{constructor(e={}){super(e,{endpoint:"/api/incident/ticket"})}}class TicketList extends e{constructor(e={}){super({ModelClass:Ticket,endpoint:"/api/incident/ticket",...e})}}const _={ticket:"Ticket",bug:"Bug",feature:"Feature Request",incident:"Incident",security:"Security Incident",fulfillment:"Fulfillment",new_user:"New User",new_group:"New Group",qa:"Quality Assurance"},S=Object.entries(_).map(([e,t])=>({value:e,label:t})),x={create:{title:"Create Ticket",fields:[{name:"title",type:"text",label:"Title",required:!0,cols:12},{name:"description",type:"textarea",label:"Description",required:!1,cols:12},{name:"category",type:"select",label:"Category",options:S,cols:12,value:"ticket"},{name:"priority",type:"number",label:"Priority",value:5,cols:6},{name:"status",type:"select",label:"Status",options:["new","open","paused","resolved","qa","ignored"],cols:6,value:"new"},{type:"collection",name:"assignee",label:"Assignee",Collection:l,labelField:"display_name",valueField:"id",cols:12},{type:"collection",name:"incident",label:"Incident",Collection:IncidentList,labelField:"title",valueField:"id",cols:12}]},edit:{title:"Edit Ticket",fields:[{name:"title",type:"text",label:"Title",required:!0,cols:12},{name:"category",type:"select",label:"Category",options:S,cols:12},{name:"priority",type:"number",label:"Priority",cols:6},{name:"status",type:"select",label:"Status",options:["new","open","paused","resolved","qa","ignored"],cols:6},{type:"collection",name:"assignee",label:"Assignee",Collection:l,labelField:"display_name",valueField:"id",cols:12},{type:"collection",name:"incident",label:"Incident",Collection:IncidentList,labelField:"title",valueField:"id",cols:12},{name:"enable_llm",type:"checkbox",label:"Enable AI agent",cols:12}]}};class TicketNote extends t{constructor(e={}){super(e,{endpoint:"/api/incident/ticket/note"})}}class TicketNoteList extends e{constructor(e={}){super({ModelClass:TicketNote,endpoint:"/api/incident/ticket/note",...e})}}Ticket.ADD_FORM=x.create,Ticket.EDIT_FORM=x.edit;class AssistantConversation extends t{constructor(e={}){super(e,{endpoint:"/api/assistant/conversation"})}}class AssistantConversationList extends e{constructor(e={}){super({ModelClass:AssistantConversation,endpoint:"/api/assistant/conversation",size:50,...e})}}class AssistantSkill extends t{constructor(e={}){super(e,{endpoint:"/api/assistant/skill"})}}class AssistantSkillList extends e{constructor(e={}){super({ModelClass:AssistantSkill,endpoint:"/api/assistant/skill",size:50,...e})}}class Job extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/job"})}async cancel(){const e=await this.save({cancel_request:!0});return e.success&&e.data.status&&this.set("cancel_requested",!0),e}async retry(e=null){const t=e?{retry_request:{retry:!0,delay:e}}:{retry_request:!0},a=await this.save(t);return a.success&&a.data.status&&a.data.new_job_id?{...a,newJobId:a.data.new_job_id,originalJobId:a.data.original_job_id}:a}async getDetailedStatus(){const e=await this.save({get_status:!0});return e.success&&e.data.status&&this.set(e.data.data),e}async cloneJob(e={}){const t={publish_job:{payload:e,...e}},a=await this.save(t);return a.success&&a.data.status&&a.data.job_id?{...a,newJobId:a.data.job_id,templateJobId:a.data.template_job_id}:a}isActive(){const e=this.get("status");return["pending","running"].includes(e)}isScheduled(){if("pending"!==this.get("status"))return!1;const e=this.get("run_at");if(!e)return!1;const t="number"==typeof e&&e<1e11?1e3*e:new Date(e).getTime();return Number.isFinite(t)&&t>Date.now()}isTerminal(){const e=this.get("status");return["completed","failed","canceled","expired"].includes(e)}canRetry(){const e=this.get("status");return["failed","canceled","expired"].includes(e)&&!1!==this.get("is_retriable")}canCancel(){const e=this.get("status");return["pending","running"].includes(e)&&!this.get("cancel_requested")}getStatusBadgeClass(){return{pending:"bg-primary",running:"bg-success",completed:"bg-info",failed:"bg-danger",canceled:"bg-secondary",expired:"bg-warning"}[this.get("status")]||"bg-secondary"}getStatusIcon(){return{pending:"bi-hourglass",running:"bi-arrow-repeat",completed:"bi-check-circle",failed:"bi-x-octagon",canceled:"bi-x-circle",expired:"bi-clock"}[this.get("status")]||"bi-question-circle"}getEvents(){return this.get("recent_events")||[]}getFormattedDuration(){const e=this.get("duration_ms");return e&&0!==e?e<1e3?`${e}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:e<36e5?`${(e/6e4).toFixed(1)}m`:`${(e/36e5).toFixed(1)}h`:"N/A"}getQueuePosition(){return this.get("queue_position")}hasExpired(){const e=this.get("expires_at");return!!e&&new Date(e)</* @__PURE__ */new Date}getRunnerId(){return this.get("runner_id")}getPayload(){return this.get("payload")||{}}getMetadata(){return this.get("metadata")||{}}}class JobList extends e{constructor(e={}){super({ModelClass:Job,endpoint:"/api/jobs/job",...e})}async fetchByStatus(e,t={}){return this.fetch({status:e,...t})}async fetchByChannel(e,t={}){return this.fetch({channel:e,...t})}async fetchPending(e={}){return this.fetchByStatus("pending",e)}async fetchRunning(e={}){return this.fetchByStatus("running",e)}async fetchCompleted(e={}){return this.fetchByStatus("completed",e)}async fetchFailed(e={}){return this.fetchByStatus("failed",e)}async fetchScheduled(e={}){return this.fetch({scheduled:!0,...e})}}const C={publish:{title:"Publish New Job",fields:[{name:"func",type:"text",label:"Function",required:!0,placeholder:"myapp.jobs.send_email",help:"Module path to job function"},{name:"channel",type:"text",label:"Channel",value:"default",help:'Queue channel (default: "default")'},{name:"payload",type:"textarea",label:"Payload (JSON)",required:!0,rows:8,placeholder:'{\n "key": "value"\n}',help:"JSON data passed to the job function"},{name:"delay",type:"number",label:"Delay (seconds)",min:0,help:"Delay execution by specified seconds"},{name:"run_at",type:"datetime-local",label:"Run At",help:"Schedule for specific date/time"},{name:"max_retries",type:"number",label:"Max Retries",value:3,min:0,max:10},{name:"expires_in",type:"number",label:"Expires In (seconds)",value:900,min:60,help:"Job will expire if not completed in this time"},{name:"broadcast",type:"switch",label:"Broadcast to All Workers",help:"Execute on all available workers"}]},retry:{title:"Retry Job",fields:[{name:"delay",type:"number",label:"Delay (seconds)",value:0,min:0,help:"Delay before retry (0 = immediate)"}]},clone:{title:"Clone Job",fields:[{name:"channel",type:"text",label:"Channel",help:"Override channel for cloned job"},{name:"payload",type:"textarea",label:"Modified Payload (JSON)",rows:8,help:"Modified payload for cloned job"},{name:"delay",type:"number",label:"Delay (seconds)",min:0}]}};Job.publish=async function(e){return await s.POST("/api/jobs/publish",e)},Job.getStats=async function(){const e=await s.GET("/api/jobs/stats");return e.success?e.data:null},Job.getHealth=async function(e=null){const t=e?`/api/jobs/health/${e}`:"/api/jobs/health",a=s.GET(t);return a.success?a.data:null},Job.test=async function(){return await s.POST("/api/jobs/test",{})},Job.tests=async function(){return await s.POST("/api/jobs/tests",{})},Job.clearStuck=async function(e=null){const t=e?{channel:e}:{};return await s.POST("/api/jobs/control/clear-stuck",t)},Job.clearChannel=async function(e){return await s.POST("/api/jobs/control/clear-queue",{channel:e,confirm:"yes"})},Job.cleanConsumers=async function(){return await s.POST("/api/jobs/control/cleanup-consumers")},Job.purgeJobs=async function(e){return await s.POST("/api/jobs/control/purge",{days_old:e})};class JobLog extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/logs"})}}class JobLogList extends e{constructor(e={}){super({endpoint:"/api/jobs/logs",model:JobLog,...e})}}class JobEvent extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/event"})}}class JobEventList extends e{constructor(e={}){super({endpoint:"/api/jobs/event",model:JobEvent,...e})}}class JobsEngineStats extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/stats",requiresId:!1})}}class SimilarJobsList extends JobList{constructor(e={}){const{func:t,params:a={},...n}=e;super({params:{ordering:"-created",...t?{func:t}:{},...a},...n})}}class ActiveJobsList extends JobList{constructor(e={}){const{runnerId:t,params:a={},...n}=e;super({params:{status:"running",...null!=t?{runner_id:t}:{},...a},...n})}}class EmailDomain extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/domain",...t})}async onboard(e={},t={}){if(!this.id)return await this.showError("Cannot onboard domain without ID"),{success:!1,status:400,error:"Missing domain id"};try{const a=`${this.buildUrl(this.id)}/onboard`;return await this.rest.POST(a,e,t.params)}catch(a){return{success:!1,status:a?.status||500,error:a?.message||"Failed to onboard domain"}}}async audit(e={}){if(!this.id)return await this.showError("Cannot audit domain without ID"),{success:!1,status:400,error:"Missing domain id"};const t=(e.method||"GET").toUpperCase(),a=`${this.buildUrl(this.id)}/audit`;try{return"POST"===t?await this.rest.POST(a,e.data||{},e.params):await this.rest.GET(a,e.params)}catch(n){return{success:!1,status:n?.status||500,error:n?.message||"Failed to audit domain"}}}async reconcile(e={},t={}){if(!this.id)return await this.showError("Cannot reconcile domain without ID"),{success:!1,status:400,error:"Missing domain id"};try{const a=`${this.buildUrl(this.id)}/reconcile`;return await this.rest.POST(a,e,t.params)}catch(a){return{success:!1,status:a?.status||500,error:a?.message||"Failed to reconcile domain"}}}static async onboardById(e,t={},a={}){const n=new EmailDomain({id:e},a);return await n.onboard(t,a)}static async auditById(e,t={}){const a=new EmailDomain({id:e},t);return await a.audit(t)}static async reconcileById(e,t={},a={}){const n=new EmailDomain({id:e},a);return await n.reconcile(t,a)}}class EmailDomainList extends e{constructor(e={}){super({ModelClass:EmailDomain,endpoint:"/api/aws/email/domain",size:10,...e})}}const E={create:{title:"Add Email Domain",fields:[{name:"name",type:"text",label:"Domain Name",placeholder:"example.com",required:!0,columns:12,help:"Enter the root domain to verify with SES (no protocol)."},{name:"region",type:"text",label:"AWS Region (optional)",placeholder:"us-east-1",columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with SES permissions",columns:12,help:"Optional, AWS Key with SES permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with SES permissions",columns:12,help:"Optional, AWS Secret with SES permissions"},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12,help:"Catch-all SES receipt rule to S3 + SNS; routing is done in-app."}]},edit:{title:"Edit Email Domain",fields:[{name:"name",type:"text",label:"Domain Name",placeholder:"example.com",required:!0,columns:12,readonly:!0,help:"Domain name cannot be changed after creation."},{name:"region",type:"text",label:"AWS Region",placeholder:"us-east-1",columns:12},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12},{name:"s3_inbound_bucket",type:"text",label:"Inbound S3 Bucket",placeholder:"my-inbound-bucket",columns:12},{name:"s3_inbound_prefix",type:"text",label:"Inbound S3 Prefix",placeholder:"inbound/example.com/",columns:12},{name:"dns_mode",type:"select",label:"DNS Mode",options:[{value:"manual",text:"Manual (show records)"},{value:"godaddy",text:"GoDaddy (apply via API)"}],columns:12}]},credentials:{fields:[{name:"region",type:"select",label:"AWS Region (optional)",placeholder:"us-east-1",options:[{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with SES permissions",columns:12,help:"Optional, AWS Key with SES permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with SES permissions",columns:12,help:"Optional, AWS Secret with SES permissions"}]},onboard:{title:"Onboard Domain",fields:[{type:"header",text:"Receiving",level:6,className:"mt-2"},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12},{name:"s3_inbound_bucket",type:"text",label:"Inbound S3 Bucket",placeholder:"my-inbound-bucket",columns:12,help:"Required if receiving is enabled."},{name:"s3_inbound_prefix",type:"text",label:"Inbound S3 Prefix",placeholder:"inbound/example.com/",columns:12},{type:"header",text:"MAIL FROM (optional)",level:6,className:"mt-3"},{name:"ensure_mail_from",type:"switch",label:"Ensure MAIL FROM Setup",columns:12},{name:"mail_from_subdomain",type:"text",label:"MAIL FROM Subdomain",placeholder:"feedback",columns:12},{type:"header",text:"DNS",level:6,className:"mt-3"},{name:"dns_mode",type:"select",label:"DNS Mode",options:[{value:"manual",text:"Manual (show records)"},{value:"godaddy",text:"GoDaddy (apply via API)"}],value:"manual",columns:12},{name:"godaddy_key",type:"text",label:"GoDaddy API Key",columns:12,help:"Required when DNS Mode = GoDaddy."},{name:"godaddy_secret",type:"password",label:"GoDaddy API Secret",columns:12},{type:"header",text:"Webhook Endpoints",level:6,className:"mt-3"},{name:"endpoints.bounce",type:"text",label:"Bounce Endpoint",placeholder:"https://portal.example.com/api/aws/sns/bounce",columns:12},{name:"endpoints.complaint",type:"text",label:"Complaint Endpoint",placeholder:"https://portal.example.com/api/aws/sns/complaint",columns:12},{name:"endpoints.delivery",type:"text",label:"Delivery Endpoint",placeholder:"https://portal.example.com/api/aws/sns/delivery",columns:12},{name:"endpoints.inbound",type:"text",label:"Inbound Endpoint",placeholder:"https://portal.example.com/api/aws/sns/inbound",columns:12}]}};class Mailbox extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/mailbox",...t})}}Mailbox.sendEmail=async function(e){return await s.POST("/api/aws/email/send",e)};class MailboxList extends e{constructor(e={}){super({ModelClass:Mailbox,endpoint:"/api/aws/email/mailbox",size:10,...e})}}const M={create:{title:"Add Mailbox",fields:[{type:"collection",name:"domain",label:"Domain",Collection:EmailDomainList,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search domains...",emptyFetch:!1,required:!0,debounceMs:300,columns:12},{name:"email",type:"email",label:"Email Address",placeholder:"support@example.com",required:!0,columns:12},{name:"allow_inbound",type:"switch",label:"Allow Inbound",columns:6},{name:"allow_outbound",type:"switch",label:"Allow Outbound",defaultValue:!0,columns:6},{name:"is_system_default",type:"switch",label:"System Default",columns:6},{name:"is_domain_default",type:"switch",label:"Domain Default",columns:6},{name:"async_handler",type:"text",label:"Async Handler (optional)",placeholder:"myapp.handlers.process_support",columns:12,help:"Module:function to process inbound messages via task system"}]},edit:{title:"Edit Mailbox",fields:[{name:"email",type:"email",label:"Email Address",required:!0,columns:12},{name:"allow_inbound",type:"switch",label:"Allow Inbound",columns:6},{name:"allow_outbound",type:"switch",label:"Allow Outbound",columns:6},{name:"is_system_default",type:"switch",label:"System Default",columns:6},{name:"is_domain_default",type:"switch",label:"Domain Default",columns:6},{name:"async_handler",type:"text",label:"Async Handler (optional)",placeholder:"myapp.handlers.process_support",columns:12}]}};class SentMessage extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/sent",...t})}}class SentMessageList extends e{constructor(e={}){super({ModelClass:SentMessage,endpoint:"/api/aws/email/sent",size:10,...e})}}const I={view:{title:"Sent Message Details",fields:[{name:"id",type:"text",label:"ID",readonly:!0,cols:6},{name:"ses_message_id",type:"text",label:"SES Message ID",readonly:!0,cols:6},{name:"from_email",type:"text",label:"From",readonly:!0,cols:12},{name:"to",type:"textarea",label:"To",readonly:!0,rows:2,cols:12},{name:"cc",type:"textarea",label:"CC",readonly:!0,rows:2,cols:12},{name:"bcc",type:"textarea",label:"BCC",readonly:!0,rows:2,cols:12},{name:"subject",type:"text",label:"Subject",readonly:!0,cols:12},{name:"status",type:"text",label:"Status",readonly:!0,cols:6},{name:"status_reason",type:"textarea",label:"Status Reason",readonly:!0,rows:3,cols:12},{name:"created",type:"text",label:"Created",readonly:!0,cols:6}]}};class EmailTemplate extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/template",...t})}}class EmailTemplateList extends e{constructor(e={}){super({ModelClass:EmailTemplate,endpoint:"/api/aws/email/template",size:10,...e})}}const k={create:{title:"Add Email Template",fields:[{name:"name",type:"text",label:"Name",required:!0,cols:12},{name:"subject_template",type:"text",label:"Subject Template",cols:12},{type:"tabset",name:"settingsTabs",tabs:[{label:"HTML",fields:[{name:"html_template",type:"htmlpreview",label:"HTML Template",rows:16,cols:12}]},{label:"TEXT",fields:[{name:"text_template",type:"textarea",label:"Text Template",rows:16,cols:12}]}]}]},edit:{title:"Edit Email Template",fields:[{name:"name",type:"text",label:"Name",required:!0,cols:12},{name:"subject_template",type:"text",label:"Subject Template",cols:12},{type:"tabset",name:"settingsTabs",tabs:[{label:"HTML",fields:[{name:"html_template",type:"textarea",label:"HTML Template",rows:16,cols:12}]},{label:"TEXT",fields:[{name:"text_template",type:"textarea",label:"Text Template",rows:16,cols:12}]}]}]}};EmailDomain.ADD_FORM=E.create,EmailDomain.EDIT_FORM=E.edit,Mailbox.ADD_FORM=M.create,Mailbox.EDIT_FORM=M.edit,EmailTemplate.ADD_FORM=k.create,EmailTemplate.EDIT_FORM=k.edit;const D=[{value:"contact_us",label:"Contact Us"},{value:"support",label:"Support"}],T=[{value:"open",label:"Open"},{value:"closed",label:"Closed"}],R=[{value:"low",label:"Low"},{value:"normal",label:"Normal"},{value:"high",label:"High"}],P=[{value:"billing",label:"Billing"},{value:"account",label:"Account"},{value:"bug",label:"Bug"},{value:"other",label:"Other"}],L={company:"Company",category:"Category",severity:"Severity",referrer:"Referrer",landing_page:"Landing Page",utm_source:"UTM Source",utm_medium:"UTM Medium",utm_campaign:"UTM Campaign",utm_term:"UTM Term",utm_content:"UTM Content"};class PublicMessage extends t{constructor(e={}){super(e,{endpoint:"/api/account/public_message"})}}class PublicMessageList extends e{constructor(e={}){super({ModelClass:PublicMessage,endpoint:"/api/account/public_message",size:25,...e})}}class PhoneNumber extends t{constructor(e={},t={}){super(e,{endpoint:"/api/phonehub/number",...t})}static async normalize(e,t="US"){const a={phone_number:e};t&&(a.country_code=t);const n=await s.POST("/api/phonehub/number/normalize",a),l=n?.data??n;return!0===l?.status||!0===l?.success?{success:!0,phone_number:l?.data?.phone_number??l?.phone_number,data:l?.data??l,response:n}:{success:!1,error:l?.error||"Normalization failed",response:n}}static async lookup(e,t={}){const a=await s.POST("/api/phonehub/number/lookup",{phone_number:e,...t}),n=a?.data??a;if(!0===n?.status||!0===n?.success){const e=n?.data??{};return{success:!0,model:new PhoneNumber(e,{endpoint:"/api/phonehub/number"}),data:e,response:a}}return{success:!1,error:n?.error||"Phone lookup failed",response:a}}}class PhoneNumberList extends e{constructor(e={}){super({ModelClass:PhoneNumber,endpoint:"/api/phonehub/number",size:10,...e})}}class SMS extends t{constructor(e={},t={}){super(e,{endpoint:"/api/phonehub/sms",...t})}static async send(e={}){const t=await s.POST("/api/phonehub/sms/send",e),a=t?.data??t;if(!0===a?.status||!0===a?.success){const e=a?.data??{};return{success:!0,model:new SMS(e,{endpoint:"/api/phonehub/sms"}),data:e,response:t}}return{success:!1,error:a?.error||"Failed to send SMS",response:t}}}class SMSList extends e{constructor(e={}){super({ModelClass:SMS,endpoint:"/api/phonehub/sms",size:10,...e})}}class PhoneConfig extends t{constructor(e={},t={}){super(e,{endpoint:"/api/phonehub/config",...t})}}class PhoneConfigList extends e{constructor(e={}){super({ModelClass:PhoneConfig,endpoint:"/api/phonehub/config",size:25,...e})}}const A=[{value:"twilio",label:"Twilio"},{value:"aws",label:"AWS SNS"},{value:"mojo",label:"Mojo Remote Instance"}],N="•••••••• (leave blank to keep existing)",O=[{name:"name",type:"text",label:"Name",required:!0,columns:8,placeholder:"e.g. Primary Twilio, Backup AWS, Mojo Bridge"},{type:"collection",name:"group",label:"Group",Collection:n,labelField:"name",valueField:"id",placeholder:"Search groups…",emptyFetch:!1,debounceMs:300,columns:4,help:"Leave blank for the System Default config."},{name:"provider",type:"select",label:"Provider",required:!0,options:A,columns:6},{name:"lookup_cache_days",type:"number",label:"Lookup cache (days)",columns:6,help:"Carrier-lookup cache lifetime per number."},{name:"is_active",type:"switch",label:"Active",columns:4},{name:"test_mode",type:"switch",label:"Test mode",columns:4,help:"Use the provider sandbox / test endpoint."},{name:"lookup_enabled",type:"switch",label:"Lookup",columns:4,help:"Auto-run carrier lookups on new numbers."},{type:"header",label:"Twilio credentials",columns:12,showWhen:{field:"provider",value:"twilio"}},{name:"twilio_from_number",type:"text",label:"Twilio From Number",placeholder:"+15551234567",columns:6,showWhen:{field:"provider",value:"twilio"}},{name:"twilio_account_sid",type:"password",label:"Twilio Account SID",placeholder:N,columns:6,autocomplete:"off",showWhen:{field:"provider",value:"twilio"}},{name:"twilio_auth_token",type:"password",label:"Twilio Auth Token",placeholder:N,columns:12,autocomplete:"new-password",showWhen:{field:"provider",value:"twilio"}},{type:"header",label:"AWS SNS credentials",columns:12,showWhen:{field:"provider",value:"aws"}},{name:"aws_region",type:"text",label:"AWS Region",value:"us-east-1",placeholder:"us-east-1",columns:6,showWhen:{field:"provider",value:"aws"}},{name:"aws_sender_id",type:"text",label:"Sender ID",placeholder:"Optional alphanumeric sender (region-dependent)",columns:6,showWhen:{field:"provider",value:"aws"}},{name:"aws_access_key_id",type:"password",label:"Access Key ID",placeholder:N,columns:6,autocomplete:"off",showWhen:{field:"provider",value:"aws"}},{name:"aws_secret_access_key",type:"password",label:"Secret Access Key",placeholder:N,columns:6,autocomplete:"new-password",showWhen:{field:"provider",value:"aws"}},{type:"header",label:"Mojo Remote credentials",columns:12,showWhen:{field:"provider",value:"mojo"}},{name:"mojo_remote_url",type:"url",label:"Remote Mojo URL",placeholder:"https://sms.example.com",columns:12,showWhen:{field:"provider",value:"mojo"}},{name:"mojo_api_key",type:"password",label:"Mojo API Key",placeholder:N,columns:12,autocomplete:"new-password",help:"Paste the token shown once when the API key was provisioned on the remote mojo. We never display it after save.",showWhen:{field:"provider",value:"mojo"}}],q={create:{title:"New Phone Config",fields:O,defaults:{provider:"twilio",is_active:!0,test_mode:!1,lookup_enabled:!0,lookup_cache_days:90}},edit:{title:"Edit Phone Config",fields:O}};PhoneConfig.ADD_FORM=q.create,PhoneConfig.EDIT_FORM=q.edit,PhoneConfig.SECRET_FIELDS=["twilio_account_sid","twilio_auth_token","aws_access_key_id","aws_secret_access_key","mojo_api_key"],PhoneConfig.PROVIDER_OPTIONS=A,PhoneConfig.FORM_DIALOG_CONFIG={size:"lg",submitText:"Create"};const B={PhoneNumber:PhoneNumber,PhoneNumberList:PhoneNumberList,SMS:SMS,SMSList:SMSList,PhoneConfig:PhoneConfig,PhoneConfigList:PhoneConfigList,PhoneConfigForms:q};class JobRunner extends t{constructor(e={}){e.runner_id&&!e.id&&(e.id=e.runner_id),super(e,{endpoint:"/api/jobs/runners",idAttribute:"runner_id"})}async ping(e=2){const t=this.getApp();if(!t||!t.rest)throw new Error("App or REST client not available");const a=await t.rest.POST("/api/jobs/runners/ping",{runner_id:this.get("runner_id"),timeout:e});return a.success&&a.data.status&&(this.set("last_heartbeat",/* @__PURE__ */(new Date).toISOString()),this.set("ping_status",a.data.ping_status||"success")),a}async shutdown(e=!0){const t=this.getApp();if(!t||!t.rest)throw new Error("App or REST client not available");const a=await t.rest.POST("/api/jobs/runners/shutdown",{runner_id:this.get("runner_id"),graceful:e});return a.success&&a.data.status&&this.set("alive",!1),a}getChannels(){return this.get("channels")||[]}getStatusBadgeClass(){return this.get("alive")?"bg-success":"bg-danger"}getStatusIcon(){return this.get("alive")?"bi-check-circle-fill":"bi-x-octagon-fill"}isActive(){return!0===this.get("alive")}isHealthy(){if(!this.isActive())return!1;const e=this.get("last_heartbeat");return!!e&&(Date.now()-new Date(e).getTime())/1e3<120}getFormattedHeartbeatAge(){const e=this.get("last_heartbeat");if(!e)return"Never";const t=(Date.now()-new Date(e).getTime())/1e3;return t<60?`${Math.round(t)}s ago`:t<3600?`${Math.round(t/60)}m ago`:`${Math.round(t/3600)}h ago`}getUtilization(){const e=(this.get("jobs_processed")||0)+(this.get("jobs_failed")||0);return e>10?100:Math.min(10*e,100)}getFormattedUptime(){const e=this.get("started");if(!e)return"Unknown";const t=new Date(e),a=/* @__PURE__ */new Date-t,n=Math.floor(a/1e3);return n<60?`${n}s`:n<3600?`${Math.floor(n/60)}m`:n<86400?`${Math.floor(n/3600)}h`:`${Math.floor(n/86400)}d`}getWorkerInfo(){const e=this.get("jobs_processed")||0,t=this.get("jobs_failed")||0;return{processed:e,failed:t,total:e+t,alive:this.get("alive"),utilization:this.getUtilization()}}getDisplayName(){const e=this.get("runner_id");if(!e)return"Unknown Runner";const t=e.split("-");return t.length>1?t[0]:e}canControl(){return!0===this.get("alive")}}class JobRunnerList extends e{constructor(e={}){super({ModelClass:JobRunner,endpoint:"/api/jobs/runners",...e})}getActive(){return this.where(e=>e.isActive())}getByChannel(e){return this.where(t=>t.getChannels().includes(e))}getHealthy(){return this.where(e=>e.isHealthy())}getTotalProcessed(){return this.models.reduce((e,t)=>e+(t.get("jobs_processed")||0),0)}getTotalFailed(){return this.models.reduce((e,t)=>e+(t.get("jobs_failed")||0),0)}getSystemHealth(){if(0===this.models.length)return 0;const e=this.models.filter(e=>e.get("alive")).length;return Math.round(e/this.models.length*100)}getAllChannels(){const e=/* @__PURE__ */new Set;return this.models.forEach(t=>{t.getChannels().forEach(t=>e.add(t))}),Array.from(e).sort()}}JobRunner.ping=async function(e,t=2){const a="undefined"!=typeof window&&window.app;if(!a||!a.rest)throw new Error("App or REST client not available");return await a.rest.POST("/api/jobs/runners/ping",{runner_id:e,timeout:t})},JobRunner.shutdown=async function(e,t=!0){const a="undefined"!=typeof window&&window.app;if(!a||!a.rest)throw new Error("App or REST client not available");return await a.rest.POST("/api/jobs/runners/shutdown",{runner_id:e,graceful:t})},JobRunner.broadcast=async function(e,t={},a=2){const n="undefined"!=typeof window&&window.app;if(!n||!n.rest)throw new Error("App or REST client not available");return await n.rest.POST("/api/jobs/runners/broadcast",{command:e,data:t,timeout:a})},JobRunner.broadcastStatus=async function(e=2){return JobRunner.broadcast("status",{},e)},JobRunner.broadcastShutdown=async function(e=2){return JobRunner.broadcast("shutdown",{},e)},JobRunner.broadcastPause=async function(e=2){return JobRunner.broadcast("pause",{},e)},JobRunner.broadcastResume=async function(e=2){return JobRunner.broadcast("resume",{},e)},JobRunner.broadcastReload=async function(e=2){return JobRunner.broadcast("reload",{},e)};const F={broadcast:{title:"Broadcast Command",fields:[{name:"command",type:"select",label:"Command",required:!0,options:[{value:"status",label:"Status Check"},{value:"pause",label:"Pause Processing"},{value:"resume",label:"Resume Processing"},{value:"reload",label:"Reload Configuration"},{value:"shutdown",label:"Shutdown All Runners"}],help:"Command to send to all runners"},{name:"timeout",type:"number",label:"Timeout (seconds)",value:2,min:.5,max:10,step:.5,help:"How long to wait for responses"}]}};class BouncerDevice extends t{constructor(e={},t={}){super(e,{endpoint:"/api/account/bouncer/device",...t})}}class BouncerDeviceList extends e{constructor(e={}){super({ModelClass:BouncerDevice,endpoint:"/api/account/bouncer/device",size:25,...e})}}class BouncerSignal extends t{constructor(e={},t={}){super(e,{endpoint:"/api/account/bouncer/signal",...t})}}class BouncerSignalList extends e{constructor(e={}){super({ModelClass:BouncerSignal,endpoint:"/api/account/bouncer/signal",size:25,...e})}}class BouncerSignature extends t{constructor(e={},t={}){super(e,{endpoint:"/api/account/bouncer/signature",...t})}}class BouncerSignatureList extends e{constructor(e={}){super({ModelClass:BouncerSignature,endpoint:"/api/account/bouncer/signature",size:25,...e})}}const j={create:{title:"Create Signature",fields:[{name:"sig_type",type:"select",label:"Signature Type",required:!0,columns:6,options:[{value:"user_agent",label:"User Agent"},{value:"ip_pattern",label:"IP Pattern"},{value:"fingerprint",label:"Fingerprint"},{value:"behavior",label:"Behavior"},{value:"header",label:"Header"},{value:"cookie",label:"Cookie"}]},{name:"value",type:"text",label:"Value",required:!0,columns:6,help:"The pattern or value to match against."},{name:"confidence",type:"number",label:"Confidence",columns:6,default:80,min:0,max:100,help:"Confidence level from 0 to 100."},{name:"notes",type:"textarea",label:"Notes",columns:12,help:"Optional notes about this signature."},{name:"is_active",type:"switch",label:"Active",columns:6,default:!0}]},edit:{title:"Edit Signature",fields:[{name:"sig_type",type:"select",label:"Signature Type",required:!0,columns:6,options:[{value:"user_agent",label:"User Agent"},{value:"ip_pattern",label:"IP Pattern"},{value:"fingerprint",label:"Fingerprint"},{value:"behavior",label:"Behavior"},{value:"header",label:"Header"},{value:"cookie",label:"Cookie"}]},{name:"value",type:"text",label:"Value",required:!0,columns:6,help:"The pattern or value to match against."},{name:"confidence",type:"number",label:"Confidence",columns:6,default:80,min:0,max:100,help:"Confidence level from 0 to 100."},{name:"notes",type:"textarea",label:"Notes",columns:12,help:"Optional notes about this signature."},{name:"is_active",type:"switch",label:"Active",columns:6,default:!0}]}};BouncerSignature.ADD_FORM=j.create,BouncerSignature.EDIT_FORM=j.edit;const J=[{value:"country",label:"Country — Block all traffic from a country"},{value:"abuse",label:"Abuse Feed — Import known attacker IPs"},{value:"datacenter",label:"Datacenter — Block datacenter/hosting ranges"},{value:"custom",label:"Custom — Define your own CIDR list"}],W=[{value:"country",label:"Country"},{value:"abuse",label:"Abuse Feed"},{value:"datacenter",label:"Datacenter"},{value:"custom",label:"Custom"}],H=[{value:"ipdeny",label:"IPDeny (Country Zones)"},{value:"abuseipdb",label:"AbuseIPDB"},{value:"manual",label:"Manual"}],U=[{value:"cn",label:"China"},{value:"ru",label:"Russia"},{value:"kp",label:"North Korea"},{value:"ir",label:"Iran"},{value:"ng",label:"Nigeria"},{value:"ro",label:"Romania"},{value:"br",label:"Brazil"},{value:"in",label:"India"},{value:"pk",label:"Pakistan"},{value:"id",label:"Indonesia"},{value:"vn",label:"Vietnam"},{value:"ua",label:"Ukraine"},{value:"th",label:"Thailand"},{value:"ph",label:"Philippines"},{value:"bd",label:"Bangladesh"},{value:"eg",label:"Egypt"},{value:"tr",label:"Turkey"},{value:"mx",label:"Mexico"},{value:"ar",label:"Argentina"},{value:"co",label:"Colombia"}];class IPSet extends t{constructor(e={}){super(e,{endpoint:"/api/incident/ipset"})}}class IPSetList extends e{constructor(e={}){super({ModelClass:IPSet,endpoint:"/api/incident/ipset",...e})}}const z={create:{title:"Create IP Set",size:"md",fields:[{name:"kind",type:"select",label:"What do you want to block?",required:!0,options:J,value:"country",columns:12},{name:"country_code",type:"select",label:"Country",required:!0,options:U,help:"Select a country to block. CIDRs are fetched automatically from IPDeny.",columns:8,showWhen:{field:"kind",value:"country"}},{name:"source_key",type:"text",label:"API Key",required:!0,placeholder:"Your AbuseIPDB API key",help:"Get a free key at abuseipdb.com. Never stored in plaintext.",columns:12,showWhen:{field:"kind",value:"abuse"}},{name:"source_url",type:"url",label:"Source URL",required:!0,placeholder:"https://example.com/datacenter-ranges.txt",help:"URL to a plain text file with one CIDR per line.",columns:12,showWhen:{field:"kind",value:"datacenter"}},{name:"data",type:"textarea",label:"CIDR List",rows:8,placeholder:"# One CIDR per line\n192.0.2.0/24\n198.51.100.0/24\n203.0.113.0/24",help:"Enter IP ranges in CIDR notation. Lines starting with # are ignored.",columns:12,showWhen:{field:"kind",value:"custom"}},{name:"name",type:"text",label:"Name",required:!0,placeholder:"e.g., abuse_ips, dc_aws",help:"Unique identifier. Used as the kernel ipset name.",columns:6,showWhen:{field:"kind",value:"country",negate:!0}},{name:"description",type:"text",label:"Description",placeholder:"Human-readable label",columns:6,showWhen:{field:"kind",value:"country",negate:!0}},{name:"is_enabled",type:"switch",label:"Enable immediately",value:!0,help:"When enabled, CIDRs are synced to the fleet and traffic is blocked.",columns:4}]},edit:{title:"Edit IP Set",size:"md",fields:[{name:"name",type:"text",label:"Name",required:!0,columns:6},{name:"kind",type:"select",label:"Kind",options:W,disabled:!0,columns:3},{name:"is_enabled",type:"switch",label:"Enabled",columns:3},{name:"description",type:"text",label:"Description",columns:12},{name:"source",type:"select",label:"Source",options:H,columns:6},{name:"source_url",type:"url",label:"Source URL",columns:6},{name:"source_key",type:"text",label:"API Key",placeholder:"Leave blank to keep current key",help:"Write-only — current value is never shown.",columns:12}]}};IPSet.EDIT_FORM=z.edit;class S3Bucket extends t{constructor(e={}){super(e,{endpoint:"/api/aws/s3/bucket"})}}class S3BucketList extends e{constructor(e={}){super({ModelClass:S3Bucket,endpoint:"/api/aws/s3/bucket",size:10,...e})}}const G={create:{title:"Add S3 Bucket",fields:[{name:"bucket_name",type:"text",label:"Name",placeholder:"bucket name",help:"Enter a universally unique name for the bucket",required:!0,cols:12},{name:"is_public",type:"switch",label:"Is Public",cols:12}]},edit:{title:"Edit S3 Bucket",fields:[{name:"bucket_name",type:"text",label:"Name",placeholder:"bucket name",help:"Enter a universally unique name for the bucket",required:!0,cols:12},{name:"is_public",type:"switch",label:"Is Public",cols:12}]}};S3Bucket.ADD_FORM=G.create,S3Bucket.EDIT_FORM=G.edit;class ScheduledTask extends t{constructor(e={},t={}){super(e,{endpoint:"/api/jobs/scheduled_task",...t})}}class ScheduledTaskList extends e{constructor(e={}){super({ModelClass:ScheduledTask,endpoint:"/api/jobs/scheduled_task",size:25,...e})}}class TaskResult extends t{constructor(e={},t={}){super(e,{endpoint:"/api/jobs/task_result",...t})}}class TaskResultList extends e{constructor(e={}){super({ModelClass:TaskResult,endpoint:"/api/jobs/task_result",size:25,...e})}}const V=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],K={create:{title:"Create Scheduled Task",fields:[{name:"name",type:"text",label:"Name",placeholder:"Daily report",required:!0,columns:12},{name:"description",type:"textarea",label:"Description",placeholder:"What this task does...",columns:12},{name:"task_type",type:"select",label:"Task Type",required:!0,columns:6,options:[{value:"llm",label:"LLM Prompt"},{value:"job",label:"Backend Job"},{value:"webhook",label:"Webhook"}]},{name:"enabled",type:"switch",label:"Enabled",columns:6,value:!0},{name:"run_times",type:"text",label:"Run Times (HH:MM)",placeholder:"09:00",required:!0,columns:6,help:'Comma-separated 24h times, max 2. e.g. "09:00, 17:00"'},{name:"run_days",type:"text",label:"Run Days",placeholder:"0,1,2,3,4",columns:6,help:"Comma-separated day numbers (Mon=0). Leave empty for every day."},{name:"run_once",type:"switch",label:"Run Once",columns:6,help:"Task runs once then disables itself."},{name:"max_retries",type:"number",label:"Max Retries",columns:6,value:0},{name:"notify",type:"text",label:"Notify",placeholder:"in_app, email",columns:12,help:"Comma-separated: email, in_app, sms, push"}]},edit:{title:"Edit Scheduled Task",fields:[{name:"name",type:"text",label:"Name",required:!0,columns:12},{name:"description",type:"textarea",label:"Description",columns:12},{name:"enabled",type:"switch",label:"Enabled",columns:6},{name:"run_times",type:"text",label:"Run Times (HH:MM)",required:!0,columns:6,help:"Comma-separated 24h times, max 2."},{name:"run_days",type:"text",label:"Run Days",columns:6,help:"Comma-separated day numbers (Mon=0). Leave empty for every day."},{name:"run_once",type:"switch",label:"Run Once",columns:6},{name:"max_retries",type:"number",label:"Max Retries",columns:6},{name:"notify",type:"text",label:"Notify",placeholder:"in_app, email",columns:12,help:"Comma-separated: email, in_app, sms, push"}]}};export{JobsEngineStats as $,AssistantConversationList as A,c as B,b as C,PublicMessageList as D,EmailDomainList as E,T as F,PhoneNumber as G,PhoneNumberList as H,IncidentEventList as I,Job as J,SMS as K,LoginEventList as L,u as M,SMSList as N,PhoneConfig as O,PushDeviceList as P,q as Q,RuleSet as R,SentMessage as S,TicketList as T,PhoneConfigList as U,PushDeliveryList as V,PushConfigList as W,PushTemplateList as X,PushDelivery as Y,F as Z,JobRunner as _,PushDeviceView as a,ActiveJobsList as a0,JobList as a1,JobLogList as a2,JobRunnerList as a3,JobEventList as a4,SimilarJobsList as a5,C as a6,BouncerSignal as a7,BouncerSignalList as a8,BouncerDevice as a9,IncidentRuleList as aA,IncidentRuleSet as aB,IncidentRuleSetList as aC,IncidentStats as aD,JobEvent as aE,JobLog as aF,LoginEvent as aG,M as aH,B as aI,P as aJ,R as aK,PushConfig as aL,f as aM,PushDevice as aN,PushTemplate as aO,w as aP,g as aQ,S3Bucket as aR,G as aS,ScheduledTaskList as aT,I as aU,TaskResult as aV,TaskResultList as aW,p as aX,BouncerDeviceList as aa,BouncerSignatureList as ab,IPSet as ac,W as ad,H as ae,z as af,IPSetList as ag,U as ah,S3BucketList as ai,AssistantSkill as aj,AssistantSkillList as ak,K as al,ScheduledTask as am,TicketNoteList as an,TicketNote as ao,BouncerSignature as ap,j as aq,m as ar,h as as,d as at,V as au,E as av,k as aw,J as ax,i as ay,IncidentRule as az,IncidentList as b,RuleList as c,y as d,IncidentHistoryList as e,IncidentHistory as f,AssistantConversation as g,Incident as h,RelatedIncidentsList as i,Ticket as j,r as k,x as l,v as m,Rule as n,_ as o,IncidentEvent as p,RuleSetList as q,EmailDomain as r,MailboxList as s,Mailbox as t,EmailTemplate as u,EmailTemplateList as v,SentMessageList as w,PublicMessage as x,D as y,L as z};
2
- //# sourceMappingURL=admin-models-CdOCWMEj.js.map
1
+ import{C as e,M as t,V as a,G as n,b as l,r as s}from"./User-DgB81g6W.js";import o from"./DataView-DhhTCP0d.js";class LoginEvent extends t{constructor(e={}){super(e,{endpoint:"/api/account/logins"})}}class LoginEventList extends e{constructor(e={}){super({ModelClass:LoginEvent,endpoint:"/api/account/logins",...e})}}class IncidentStats extends t{constructor(e={}){super(e,{endpoint:"/api/incident/stats",requiresId:!1})}}class IncidentEvent extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event"})}}class IncidentEventList extends e{constructor(e={}){super({ModelClass:IncidentEvent,endpoint:"/api/incident/event",size:10,...e})}}const i={edit:{title:"Edit Incident Event",fields:[{name:"category",type:"select",label:"Category",placeholder:"Select category",options:()=>Incident.COMPONENTS,editable:!0,force_top:!0,cols:6},{name:"incident",type:"text",label:"Incident",placeholder:"Enter Incident ID",cols:6},{name:"description",type:"textarea",label:"Description",placeholder:"Enter Description",cols:12},{name:"details",type:"textarea",label:"Details",placeholder:"Enter Details",cols:12},{name:"component",type:"text",label:"Component",placeholder:"Enter Component",cols:8},{name:"component_id",type:"text",label:"Component ID",placeholder:"Enter Component ID",cols:4}]}};class Incident extends t{constructor(e={}){super(e,{endpoint:"/api/incident/incident"})}}class IncidentList extends e{constructor(e={}){super({ModelClass:Incident,endpoint:"/api/incident/incident",size:10,...e})}}const r={create:{title:"Create Incident",fields:[{type:"tabset",name:"settingsTabs",tabs:[{label:"General",fields:[{name:"title",type:"text",label:"Title",required:!0,columns:12},{name:"details",type:"textarea",label:"Details",required:!0,columns:12}]},{label:"Advanced",fields:[{name:"priority",type:"select",label:"Priority",options:["1","2","3","4","5","6","7","8","9","10"],value:5,columns:6},{name:"status",type:"select",label:"Status",value:"open",options:["open","investigating","resolved","closed","paused","ignored"],columns:6},{name:"category",type:"text",label:"Category",value:"manual",columns:6}]},{label:"Metadata",fields:[{name:"metadata",type:"json",label:"Metadata",value:{example:"hello world"},rows:15,columns:12}]}]}]},edit:{title:"Edit Incident",fields:[{name:"category",type:"text",label:"Category",cols:6},{name:"status",type:"select",label:"Status",placeholder:"Select Status",options:["open","investigating","resolved","closed","paused","ignored"],cols:3},{name:"priority",type:"text",label:"Priority"},{name:"details",type:"textarea",label:"Description",placeholder:"Enter Name",cols:12},{name:"model_name",type:"text",label:"Model",placeholder:"Enter Model",cols:8},{name:"model_id",type:"text",label:"Model ID",placeholder:"Enter Model ID",cols:4}]}};class IncidentRuleSet extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset"})}}class IncidentRuleSetList extends e{constructor(e={}){super({ModelClass:IncidentRuleSet,endpoint:"/api/incident/event/ruleset",size:10,...e})}}class IncidentRule extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset/rule"})}}class IncidentRuleList extends e{constructor(e={}){super({ModelClass:IncidentRule,endpoint:"/api/incident/event/ruleset/rule",size:10,...e})}}class IncidentHistory extends t{constructor(e={}){super(e,{endpoint:"/api/incident/incident/history"})}}class IncidentHistoryList extends e{constructor(e={}){super({ModelClass:IncidentHistory,endpoint:"/api/incident/incident/history",size:10,...e})}}class RelatedIncidentsList extends IncidentList{constructor(e={}){const{sourceIp:t,ruleSet:a,group:n,hostname:l,category:s,status:o,params:i={},...r}=e;super({params:{ordering:"-modified",...null!=t?{source_ip:t}:{},...null!=a?{rule_set:a}:{},...null!=n?{group:n}:{},...null!=l?{hostname:l}:{},...null!=s?{category:s}:{},...null!=o?{status:o}:{},...i},...r})}}Incident.ADD_FORM=r.create,Incident.EDIT_FORM=r.edit,IncidentEvent.EDIT_FORM=i.edit;const c=[{value:0,label:"No Bundling"},{value:1,label:"By Hostname"},{value:2,label:"By Model Name"},{value:3,label:"By Model Name + ID"},{value:4,label:"By Source IP"},{value:5,label:"By Hostname + Model Name"},{value:6,label:"By Hostname + Model Name + ID"},{value:7,label:"By Source IP + Model Name"},{value:8,label:"By Source IP + Model Name + ID"},{value:9,label:"By Source IP + Hostname"}],u=[{value:0,label:"ALL (must match all rules)"},{value:1,label:"ANY (match any rule)"}],d=[{value:"==",label:"Equal (==)"},{value:"eq",label:"Equal (eq)"},{value:">",label:"Greater Than (>)"},{value:">=",label:"Greater Than or Equal (>=)"},{value:"<",label:"Less Than (<)"},{value:"<=",label:"Less Than or Equal (<=)"},{value:"contains",label:"Contains"},{value:"regex",label:"Regular Expression"}],p=[{value:"str",label:"String"},{value:"int",label:"Integer"},{value:"float",label:"Float"},{value:"bool",label:"Boolean"}],m=[{value:"level",label:"Level",description:"Event level (error, warning, info, debug)",meta:{type:"str"}},{value:"source_ip",label:"Source IP Address",description:"IP address of the event source",meta:{type:"str"}},{value:"rule_id",label:"Rule ID",description:"Numeric rule identifier",meta:{type:"int"}},{value:"hostname",label:"Hostname",description:"Hostname where event occurred",meta:{type:"str"}},{value:"component",label:"Component",description:"System component name",meta:{type:"str"}},{value:"component_id",label:"Component ID",description:"Component identifier",meta:{type:"str"}},{value:"category",label:"Category",description:"Event category (ossec, auth, api_error, etc.)",meta:{type:"str"}},{value:"description",label:"Description",description:"Event description text",meta:{type:"str"}},{value:"details",label:"Details",description:"Additional event details",meta:{type:"str"}},{value:"alert_id",label:"Alert ID",description:"Numeric alert identifier",meta:{type:"int"}},{value:"severity",label:"Severity",description:"Numeric severity level",meta:{type:"int"}},{value:"user",label:"User",description:"Username associated with event",meta:{type:"str"}},{value:"action",label:"Action",description:"Action that triggered the event",meta:{type:"str"}},{value:"status",label:"Status",description:"Status value or code",meta:{type:"str"}},{value:"status_code",label:"Status Code",description:"Numeric status code (e.g., HTTP status)",meta:{type:"int"}},{value:"message",label:"Message",description:"Event message text",meta:{type:"str"}},{value:"path",label:"Path",description:"File path or URL path",meta:{type:"str"}},{value:"title",label:"Title",description:"OSSEC Title",meta:{type:"str"}},{value:"country_code",label:"Country Code",description:"Country code associated with event",meta:{type:"str"}},{value:"region",label:"Region",description:"Region associated with event",meta:{type:"str"}},{value:"city",label:"City",description:"City associated with event",meta:{type:"str"}},{value:"http_user_agent",label:"HTTP User Agent",description:"User agent string associated with event",meta:{type:"str"}},{value:"request_path",label:"Request Path",description:"Request path associated with event",meta:{type:"str"}},{value:"method",label:"Method",description:"HTTP method or function name",meta:{type:"str"}}],b=["global","account","ossec","api","realtime","auth","login:unknown","invalid_password","sms:login_unknown","totp:login_unknown","reset:unknown","magic:unknown","token:unknown","api_denied","unauthenticated","view_permission_denied","edit_permission_denied","group_member_permission_denied","user_permission_denied","security_alert","totp:confirm_failed","totp:login_failed","totp:recovery_used","sms:otp_failed","email:no_mailbox","email:send_failed","sms:send_failed","email_change:bad_password","email_change:requested","account:deactivate_requested","phone_verify:invalid","email_verify:invalid","oauth:unlink_guard_error","rest_error","mojo_rest_error","rest_value_error"],h=b;class RuleSet extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset"})}}class RuleSetList extends e{constructor(e={}){super({ModelClass:RuleSet,endpoint:"/api/incident/event/ruleset",...e})}}const y=[{value:0,label:"Disabled — each event gets its own incident"},{value:5,label:"5 minutes"},{value:10,label:"10 minutes"},{value:15,label:"15 minutes"},{value:30,label:"30 minutes"},{value:60,label:"1 hour"},{value:120,label:"2 hours"},{value:360,label:"6 hours"},{value:720,label:"12 hours"},{value:1440,label:"1 day"},{value:null,label:"No limit — bundle forever"}],v={create:{title:"Create RuleSet",size:"lg",fields:[{type:"tabset",name:"rulesetTabs",tabs:[{label:"General",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"e.g., Brute Force Detection",columns:6},{name:"match_by",type:"select",label:"Match Logic",value:0,options:u,tooltip:"ALL = every condition must match. ANY = at least one",columns:6},{name:"category",type:"combo",label:"Scope / Category",required:!0,options:b,allowCustom:!0,placeholder:"Type or select...",tooltip:"Scope or event category to match. Use * as a catch-all",columns:6},{name:"priority",type:"number",label:"Evaluation Priority",value:10,required:!0,tooltip:"Lower number = evaluated first",columns:6},{name:"is_active",type:"switch",label:"Active",value:!0,tooltip:"Inactive rules are skipped during event processing",columns:6},{name:"metadata.delete_on_resolution",type:"switch",label:"Delete on Resolution",value:!1,tooltip:"Incidents are permanently deleted when resolved or closed (CASCADE)",columns:6}]},{label:"Bundling",fields:[{name:"bundle_by",type:"select",label:"Bundle By",value:4,options:c,tooltip:"How to group related events into one incident",columns:6},{name:"bundle_minutes",type:"select",label:"Bundle Window",value:30,options:y,tooltip:"Events outside this window create a new incident",columns:6},{name:"bundle_by_rule_set",type:"switch",label:"Bundle by RuleSet",value:!0,tooltip:"Group events matched by this rule into the same incident",columns:6}]},{label:"Thresholds",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-info-circle me-1"></i>\n <strong>How thresholds work:</strong> Events accumulate in "pending" status.\n Once trigger count is reached, the handler fires and the incident becomes "new".\n Leave empty to fire immediately on the first event.\n </div>'},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mb-1"><span class="badge bg-secondary me-1">1</span> Count — events before fire</div>'},{name:"trigger_count",type:"number",label:"",placeholder:"Empty = fire immediately on first event",tooltip:"Number of events before the handler fires",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">2</span> Within window — count only events in this many minutes</div>'},{name:"trigger_window",type:"number",label:"",placeholder:"Empty = count all events regardless of age",tooltip:"Only count events within this many minutes",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">3</span> Re-trigger — re-fire handler every N additional events</div>'},{name:"retrigger_every",type:"number",label:"",placeholder:"Empty = fire once only",tooltip:"Re-fire handler every N additional events after initial trigger",columns:12}]},{label:"Handler",fields:[{name:"handler",type:"text",label:"Handler Chain",placeholder:"e.g., block://?ttl=3600,ticket://?priority=8",tooltip:"Chain multiple handlers with commas",columns:12},{type:"html",columns:12,html:'<div class="alert alert-light border small mb-0">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>'}]},{label:"Agent",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-stars me-1"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>'},{name:"metadata.agent_prompt",type:"textarea",label:"Agent Prompt",rows:12,columns:12,placeholder:"You are a security analyst triaging…",tooltip:"Free-form prompt the LLM handler receives alongside the structured incident summary"}]}]}]},edit:{title:"Edit RuleSet",size:"lg",fields:[{type:"tabset",name:"rulesetTabs",tabs:[{label:"General",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"e.g., Brute Force Detection",columns:6},{name:"match_by",type:"select",label:"Match Logic",options:u,tooltip:"ALL = every condition must match. ANY = at least one",columns:6},{name:"category",type:"combo",label:"Scope / Category",options:b,allowCustom:!0,required:!0,placeholder:"Type or select...",tooltip:"Scope or event category to match. Use * as a catch-all",columns:6},{name:"priority",type:"number",label:"Evaluation Priority",required:!0,tooltip:"Lower number = evaluated first",columns:6},{name:"is_active",type:"switch",label:"Active",tooltip:"Inactive rules are skipped during event processing",columns:6},{name:"metadata.delete_on_resolution",type:"switch",label:"Delete on Resolution",tooltip:"Incidents are permanently deleted when resolved or closed (CASCADE)",columns:6}]},{label:"Bundling",fields:[{name:"bundle_by",type:"select",label:"Bundle By",options:c,tooltip:"How to group related events into one incident",columns:6},{name:"bundle_minutes",type:"select",label:"Bundle Window",options:y,tooltip:"Events outside this window create a new incident",columns:6},{name:"bundle_by_rule_set",type:"switch",label:"Bundle by RuleSet",tooltip:"Group events matched by this rule into the same incident",columns:6}]},{label:"Thresholds",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-info-circle me-1"></i>\n <strong>How thresholds work:</strong> Events accumulate in "pending" status.\n Once trigger count is reached, the handler fires and the incident becomes "new".\n Leave empty to fire immediately on the first event.\n </div>'},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mb-1"><span class="badge bg-secondary me-1">1</span> Count — events before fire</div>'},{name:"trigger_count",type:"number",label:"",placeholder:"Empty = fire immediately on first event",tooltip:"Number of events before the handler fires",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">2</span> Within window — count only events in this many minutes</div>'},{name:"trigger_window",type:"number",label:"",placeholder:"Empty = count all events regardless of age",tooltip:"Only count events within this window toward the trigger count",columns:12},{type:"html",columns:12,html:'<div class="text-muted small fw-semibold mt-3 mb-1"><span class="badge bg-secondary me-1">3</span> Re-trigger — re-fire handler every N additional events</div>'},{name:"retrigger_every",type:"number",label:"",placeholder:"Empty = fire once only",tooltip:"Re-fire handler every N additional events after initial trigger",columns:12}]},{label:"Handler",fields:[{name:"handler",type:"text",label:"Handler Chain",placeholder:"e.g., block://?ttl=3600,ticket://?priority=8",tooltip:"Chain multiple handlers with commas",columns:12},{type:"html",columns:12,html:'<div class="alert alert-light border small mb-0">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>'}]},{label:"Agent",fields:[{type:"html",columns:12,html:'<div class="alert alert-info small mb-3">\n <i class="bi bi-stars me-1"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>'},{name:"metadata.agent_prompt",type:"textarea",label:"Agent Prompt",rows:12,columns:12,placeholder:"You are a security analyst triaging…",tooltip:"Free-form prompt the LLM handler receives alongside the structured incident summary"}]}]}]}};class Rule extends t{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset/rule"})}}class RuleList extends e{constructor(e={}){super({ModelClass:Rule,endpoint:"/api/incident/event/ruleset/rule",...e})}}const g={create:{title:"Create Rule",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter rule name",cols:12},{name:"field_name",type:"combo",label:"Field Name",required:!0,placeholder:"Select or enter field name...",options:m,allowCustom:!0,showDescription:!0,help:"Select a common field or type a custom field name",cols:8},{name:"index",type:"select",label:"Index",required:!0,start:0,end:14,step:1,cols:4},{name:"comparator",type:"select",label:"Comparator",required:!0,options:d,cols:6},{name:"value_type",type:"select",label:"Value Type",required:!0,options:p,value:"str",cols:6},{name:"value",type:"textarea",label:"Value",required:!0,placeholder:"Enter comparison value",cols:12}]},edit:{title:"Edit Rule",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter rule name",cols:12},{name:"field_name",type:"combo",label:"Field Name",required:!0,placeholder:"Select or enter field name...",options:m,allowCustom:!0,showDescription:!0,help:"Select a common field or type a custom field name",cols:12},{name:"comparator",type:"select",label:"Comparator",required:!0,options:d,cols:6},{name:"value_type",type:"select",label:"Value Type",required:!0,options:p,cols:6},{name:"value",type:"text",label:"Value",required:!0,placeholder:"Enter comparison value",cols:12}]}};RuleSet.EDIT_FORM=v.edit,RuleSet.ADD_FORM=v.create,RuleSet.CREATE_FORM=v.create,RuleSet.BundleByOptions=c,RuleSet.MatchByOptions=u,Rule.EDIT_FORM=g.edit,Rule.ADD_FORM=g.create,Rule.CREATE_FORM=g.create,Rule.ComparatorOptions=d,Rule.ValueTypeOptions=p;class PushDeviceView extends a{constructor(e={}){super({className:"push-device-view",...e}),this.model=e.model}getTemplate(){return'\n <div class="p-3">\n <h3>{{model.device_name}}</h3>\n <p class="text-muted">{{model.user.display_name}}</p>\n <div data-container="data-view"></div>\n </div>\n '}onInit(){this.dataView=new o({containerId:"data-view",model:this.model,fields:[{name:"platform",label:"Platform",format:"badge"},{name:"push_enabled",label:"Push Enabled",format:"boolean"},{name:"app_version",label:"App Version"},{name:"os_version",label:"OS Version"},{name:"last_seen",label:"Last Seen",format:"datetime"},{name:"push_preferences",label:"Preferences",format:"json"}]}),this.addChild(this.dataView)}}class PushDevice extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push"})}}class PushDeviceList extends e{constructor(e={}){super({ModelClass:PushDevice,endpoint:"/api/account/devices/push",...e})}}class PushTemplate extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/templates"})}}class PushTemplateList extends e{constructor(e={}){super({ModelClass:PushTemplate,endpoint:"/api/account/devices/push/templates",...e})}}class PushConfig extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/config"})}}class PushConfigList extends e{constructor(e={}){super({ModelClass:PushConfig,endpoint:"/api/account/devices/push/config",...e})}}class PushDelivery extends t{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/deliveries"})}}class PushDeliveryList extends e{constructor(e={}){super({ModelClass:PushDelivery,endpoint:"/api/account/devices/push/deliveries",...e})}}const f={create:{title:"Create Push Configuration",fields:[{name:"name",label:"Name",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id"},{name:"fcm_service_account",label:"Service Account",type:"textarea",rows:10}]},edit:{title:"Edit Push Configuration",fields:[{name:"name",label:"Name",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id"},{name:"fcm_service_account",label:"Service Account",type:"textarea",rows:10},{name:"is_active",label:"Is Active",type:"switch",value:!0}]}},w={edit:{title:"Edit Push Template",fields:[{name:"name",label:"Name",required:!0},{name:"category",label:"Category",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id",defaultParams:{is_active:!0}},{name:"title_template",label:"Title Template",required:!0},{name:"body_template",label:"Body Template",type:"textarea",required:!0},{name:"action_url",label:"Action URL"},{name:"priority",label:"Priority",type:"select",options:["high","normal"]},{name:"variables",label:"Variables",type:"json",help:"JSON format"},{name:"is_active",label:"Is Active",type:"switch"}]}};f.create=f.edit,w.create=w.edit,PushConfig.ADD_FORM=f.create,PushConfig.EDIT_FORM=f.edit,PushTemplate.ADD_FORM=w.create,PushTemplate.EDIT_FORM=w.edit,PushDevice.VIEW_CLASS=PushDeviceView;class Ticket extends t{constructor(e={}){super(e,{endpoint:"/api/incident/ticket"})}}class TicketList extends e{constructor(e={}){super({ModelClass:Ticket,endpoint:"/api/incident/ticket",...e})}}const _={ticket:"Ticket",bug:"Bug",feature:"Feature Request",incident:"Incident",security:"Security Incident",fulfillment:"Fulfillment",new_user:"New User",new_group:"New Group",qa:"Quality Assurance"},S=Object.entries(_).map(([e,t])=>({value:e,label:t})),x={create:{title:"Create Ticket",fields:[{name:"title",type:"text",label:"Title",required:!0,cols:12},{name:"description",type:"textarea",label:"Description",required:!1,cols:12},{name:"category",type:"select",label:"Category",options:S,cols:12,value:"ticket"},{name:"priority",type:"number",label:"Priority",value:5,cols:6},{name:"status",type:"select",label:"Status",options:["new","open","paused","resolved","qa","ignored"],cols:6,value:"new"},{type:"collection",name:"assignee",label:"Assignee",Collection:l,labelField:"display_name",valueField:"id",cols:12},{type:"collection",name:"incident",label:"Incident",Collection:IncidentList,labelField:"title",valueField:"id",cols:12}]},edit:{title:"Edit Ticket",fields:[{name:"title",type:"text",label:"Title",required:!0,cols:12},{name:"category",type:"select",label:"Category",options:S,cols:12},{name:"priority",type:"number",label:"Priority",cols:6},{name:"status",type:"select",label:"Status",options:["new","open","paused","resolved","qa","ignored"],cols:6},{type:"collection",name:"assignee",label:"Assignee",Collection:l,labelField:"display_name",valueField:"id",cols:12},{type:"collection",name:"incident",label:"Incident",Collection:IncidentList,labelField:"title",valueField:"id",cols:12},{name:"enable_llm",type:"checkbox",label:"Enable AI agent",cols:12}]}};class TicketNote extends t{constructor(e={}){super(e,{endpoint:"/api/incident/ticket/note"})}}class TicketNoteList extends e{constructor(e={}){super({ModelClass:TicketNote,endpoint:"/api/incident/ticket/note",...e})}}Ticket.ADD_FORM=x.create,Ticket.EDIT_FORM=x.edit;class AssistantConversation extends t{constructor(e={}){super(e,{endpoint:"/api/assistant/conversation"})}}class AssistantConversationList extends e{constructor(e={}){super({ModelClass:AssistantConversation,endpoint:"/api/assistant/conversation",size:50,...e})}}class AssistantSkill extends t{constructor(e={}){super(e,{endpoint:"/api/assistant/skill"})}}class AssistantSkillList extends e{constructor(e={}){super({ModelClass:AssistantSkill,endpoint:"/api/assistant/skill",size:50,...e})}}class Job extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/job"})}async cancel(){const e=await this.save({cancel_request:!0});return e.success&&e.data.status&&this.set("cancel_requested",!0),e}async retry(e=null){const t=e?{retry_request:{retry:!0,delay:e}}:{retry_request:!0},a=await this.save(t);return a.success&&a.data.status&&a.data.new_job_id?{...a,newJobId:a.data.new_job_id,originalJobId:a.data.original_job_id}:a}async getDetailedStatus(){const e=await this.save({get_status:!0});return e.success&&e.data.status&&this.set(e.data.data),e}async cloneJob(e={}){const t={publish_job:{payload:e,...e}},a=await this.save(t);return a.success&&a.data.status&&a.data.job_id?{...a,newJobId:a.data.job_id,templateJobId:a.data.template_job_id}:a}isActive(){const e=this.get("status");return["pending","running"].includes(e)}isScheduled(){if("pending"!==this.get("status"))return!1;const e=this.get("run_at");if(!e)return!1;const t="number"==typeof e&&e<1e11?1e3*e:new Date(e).getTime();return Number.isFinite(t)&&t>Date.now()}isTerminal(){const e=this.get("status");return["completed","failed","canceled","expired"].includes(e)}canRetry(){const e=this.get("status");return["failed","canceled","expired"].includes(e)&&!1!==this.get("is_retriable")}canCancel(){const e=this.get("status");return["pending","running"].includes(e)&&!this.get("cancel_requested")}getStatusBadgeClass(){return{pending:"bg-primary",running:"bg-success",completed:"bg-info",failed:"bg-danger",canceled:"bg-secondary",expired:"bg-warning"}[this.get("status")]||"bg-secondary"}getStatusIcon(){return{pending:"bi-hourglass",running:"bi-arrow-repeat",completed:"bi-check-circle",failed:"bi-x-octagon",canceled:"bi-x-circle",expired:"bi-clock"}[this.get("status")]||"bi-question-circle"}getEvents(){return this.get("recent_events")||[]}getFormattedDuration(){const e=this.get("duration_ms");return e&&0!==e?e<1e3?`${e}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:e<36e5?`${(e/6e4).toFixed(1)}m`:`${(e/36e5).toFixed(1)}h`:"N/A"}getQueuePosition(){return this.get("queue_position")}hasExpired(){const e=this.get("expires_at");return!!e&&new Date(e)</* @__PURE__ */new Date}getRunnerId(){return this.get("runner_id")}getPayload(){return this.get("payload")||{}}getMetadata(){return this.get("metadata")||{}}}class JobList extends e{constructor(e={}){super({ModelClass:Job,endpoint:"/api/jobs/job",...e})}async fetchByStatus(e,t={}){return this.fetch({status:e,...t})}async fetchByChannel(e,t={}){return this.fetch({channel:e,...t})}async fetchPending(e={}){return this.fetchByStatus("pending",e)}async fetchRunning(e={}){return this.fetchByStatus("running",e)}async fetchCompleted(e={}){return this.fetchByStatus("completed",e)}async fetchFailed(e={}){return this.fetchByStatus("failed",e)}async fetchScheduled(e={}){return this.fetch({scheduled:!0,...e})}}const C={publish:{title:"Publish New Job",fields:[{name:"func",type:"text",label:"Function",required:!0,placeholder:"myapp.jobs.send_email",help:"Module path to job function"},{name:"channel",type:"text",label:"Channel",value:"default",help:'Queue channel (default: "default")'},{name:"payload",type:"textarea",label:"Payload (JSON)",required:!0,rows:8,placeholder:'{\n "key": "value"\n}',help:"JSON data passed to the job function"},{name:"delay",type:"number",label:"Delay (seconds)",min:0,help:"Delay execution by specified seconds"},{name:"run_at",type:"datetime-local",label:"Run At",help:"Schedule for specific date/time"},{name:"max_retries",type:"number",label:"Max Retries",value:3,min:0,max:10},{name:"expires_in",type:"number",label:"Expires In (seconds)",value:900,min:60,help:"Job will expire if not completed in this time"},{name:"broadcast",type:"switch",label:"Broadcast to All Workers",help:"Execute on all available workers"}]},retry:{title:"Retry Job",fields:[{name:"delay",type:"number",label:"Delay (seconds)",value:0,min:0,help:"Delay before retry (0 = immediate)"}]},clone:{title:"Clone Job",fields:[{name:"channel",type:"text",label:"Channel",help:"Override channel for cloned job"},{name:"payload",type:"textarea",label:"Modified Payload (JSON)",rows:8,help:"Modified payload for cloned job"},{name:"delay",type:"number",label:"Delay (seconds)",min:0}]}};Job.publish=async function(e){return await s.POST("/api/jobs/publish",e)},Job.getStats=async function(){const e=await s.GET("/api/jobs/stats");return e.success?e.data:null},Job.getHealth=async function(e=null){const t=e?`/api/jobs/health/${e}`:"/api/jobs/health",a=s.GET(t);return a.success?a.data:null},Job.test=async function(){return await s.POST("/api/jobs/test",{})},Job.tests=async function(){return await s.POST("/api/jobs/tests",{})},Job.clearStuck=async function(e=null){const t=e?{channel:e}:{};return await s.POST("/api/jobs/control/clear-stuck",t)},Job.clearChannel=async function(e){return await s.POST("/api/jobs/control/clear-queue",{channel:e,confirm:"yes"})},Job.cleanConsumers=async function(){return await s.POST("/api/jobs/control/cleanup-consumers")},Job.purgeJobs=async function(e){return await s.POST("/api/jobs/control/purge",{days_old:e})};class JobLog extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/logs"})}}class JobLogList extends e{constructor(e={}){super({endpoint:"/api/jobs/logs",model:JobLog,...e})}}class JobEvent extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/event"})}}class JobEventList extends e{constructor(e={}){super({endpoint:"/api/jobs/event",model:JobEvent,...e})}}class JobsEngineStats extends t{constructor(e={}){super(e,{endpoint:"/api/jobs/stats",requiresId:!1})}}class SimilarJobsList extends JobList{constructor(e={}){const{func:t,params:a={},...n}=e;super({params:{ordering:"-created",...t?{func:t}:{},...a},...n})}}class ActiveJobsList extends JobList{constructor(e={}){const{runnerId:t,params:a={},...n}=e;super({params:{status:"running",...null!=t?{runner_id:t}:{},...a},...n})}}class EmailDomain extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/domain",...t})}async onboard(e={},t={}){if(!this.id)return await this.showError("Cannot onboard domain without ID"),{success:!1,status:400,error:"Missing domain id"};try{const a=`${this.buildUrl(this.id)}/onboard`;return await this.rest.POST(a,e,t.params)}catch(a){return{success:!1,status:a?.status||500,error:a?.message||"Failed to onboard domain"}}}async audit(e={}){if(!this.id)return await this.showError("Cannot audit domain without ID"),{success:!1,status:400,error:"Missing domain id"};const t=(e.method||"GET").toUpperCase(),a=`${this.buildUrl(this.id)}/audit`;try{return"POST"===t?await this.rest.POST(a,e.data||{},e.params):await this.rest.GET(a,e.params)}catch(n){return{success:!1,status:n?.status||500,error:n?.message||"Failed to audit domain"}}}async reconcile(e={},t={}){if(!this.id)return await this.showError("Cannot reconcile domain without ID"),{success:!1,status:400,error:"Missing domain id"};try{const a=`${this.buildUrl(this.id)}/reconcile`;return await this.rest.POST(a,e,t.params)}catch(a){return{success:!1,status:a?.status||500,error:a?.message||"Failed to reconcile domain"}}}static async onboardById(e,t={},a={}){const n=new EmailDomain({id:e},a);return await n.onboard(t,a)}static async auditById(e,t={}){const a=new EmailDomain({id:e},t);return await a.audit(t)}static async reconcileById(e,t={},a={}){const n=new EmailDomain({id:e},a);return await n.reconcile(t,a)}}class EmailDomainList extends e{constructor(e={}){super({ModelClass:EmailDomain,endpoint:"/api/aws/email/domain",size:10,...e})}}const E={create:{title:"Add Email Domain",fields:[{name:"name",type:"text",label:"Domain Name",placeholder:"example.com",required:!0,columns:12,help:"Enter the root domain to verify with SES (no protocol)."},{name:"region",type:"text",label:"AWS Region (optional)",placeholder:"us-east-1",columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with SES permissions",columns:12,help:"Optional, AWS Key with SES permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with SES permissions",columns:12,help:"Optional, AWS Secret with SES permissions"},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12,help:"Catch-all SES receipt rule to S3 + SNS; routing is done in-app."}]},edit:{title:"Edit Email Domain",fields:[{name:"name",type:"text",label:"Domain Name",placeholder:"example.com",required:!0,columns:12,readonly:!0,help:"Domain name cannot be changed after creation."},{name:"region",type:"text",label:"AWS Region",placeholder:"us-east-1",columns:12},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12},{name:"s3_inbound_bucket",type:"text",label:"Inbound S3 Bucket",placeholder:"my-inbound-bucket",columns:12},{name:"s3_inbound_prefix",type:"text",label:"Inbound S3 Prefix",placeholder:"inbound/example.com/",columns:12},{name:"dns_mode",type:"select",label:"DNS Mode",options:[{value:"manual",text:"Manual (show records)"},{value:"godaddy",text:"GoDaddy (apply via API)"}],columns:12}]},credentials:{fields:[{name:"region",type:"select",label:"AWS Region (optional)",placeholder:"us-east-1",options:[{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with SES permissions",columns:12,help:"Optional, AWS Key with SES permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with SES permissions",columns:12,help:"Optional, AWS Secret with SES permissions"}]},onboard:{title:"Onboard Domain",fields:[{type:"header",text:"Receiving",level:6,className:"mt-2"},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12},{name:"s3_inbound_bucket",type:"text",label:"Inbound S3 Bucket",placeholder:"my-inbound-bucket",columns:12,help:"Required if receiving is enabled."},{name:"s3_inbound_prefix",type:"text",label:"Inbound S3 Prefix",placeholder:"inbound/example.com/",columns:12},{type:"header",text:"MAIL FROM (optional)",level:6,className:"mt-3"},{name:"ensure_mail_from",type:"switch",label:"Ensure MAIL FROM Setup",columns:12},{name:"mail_from_subdomain",type:"text",label:"MAIL FROM Subdomain",placeholder:"feedback",columns:12},{type:"header",text:"DNS",level:6,className:"mt-3"},{name:"dns_mode",type:"select",label:"DNS Mode",options:[{value:"manual",text:"Manual (show records)"},{value:"godaddy",text:"GoDaddy (apply via API)"}],value:"manual",columns:12},{name:"godaddy_key",type:"text",label:"GoDaddy API Key",columns:12,help:"Required when DNS Mode = GoDaddy."},{name:"godaddy_secret",type:"password",label:"GoDaddy API Secret",columns:12},{type:"header",text:"Webhook Endpoints",level:6,className:"mt-3"},{name:"endpoints.bounce",type:"text",label:"Bounce Endpoint",placeholder:"https://portal.example.com/api/aws/sns/bounce",columns:12},{name:"endpoints.complaint",type:"text",label:"Complaint Endpoint",placeholder:"https://portal.example.com/api/aws/sns/complaint",columns:12},{name:"endpoints.delivery",type:"text",label:"Delivery Endpoint",placeholder:"https://portal.example.com/api/aws/sns/delivery",columns:12},{name:"endpoints.inbound",type:"text",label:"Inbound Endpoint",placeholder:"https://portal.example.com/api/aws/sns/inbound",columns:12}]}};class Mailbox extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/mailbox",...t})}}Mailbox.sendEmail=async function(e){return await s.POST("/api/aws/email/send",e)};class MailboxList extends e{constructor(e={}){super({ModelClass:Mailbox,endpoint:"/api/aws/email/mailbox",size:10,...e})}}const M={create:{title:"Add Mailbox",fields:[{type:"collection",name:"domain",label:"Domain",Collection:EmailDomainList,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search domains...",emptyFetch:!1,required:!0,debounceMs:300,columns:12},{name:"email",type:"email",label:"Email Address",placeholder:"support@example.com",required:!0,columns:12},{name:"allow_inbound",type:"switch",label:"Allow Inbound",columns:6},{name:"allow_outbound",type:"switch",label:"Allow Outbound",defaultValue:!0,columns:6},{name:"is_system_default",type:"switch",label:"System Default",columns:6},{name:"is_domain_default",type:"switch",label:"Domain Default",columns:6},{name:"async_handler",type:"text",label:"Async Handler (optional)",placeholder:"myapp.handlers.process_support",columns:12,help:"Module:function to process inbound messages via task system"}]},edit:{title:"Edit Mailbox",fields:[{name:"email",type:"email",label:"Email Address",required:!0,columns:12},{name:"allow_inbound",type:"switch",label:"Allow Inbound",columns:6},{name:"allow_outbound",type:"switch",label:"Allow Outbound",columns:6},{name:"is_system_default",type:"switch",label:"System Default",columns:6},{name:"is_domain_default",type:"switch",label:"Domain Default",columns:6},{name:"async_handler",type:"text",label:"Async Handler (optional)",placeholder:"myapp.handlers.process_support",columns:12}]}};class SentMessage extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/sent",...t})}}class SentMessageList extends e{constructor(e={}){super({ModelClass:SentMessage,endpoint:"/api/aws/email/sent",size:10,...e})}}const I={view:{title:"Sent Message Details",fields:[{name:"id",type:"text",label:"ID",readonly:!0,cols:6},{name:"ses_message_id",type:"text",label:"SES Message ID",readonly:!0,cols:6},{name:"from_email",type:"text",label:"From",readonly:!0,cols:12},{name:"to",type:"textarea",label:"To",readonly:!0,rows:2,cols:12},{name:"cc",type:"textarea",label:"CC",readonly:!0,rows:2,cols:12},{name:"bcc",type:"textarea",label:"BCC",readonly:!0,rows:2,cols:12},{name:"subject",type:"text",label:"Subject",readonly:!0,cols:12},{name:"status",type:"text",label:"Status",readonly:!0,cols:6},{name:"status_reason",type:"textarea",label:"Status Reason",readonly:!0,rows:3,cols:12},{name:"created",type:"text",label:"Created",readonly:!0,cols:6}]}};class EmailTemplate extends t{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/template",...t})}}class EmailTemplateList extends e{constructor(e={}){super({ModelClass:EmailTemplate,endpoint:"/api/aws/email/template",size:10,...e})}}const k={create:{title:"Add Email Template",fields:[{name:"name",type:"text",label:"Name",required:!0,cols:12},{name:"subject_template",type:"text",label:"Subject Template",cols:12},{type:"tabset",name:"settingsTabs",tabs:[{label:"HTML",fields:[{name:"html_template",type:"htmlpreview",label:"HTML Template",rows:16,cols:12}]},{label:"TEXT",fields:[{name:"text_template",type:"textarea",label:"Text Template",rows:16,cols:12}]}]}]},edit:{title:"Edit Email Template",fields:[{name:"name",type:"text",label:"Name",required:!0,cols:12},{name:"subject_template",type:"text",label:"Subject Template",cols:12},{type:"tabset",name:"settingsTabs",tabs:[{label:"HTML",fields:[{name:"html_template",type:"textarea",label:"HTML Template",rows:16,cols:12}]},{label:"TEXT",fields:[{name:"text_template",type:"textarea",label:"Text Template",rows:16,cols:12}]}]}]}};EmailDomain.ADD_FORM=E.create,EmailDomain.EDIT_FORM=E.edit,Mailbox.ADD_FORM=M.create,Mailbox.EDIT_FORM=M.edit,EmailTemplate.ADD_FORM=k.create,EmailTemplate.EDIT_FORM=k.edit;const D=[{value:"contact_us",label:"Contact Us"},{value:"support",label:"Support"}],T=[{value:"open",label:"Open"},{value:"closed",label:"Closed"}],R=[{value:"low",label:"Low"},{value:"normal",label:"Normal"},{value:"high",label:"High"}],P=[{value:"billing",label:"Billing"},{value:"account",label:"Account"},{value:"bug",label:"Bug"},{value:"other",label:"Other"}],L={company:"Company",category:"Category",severity:"Severity",referrer:"Referrer",landing_page:"Landing Page",utm_source:"UTM Source",utm_medium:"UTM Medium",utm_campaign:"UTM Campaign",utm_term:"UTM Term",utm_content:"UTM Content"};class PublicMessage extends t{constructor(e={}){super(e,{endpoint:"/api/account/public_message"})}}class PublicMessageList extends e{constructor(e={}){super({ModelClass:PublicMessage,endpoint:"/api/account/public_message",size:25,...e})}}class PhoneNumber extends t{constructor(e={},t={}){super(e,{endpoint:"/api/phonehub/number",...t})}static async normalize(e,t="US"){const a={phone_number:e};t&&(a.country_code=t);const n=await s.POST("/api/phonehub/number/normalize",a),l=n?.data??n;return!0===l?.status||!0===l?.success?{success:!0,phone_number:l?.data?.phone_number??l?.phone_number,data:l?.data??l,response:n}:{success:!1,error:l?.error||"Normalization failed",response:n}}static async lookup(e,t={}){const a=await s.POST("/api/phonehub/number/lookup",{phone_number:e,...t}),n=a?.data??a;if(!0===n?.status||!0===n?.success){const e=n?.data??{};return{success:!0,model:new PhoneNumber(e,{endpoint:"/api/phonehub/number"}),data:e,response:a}}return{success:!1,error:n?.error||"Phone lookup failed",response:a}}}class PhoneNumberList extends e{constructor(e={}){super({ModelClass:PhoneNumber,endpoint:"/api/phonehub/number",size:10,...e})}}class SMS extends t{constructor(e={},t={}){super(e,{endpoint:"/api/phonehub/sms",...t})}static async send(e={}){const t=await s.POST("/api/phonehub/sms/send",e),a=t?.data??t;if(!0===a?.status||!0===a?.success){const e=a?.data??{};return{success:!0,model:new SMS(e,{endpoint:"/api/phonehub/sms"}),data:e,response:t}}return{success:!1,error:a?.error||"Failed to send SMS",response:t}}}class SMSList extends e{constructor(e={}){super({ModelClass:SMS,endpoint:"/api/phonehub/sms",size:10,...e})}}class PhoneConfig extends t{constructor(e={},t={}){super(e,{endpoint:"/api/phonehub/config",...t})}}class PhoneConfigList extends e{constructor(e={}){super({ModelClass:PhoneConfig,endpoint:"/api/phonehub/config",size:25,...e})}}const A=[{value:"twilio",label:"Twilio"},{value:"aws",label:"AWS SNS"},{value:"mojo",label:"Mojo Remote Instance"}],N="•••••••• (leave blank to keep existing)",O=[{name:"name",type:"text",label:"Name",required:!0,columns:8,placeholder:"e.g. Primary Twilio, Backup AWS, Mojo Bridge"},{type:"collection",name:"group",label:"Group",Collection:n,labelField:"name",valueField:"id",placeholder:"Search groups…",emptyFetch:!1,debounceMs:300,columns:4,help:"Leave blank for the System Default config."},{name:"provider",type:"select",label:"Provider",required:!0,options:A,columns:6},{name:"lookup_cache_days",type:"number",label:"Lookup cache (days)",columns:6,help:"Carrier-lookup cache lifetime per number."},{name:"is_active",type:"switch",label:"Active",columns:4},{name:"test_mode",type:"switch",label:"Test mode",columns:4,help:"Use the provider sandbox / test endpoint."},{name:"lookup_enabled",type:"switch",label:"Lookup",columns:4,help:"Auto-run carrier lookups on new numbers."},{type:"header",label:"Twilio credentials",columns:12,showWhen:{field:"provider",value:"twilio"}},{name:"twilio_from_number",type:"text",label:"Twilio From Number",placeholder:"+15551234567",columns:6,showWhen:{field:"provider",value:"twilio"}},{name:"twilio_account_sid",type:"password",label:"Twilio Account SID",placeholder:N,columns:6,autocomplete:"off",showWhen:{field:"provider",value:"twilio"}},{name:"twilio_auth_token",type:"password",label:"Twilio Auth Token",placeholder:N,columns:12,autocomplete:"new-password",showWhen:{field:"provider",value:"twilio"}},{type:"header",label:"AWS SNS credentials",columns:12,showWhen:{field:"provider",value:"aws"}},{name:"aws_region",type:"text",label:"AWS Region",value:"us-east-1",placeholder:"us-east-1",columns:6,showWhen:{field:"provider",value:"aws"}},{name:"aws_sender_id",type:"text",label:"Sender ID",placeholder:"Optional alphanumeric sender (region-dependent)",columns:6,showWhen:{field:"provider",value:"aws"}},{name:"aws_access_key_id",type:"password",label:"Access Key ID",placeholder:N,columns:6,autocomplete:"off",showWhen:{field:"provider",value:"aws"}},{name:"aws_secret_access_key",type:"password",label:"Secret Access Key",placeholder:N,columns:6,autocomplete:"new-password",showWhen:{field:"provider",value:"aws"}},{type:"header",label:"Mojo Remote credentials",columns:12,showWhen:{field:"provider",value:"mojo"}},{name:"mojo_remote_url",type:"url",label:"Remote Mojo URL",placeholder:"https://sms.example.com",columns:12,showWhen:{field:"provider",value:"mojo"}},{name:"mojo_api_key",type:"password",label:"Mojo API Key",placeholder:N,columns:12,autocomplete:"new-password",help:"Paste the token shown once when the API key was provisioned on the remote mojo. We never display it after save.",showWhen:{field:"provider",value:"mojo"}}],q={create:{title:"New Phone Config",fields:O,defaults:{provider:"twilio",is_active:!0,test_mode:!1,lookup_enabled:!0,lookup_cache_days:90}},edit:{title:"Edit Phone Config",fields:O}};PhoneConfig.ADD_FORM=q.create,PhoneConfig.EDIT_FORM=q.edit,PhoneConfig.SECRET_FIELDS=["twilio_account_sid","twilio_auth_token","aws_access_key_id","aws_secret_access_key","mojo_api_key"],PhoneConfig.PROVIDER_OPTIONS=A,PhoneConfig.FORM_DIALOG_CONFIG={size:"lg",submitText:"Create"};const B={PhoneNumber:PhoneNumber,PhoneNumberList:PhoneNumberList,SMS:SMS,SMSList:SMSList,PhoneConfig:PhoneConfig,PhoneConfigList:PhoneConfigList,PhoneConfigForms:q};class JobRunner extends t{constructor(e={}){e.runner_id&&!e.id&&(e.id=e.runner_id),super(e,{endpoint:"/api/jobs/runners",idAttribute:"runner_id"})}async ping(e=2){const t=this.getApp();if(!t||!t.rest)throw new Error("App or REST client not available");const a=await t.rest.POST("/api/jobs/runners/ping",{runner_id:this.get("runner_id"),timeout:e});return a.success&&a.data.status&&(this.set("last_heartbeat",/* @__PURE__ */(new Date).toISOString()),this.set("ping_status",a.data.ping_status||"success")),a}async shutdown(e=!0){const t=this.getApp();if(!t||!t.rest)throw new Error("App or REST client not available");const a=await t.rest.POST("/api/jobs/runners/shutdown",{runner_id:this.get("runner_id"),graceful:e});return a.success&&a.data.status&&this.set("alive",!1),a}getChannels(){return this.get("channels")||[]}getStatusBadgeClass(){return this.get("alive")?"bg-success":"bg-danger"}getStatusIcon(){return this.get("alive")?"bi-check-circle-fill":"bi-x-octagon-fill"}isActive(){return!0===this.get("alive")}isHealthy(){if(!this.isActive())return!1;const e=this.get("last_heartbeat");return!!e&&(Date.now()-new Date(e).getTime())/1e3<120}getFormattedHeartbeatAge(){const e=this.get("last_heartbeat");if(!e)return"Never";const t=(Date.now()-new Date(e).getTime())/1e3;return t<60?`${Math.round(t)}s ago`:t<3600?`${Math.round(t/60)}m ago`:`${Math.round(t/3600)}h ago`}getUtilization(){const e=(this.get("jobs_processed")||0)+(this.get("jobs_failed")||0);return e>10?100:Math.min(10*e,100)}getFormattedUptime(){const e=this.get("started");if(!e)return"Unknown";const t=new Date(e),a=/* @__PURE__ */new Date-t,n=Math.floor(a/1e3);return n<60?`${n}s`:n<3600?`${Math.floor(n/60)}m`:n<86400?`${Math.floor(n/3600)}h`:`${Math.floor(n/86400)}d`}getWorkerInfo(){const e=this.get("jobs_processed")||0,t=this.get("jobs_failed")||0;return{processed:e,failed:t,total:e+t,alive:this.get("alive"),utilization:this.getUtilization()}}getDisplayName(){const e=this.get("runner_id");if(!e)return"Unknown Runner";const t=e.split("-");return t.length>1?t[0]:e}canControl(){return!0===this.get("alive")}}class JobRunnerList extends e{constructor(e={}){super({ModelClass:JobRunner,endpoint:"/api/jobs/runners",...e})}getActive(){return this.where(e=>e.isActive())}getByChannel(e){return this.where(t=>t.getChannels().includes(e))}getHealthy(){return this.where(e=>e.isHealthy())}getTotalProcessed(){return this.models.reduce((e,t)=>e+(t.get("jobs_processed")||0),0)}getTotalFailed(){return this.models.reduce((e,t)=>e+(t.get("jobs_failed")||0),0)}getSystemHealth(){if(0===this.models.length)return 0;const e=this.models.filter(e=>e.get("alive")).length;return Math.round(e/this.models.length*100)}getAllChannels(){const e=/* @__PURE__ */new Set;return this.models.forEach(t=>{t.getChannels().forEach(t=>e.add(t))}),Array.from(e).sort()}}JobRunner.ping=async function(e,t=2){const a="undefined"!=typeof window&&window.app;if(!a||!a.rest)throw new Error("App or REST client not available");return await a.rest.POST("/api/jobs/runners/ping",{runner_id:e,timeout:t})},JobRunner.shutdown=async function(e,t=!0){const a="undefined"!=typeof window&&window.app;if(!a||!a.rest)throw new Error("App or REST client not available");return await a.rest.POST("/api/jobs/runners/shutdown",{runner_id:e,graceful:t})},JobRunner.broadcast=async function(e,t={},a=2){const n="undefined"!=typeof window&&window.app;if(!n||!n.rest)throw new Error("App or REST client not available");return await n.rest.POST("/api/jobs/runners/broadcast",{command:e,data:t,timeout:a})},JobRunner.broadcastStatus=async function(e=2){return JobRunner.broadcast("status",{},e)},JobRunner.broadcastShutdown=async function(e=2){return JobRunner.broadcast("shutdown",{},e)},JobRunner.broadcastPause=async function(e=2){return JobRunner.broadcast("pause",{},e)},JobRunner.broadcastResume=async function(e=2){return JobRunner.broadcast("resume",{},e)},JobRunner.broadcastReload=async function(e=2){return JobRunner.broadcast("reload",{},e)};const F={broadcast:{title:"Broadcast Command",fields:[{name:"command",type:"select",label:"Command",required:!0,options:[{value:"status",label:"Status Check"},{value:"pause",label:"Pause Processing"},{value:"resume",label:"Resume Processing"},{value:"reload",label:"Reload Configuration"},{value:"shutdown",label:"Shutdown All Runners"}],help:"Command to send to all runners"},{name:"timeout",type:"number",label:"Timeout (seconds)",value:2,min:.5,max:10,step:.5,help:"How long to wait for responses"}]}};class BouncerDevice extends t{constructor(e={},t={}){super(e,{endpoint:"/api/account/bouncer/device",...t})}}class BouncerDeviceList extends e{constructor(e={}){super({ModelClass:BouncerDevice,endpoint:"/api/account/bouncer/device",size:25,...e})}}class BouncerSignal extends t{constructor(e={},t={}){super(e,{endpoint:"/api/account/bouncer/signal",...t})}}class BouncerSignalList extends e{constructor(e={}){super({ModelClass:BouncerSignal,endpoint:"/api/account/bouncer/signal",size:25,...e})}}class BouncerSignature extends t{constructor(e={},t={}){super(e,{endpoint:"/api/account/bouncer/signature",...t})}}class BouncerSignatureList extends e{constructor(e={}){super({ModelClass:BouncerSignature,endpoint:"/api/account/bouncer/signature",size:25,...e})}}const j={create:{title:"Create Signature",fields:[{name:"sig_type",type:"select",label:"Signature Type",required:!0,columns:6,options:[{value:"user_agent",label:"User Agent"},{value:"ip_pattern",label:"IP Pattern"},{value:"fingerprint",label:"Fingerprint"},{value:"behavior",label:"Behavior"},{value:"header",label:"Header"},{value:"cookie",label:"Cookie"}]},{name:"value",type:"text",label:"Value",required:!0,columns:6,help:"The pattern or value to match against."},{name:"confidence",type:"number",label:"Confidence",columns:6,default:80,min:0,max:100,help:"Confidence level from 0 to 100."},{name:"notes",type:"textarea",label:"Notes",columns:12,help:"Optional notes about this signature."},{name:"is_active",type:"switch",label:"Active",columns:6,default:!0}]},edit:{title:"Edit Signature",fields:[{name:"sig_type",type:"select",label:"Signature Type",required:!0,columns:6,options:[{value:"user_agent",label:"User Agent"},{value:"ip_pattern",label:"IP Pattern"},{value:"fingerprint",label:"Fingerprint"},{value:"behavior",label:"Behavior"},{value:"header",label:"Header"},{value:"cookie",label:"Cookie"}]},{name:"value",type:"text",label:"Value",required:!0,columns:6,help:"The pattern or value to match against."},{name:"confidence",type:"number",label:"Confidence",columns:6,default:80,min:0,max:100,help:"Confidence level from 0 to 100."},{name:"notes",type:"textarea",label:"Notes",columns:12,help:"Optional notes about this signature."},{name:"is_active",type:"switch",label:"Active",columns:6,default:!0}]}};BouncerSignature.ADD_FORM=j.create,BouncerSignature.EDIT_FORM=j.edit;const J=[{value:"country",label:"Country — Block all traffic from a country"},{value:"abuse",label:"Abuse Feed — Import known attacker IPs"},{value:"datacenter",label:"Datacenter — Block datacenter/hosting ranges"},{value:"custom",label:"Custom — Define your own CIDR list"}],W=[{value:"country",label:"Country"},{value:"abuse",label:"Abuse Feed"},{value:"datacenter",label:"Datacenter"},{value:"custom",label:"Custom"}],H=[{value:"ipdeny",label:"IPDeny (Country Zones)"},{value:"abuseipdb",label:"AbuseIPDB"},{value:"manual",label:"Manual"}],U=[{value:"cn",label:"China"},{value:"ru",label:"Russia"},{value:"kp",label:"North Korea"},{value:"ir",label:"Iran"},{value:"ng",label:"Nigeria"},{value:"ro",label:"Romania"},{value:"br",label:"Brazil"},{value:"in",label:"India"},{value:"pk",label:"Pakistan"},{value:"id",label:"Indonesia"},{value:"vn",label:"Vietnam"},{value:"ua",label:"Ukraine"},{value:"th",label:"Thailand"},{value:"ph",label:"Philippines"},{value:"bd",label:"Bangladesh"},{value:"eg",label:"Egypt"},{value:"tr",label:"Turkey"},{value:"mx",label:"Mexico"},{value:"ar",label:"Argentina"},{value:"co",label:"Colombia"}];class IPSet extends t{constructor(e={}){super(e,{endpoint:"/api/incident/ipset"})}}class IPSetList extends e{constructor(e={}){super({ModelClass:IPSet,endpoint:"/api/incident/ipset",...e})}}const z={create:{title:"Create IP Set",size:"md",fields:[{name:"kind",type:"select",label:"What do you want to block?",required:!0,options:J,value:"country",columns:12},{name:"country_code",type:"select",label:"Country",required:!0,options:U,help:"Select a country to block. CIDRs are fetched automatically from IPDeny.",columns:8,showWhen:{field:"kind",value:"country"}},{name:"source_key",type:"text",label:"API Key",required:!0,placeholder:"Your AbuseIPDB API key",help:"Get a free key at abuseipdb.com. Never stored in plaintext.",columns:12,showWhen:{field:"kind",value:"abuse"}},{name:"source_url",type:"url",label:"Source URL",required:!0,placeholder:"https://example.com/datacenter-ranges.txt",help:"URL to a plain text file with one CIDR per line.",columns:12,showWhen:{field:"kind",value:"datacenter"}},{name:"data",type:"textarea",label:"CIDR List",rows:8,placeholder:"# One CIDR per line\n192.0.2.0/24\n198.51.100.0/24\n203.0.113.0/24",help:"Enter IP ranges in CIDR notation. Lines starting with # are ignored.",columns:12,showWhen:{field:"kind",value:"custom"}},{name:"name",type:"text",label:"Name",required:!0,placeholder:"e.g., abuse_ips, dc_aws",help:"Unique identifier. Used as the kernel ipset name.",columns:6,showWhen:{field:"kind",value:"country",negate:!0}},{name:"description",type:"text",label:"Description",placeholder:"Human-readable label",columns:6,showWhen:{field:"kind",value:"country",negate:!0}},{name:"is_enabled",type:"switch",label:"Enable immediately",value:!0,help:"When enabled, CIDRs are synced to the fleet and traffic is blocked.",columns:4}]},edit:{title:"Edit IP Set",size:"md",fields:[{name:"name",type:"text",label:"Name",required:!0,columns:6},{name:"kind",type:"select",label:"Kind",options:W,disabled:!0,columns:3},{name:"is_enabled",type:"switch",label:"Enabled",columns:3},{name:"description",type:"text",label:"Description",columns:12},{name:"source",type:"select",label:"Source",options:H,columns:6},{name:"source_url",type:"url",label:"Source URL",columns:6},{name:"source_key",type:"text",label:"API Key",placeholder:"Leave blank to keep current key",help:"Write-only — current value is never shown.",columns:12}]}};IPSet.EDIT_FORM=z.edit;class S3Bucket extends t{constructor(e={}){super(e,{endpoint:"/api/aws/s3/bucket"})}}class S3BucketList extends e{constructor(e={}){super({ModelClass:S3Bucket,endpoint:"/api/aws/s3/bucket",size:10,...e})}}const G={create:{title:"Add S3 Bucket",fields:[{name:"bucket_name",type:"text",label:"Name",placeholder:"bucket name",help:"Enter a universally unique name for the bucket",required:!0,cols:12},{name:"is_public",type:"switch",label:"Is Public",cols:12}]},edit:{title:"Edit S3 Bucket",fields:[{name:"bucket_name",type:"text",label:"Name",placeholder:"bucket name",help:"Enter a universally unique name for the bucket",required:!0,cols:12},{name:"is_public",type:"switch",label:"Is Public",cols:12}]}};S3Bucket.ADD_FORM=G.create,S3Bucket.EDIT_FORM=G.edit;class ScheduledTask extends t{constructor(e={},t={}){super(e,{endpoint:"/api/jobs/scheduled_task",...t})}}class ScheduledTaskList extends e{constructor(e={}){super({ModelClass:ScheduledTask,endpoint:"/api/jobs/scheduled_task",size:25,...e})}}class TaskResult extends t{constructor(e={},t={}){super(e,{endpoint:"/api/jobs/task_result",...t})}}class TaskResultList extends e{constructor(e={}){super({ModelClass:TaskResult,endpoint:"/api/jobs/task_result",size:25,...e})}}const V=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],K={create:{title:"Create Scheduled Task",fields:[{name:"name",type:"text",label:"Name",placeholder:"Daily report",required:!0,columns:12},{name:"description",type:"textarea",label:"Description",placeholder:"What this task does...",columns:12},{name:"task_type",type:"select",label:"Task Type",required:!0,columns:6,options:[{value:"llm",label:"LLM Prompt"},{value:"job",label:"Backend Job"},{value:"webhook",label:"Webhook"}]},{name:"enabled",type:"switch",label:"Enabled",columns:6,value:!0},{name:"run_times",type:"text",label:"Run Times (HH:MM)",placeholder:"09:00",required:!0,columns:6,help:'Comma-separated 24h times, max 2. e.g. "09:00, 17:00"'},{name:"run_days",type:"text",label:"Run Days",placeholder:"0,1,2,3,4",columns:6,help:"Comma-separated day numbers (Mon=0). Leave empty for every day."},{name:"run_once",type:"switch",label:"Run Once",columns:6,help:"Task runs once then disables itself."},{name:"max_retries",type:"number",label:"Max Retries",columns:6,value:0},{name:"notify",type:"text",label:"Notify",placeholder:"in_app, email",columns:12,help:"Comma-separated: email, in_app, sms, push"}]},edit:{title:"Edit Scheduled Task",fields:[{name:"name",type:"text",label:"Name",required:!0,columns:12},{name:"description",type:"textarea",label:"Description",columns:12},{name:"enabled",type:"switch",label:"Enabled",columns:6},{name:"run_times",type:"text",label:"Run Times (HH:MM)",required:!0,columns:6,help:"Comma-separated 24h times, max 2."},{name:"run_days",type:"text",label:"Run Days",columns:6,help:"Comma-separated day numbers (Mon=0). Leave empty for every day."},{name:"run_once",type:"switch",label:"Run Once",columns:6},{name:"max_retries",type:"number",label:"Max Retries",columns:6},{name:"notify",type:"text",label:"Notify",placeholder:"in_app, email",columns:12,help:"Comma-separated: email, in_app, sms, push"}]}};export{JobsEngineStats as $,AssistantConversationList as A,c as B,b as C,PublicMessageList as D,EmailDomainList as E,T as F,PhoneNumber as G,PhoneNumberList as H,IncidentEventList as I,Job as J,SMS as K,LoginEventList as L,u as M,SMSList as N,PhoneConfig as O,PushDeviceList as P,q as Q,RuleSet as R,SentMessage as S,TicketList as T,PhoneConfigList as U,PushDeliveryList as V,PushConfigList as W,PushTemplateList as X,PushDelivery as Y,F as Z,JobRunner as _,PushDeviceView as a,ActiveJobsList as a0,JobList as a1,JobLogList as a2,JobRunnerList as a3,JobEventList as a4,SimilarJobsList as a5,C as a6,BouncerSignal as a7,BouncerSignalList as a8,BouncerDevice as a9,IncidentRuleList as aA,IncidentRuleSet as aB,IncidentRuleSetList as aC,IncidentStats as aD,JobEvent as aE,JobLog as aF,LoginEvent as aG,M as aH,B as aI,P as aJ,R as aK,PushConfig as aL,f as aM,PushDevice as aN,PushTemplate as aO,w as aP,g as aQ,S3Bucket as aR,G as aS,ScheduledTaskList as aT,I as aU,TaskResult as aV,TaskResultList as aW,p as aX,BouncerDeviceList as aa,BouncerSignatureList as ab,IPSet as ac,W as ad,H as ae,z as af,IPSetList as ag,U as ah,S3BucketList as ai,AssistantSkill as aj,AssistantSkillList as ak,K as al,ScheduledTask as am,TicketNoteList as an,TicketNote as ao,BouncerSignature as ap,j as aq,m as ar,h as as,d as at,V as au,E as av,k as aw,J as ax,i as ay,IncidentRule as az,IncidentList as b,RuleList as c,y as d,IncidentHistoryList as e,IncidentHistory as f,AssistantConversation as g,Incident as h,RelatedIncidentsList as i,Ticket as j,r as k,x as l,v as m,Rule as n,_ as o,IncidentEvent as p,RuleSetList as q,EmailDomain as r,MailboxList as s,Mailbox as t,EmailTemplate as u,EmailTemplateList as v,SentMessageList as w,PublicMessage as x,D as y,L as z};
2
+ //# sourceMappingURL=admin-models-C8VPjEPG.js.map