@dialstack/sdk-native 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -8,28 +8,10 @@ pieces (`<DialPad>` / `<IncomingCall>` / `<OngoingCall>`).
8
8
  import { Softphone, SoftphoneProvider } from '@dialstack/sdk-native';
9
9
  ```
10
10
 
11
- ## Why a separate package (not `@dialstack/sdk/native`)
12
-
13
- This is a distinct package from `@dialstack/sdk` **on purpose**: it declares the
14
- React Native peer dependencies. Keeping them here means the web SDK's dependency
15
- graph is _structurally_ free of anything React Native — a web app that installs
16
- `@dialstack/sdk` can never pull `react-native-webrtc`/`-svg`/`-incall-manager`.
17
-
18
- `@dialstack/sdk-native` is self-contained: it inlines its own compiled copy of
19
- the shared headless calling core and call-state hooks at build time, so it has
20
- **no runtime dependency on `@dialstack/sdk`** (the core is authored once in that
21
- package and shared at build time only). The core is written to the standard
22
- browser WebRTC surface (`RTCPeerConnection`, `MediaStream`, `navigator.mediaDevices`);
23
- call `registerGlobals()` from your WebRTC package at your app's entry point so
24
- that surface exists on React Native before the SDK runs. The two RN-only gaps —
25
- outbound ringback audio and E911 persistence — are supplied by the softphone
26
- provider (an InCallManager-backed ringback and your `storage` adapter).
27
-
28
- ```js
29
- // index.js — before anything imports the SDK
30
- import { registerGlobals } from 'react-native-webrtc';
31
- registerGlobals();
32
- ```
11
+ React components for the web live in
12
+ [`@dialstack/sdk-react`](https://www.npmjs.com/package/@dialstack/sdk-react).
13
+ This package is self-contained: install it alone, and nothing from the web SDK
14
+ comes with it.
33
15
 
34
16
  ## Install
35
17
 
@@ -52,8 +34,99 @@ globals `registerGlobals()` installs, so any spec-compliant build works. The
52
34
  `react-native-webrtc` peer is **optional** precisely so a differently-named
53
35
  package can satisfy it without npm installing a second copy alongside.
54
36
 
55
- See the example apps under `../mobile/` for a runnable Expo app and a bare React
56
- Native app.
37
+ > **Installing our fork from GitHub:** its entry points are generated by its
38
+ > `prepare` script at install time. If your npm or CI blocks install scripts,
39
+ > the package installs without them and the failure surfaces later as
40
+ > `Cannot find module`, not as an install error — allow install scripts for
41
+ > that dependency.
42
+
43
+ ### Install the WebRTC globals
44
+
45
+ The SDK core is written to the standard browser WebRTC surface
46
+ (`RTCPeerConnection`, `MediaStream`, `navigator.mediaDevices`), so call
47
+ `registerGlobals()` from your WebRTC package at your app's entry point, before
48
+ anything imports the SDK:
49
+
50
+ ```js
51
+ // index.js
52
+ import { registerGlobals } from 'react-native-webrtc';
53
+ registerGlobals();
54
+ ```
55
+
56
+ Two RN-only gaps — outbound ringback audio and E911 persistence — are supplied
57
+ by the softphone provider (an InCallManager-backed ringback and your `storage`
58
+ adapter).
59
+
60
+ ## Permissions (required)
61
+
62
+ **Without microphone permission a call fails with `Call failed` and no other
63
+ symptom** — `getUserMedia` never runs, so there is nothing else to see. Declare
64
+ these before your first call.
65
+
66
+ ### Expo
67
+
68
+ ```json
69
+ {
70
+ "expo": {
71
+ "plugins": ["@config-plugins/react-native-webrtc"],
72
+ "android": {
73
+ "permissions": [
74
+ "android.permission.RECORD_AUDIO",
75
+ "android.permission.MODIFY_AUDIO_SETTINGS",
76
+ "android.permission.INTERNET",
77
+ "android.permission.ACCESS_NETWORK_STATE",
78
+ "android.permission.VIBRATE"
79
+ ]
80
+ },
81
+ "ios": {
82
+ "infoPlist": {
83
+ "NSMicrophoneUsageDescription": "… needs the microphone to place and receive calls.",
84
+ "UIBackgroundModes": ["audio", "voip"]
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ `react-native-webrtc` is a native module, so it needs a **development build** —
92
+ it cannot run in Expo Go. Re-run `expo prebuild` after changing any of the above.
93
+
94
+ The config plugin also injects permissions of its own that this SDK does not use
95
+ — including `CAMERA`, `SYSTEM_ALERT_WINDOW` and `BLUETOOTH` — and writes a
96
+ default camera-usage string. If a store listing or privacy review asks about
97
+ them, drop the ones you don't need with Expo's
98
+ [`android.blockedPermissions`](https://docs.expo.dev/versions/latest/config/app/#blockedpermissions).
99
+
100
+ ### Bare React Native
101
+
102
+ `android/app/src/main/AndroidManifest.xml`:
103
+
104
+ ```xml
105
+ <uses-permission android:name="android.permission.INTERNET" />
106
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
107
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
108
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
109
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
110
+ <uses-permission android:name="android.permission.VIBRATE" />
111
+ ```
112
+
113
+ `VIBRATE` is what gives the incoming call its haptic buzz: Android enforces it
114
+ by throwing rather than no-op'ing, so without it the call still rings but never
115
+ vibrates. The SDK catches that throw, so omitting the permission degrades
116
+ gracefully — it does not break the call. Neither `react-native` nor
117
+ `react-native-incall-manager` declares it, so your app must.
118
+
119
+ `ios/<YourApp>/Info.plist`:
120
+
121
+ ```xml
122
+ <key>NSMicrophoneUsageDescription</key>
123
+ <string>… needs the microphone to place and receive calls.</string>
124
+ <key>UIBackgroundModes</key>
125
+ <array>
126
+ <string>audio</string>
127
+ <string>voip</string>
128
+ </array>
129
+ ```
57
130
 
58
131
  ## DTMF
59
132
 
@@ -68,7 +141,7 @@ npm install 'github:dialstack/react-native-webrtc#7e9a0eb55e068b2ba452f22e02e4b7
68
141
  With any other WebRTC package — including LiveKit's and Stream's forks, neither
69
142
  of which exposes `RTCRtpSender.dtmf` — `Call.canSendDtmf` is `false`, the in-call
70
143
  keypad stays hidden, `Call.sendDtmf()` throws `call_failed`, and the SDK logs
71
- `[dialstack] DTMF is unavailable …` on the first call. Calls are otherwise
144
+ `[dialstack] DTMF is unavailable …` once per app process. Calls are otherwise
72
145
  unaffected, but there is no way to navigate an IVR or phone tree. That is the
73
146
  tradeoff to weigh if another library forces a particular WebRTC package on you.
74
147
 
@@ -96,10 +169,17 @@ const storage: PlatformStorage = {
96
169
  </SoftphoneProvider>;
97
170
  ```
98
171
 
99
- The Expo `../examples/mobile/expo` app ships this MMKV adapter; the bare
100
- `../examples/mobile/bare` app ships an AsyncStorage one. Either works —
101
172
  `storage` just needs `getItem`/`setItem`/`removeItem`.
102
173
 
174
+ ## Example apps
175
+
176
+ Two runnable apps, both wired with the permissions and plugin above:
177
+
178
+ - [Expo](https://github.com/dialstack/dialstack-sdk/tree/main/examples/mobile/expo)
179
+ — ships the MMKV storage adapter
180
+ - [Bare React Native](https://github.com/dialstack/dialstack-sdk/tree/main/examples/mobile/bare)
181
+ — ships an AsyncStorage adapter
182
+
103
183
  ## Scope
104
184
 
105
185
  This package provides the in-app calling surface: the provider, the call state,
package/dist/index.js CHANGED
@@ -508,8 +508,8 @@ function warnMissingDtmfBridgeOnce() {
508
508
  return;
509
509
  warnedMissingDtmfBridge = true;
510
510
  logWarn('DTMF is unavailable: the audio sender exposes no RTCDTMFSender. On React ' +
511
- "Native, install DialStack's react-native-webrtc fork (which adds " +
512
- 'RTCRtpSender.dtmf) — see the @dialstack/sdk-native README.');
511
+ "Native, use DialStack's react-native-webrtc fork, or any WebRTC package " +
512
+ 'that implements RTCRtpSender.dtmf — see the @dialstack/sdk-native README.');
513
513
  }
514
514
  // Always `exact` for a real request: Chrome's own device-picker preference overrides
515
515
  // `ideal`, so a lenient constraint can silently capture a mic that was never asked for
@@ -4579,7 +4579,7 @@ function resolveSoftphonePalette(appearance) {
4579
4579
  };
4580
4580
  }
4581
4581
 
4582
- "function"==typeof SuppressedError&&SuppressedError;const m={common:{loading:"Loading...",error:"Error",noResults:"No results",delete:"Delete",call:"Call",cancel:"Cancel",confirm:"Confirm",previous:"Previous",next:"Next",perPage:"Per page",showing:"Showing {start}-{end} of {total}",play:"Play",pause:"Pause"},softphone:{title:"Softphone",destinationPlaceholder:"Enter a number",call:"Call",backspace:"Delete",connecting:"Connecting…",reconnecting:"Reconnecting…",disconnected:"Disconnected",connectionError:"Connection error",callError:"Call failed",micPermissionError:"Microphone access is required — allow it and try again",dismiss:"Dismiss",unknownCaller:"Unknown",incomingCall:"Incoming call",answer:"Answer",decline:"Decline",hangUp:"Hang up",mute:"Mute",unmute:"Unmute",hold:"Hold",resume:"Resume",keypad:"Keypad",transfer:"Transfer",transferPlaceholder:"Transfer to…",transferSend:"Transfer",transferNow:"Transfer now",transferConsult:"Consult first",transferComplete:"Complete transfer",transferConsulting:"Consulting…",transferOriginalOnHold:"On hold",addCall:"Add call",addCallPlaceholder:"Number to dial",addCallSend:"Call",cancel:"Cancel",stateTrying:"Calling…",stateRinging:"Ringing…",stateActive:"In call",stateHeld:"On hold",stateEnded:"Call ended",done:"Done",audioDevices:"Audio",audioMicrophone:"Microphone",audioSpeaker:"Speaker",audioSystemDefault:"System default",audioUnnamedDevice:"Unnamed device",audioLabelsHidden:"Allow microphone access to see device names",audioDevicesUnsupported:"This browser cannot list audio devices",audioSpeakerUnsupported:"Choose your speaker in your device settings",audioMicrophoneLost:"Your microphone was disconnected — choose another",switchToCall:"Switch to this call",heldCallsLabel:"On hold",callWaiting:"Call waiting",emergencyPrompt:"Set your emergency location to be able to place external calls",emergencyHint:"Confirm your location before placing calls — required by 911 regulations for internet calling.",emergencyConfirm:"Yes, I'm here",emergencyNewLocation:"Set a new location",emergencyUseLocation:"Use my current location",emergencyLocating:"Getting your location…",emergencyNumber:"Number",emergencyStreet:"Street",emergencyUnit:"Unit (optional)",emergencyCity:"City",emergencyState:"State",emergencyPostalCode:"Postal code",emergencySave:"Confirm location",emergencySaving:"Saving…",emergencyBack:"Back"},aiAgent:{loading:"Loading AI agent…",loadFailed:"Failed to load AI agent: {message}",fields:{name:"Name",namePlaceholder:"Front Desk Agent",nameHint:"Internal label shown in lists and call logs. Not heard by callers.",extensionNumber:"Extension",extensionNumberPlaceholder:"700",extensionNumberHint:"Dial this extension from any phone on the account to reach the agent.",extensionChecking:"Checking extension...",personaName:"Persona name",personaNamePlaceholder:"e.g. Receptionist",personaNameHint:"How the agent introduces itself on calls.",greetingName:"Greeting name",greetingNamePlaceholder:"Your business name",greetingNameHintWithName:'Used in the call greeting (e.g. "Thanks for calling {name}").',greetingNameHintGeneric:'Used in the call greeting (e.g. "Thanks for calling [your business]").',instructions:"Instructions",instructionsPlaceholder:"Provide additional instructions for how the AI agent should behave during calls...",instructionsHint:"Plain-English guidance for the agent: tone, what to do, what to escalate.",faq:"FAQ",faqEmpty:"No FAQ entries yet. Add one to teach the agent a recurring question.",faqEntry:"Entry {index}",faqQuestion:"Question",faqAnswer:"Answer",faqQuestionLabel:"FAQ entry {index} question",faqAnswerLabel:"FAQ entry {index} answer",faqRemove:"Remove",faqRemoveLabel:"Remove FAQ entry {index}",faqAdd:"Add FAQ entry",scheduling:"Scheduling",schedulingHint:"Connect your AI agent to an external scheduling system. Clear the URL to disable scheduling.",webhookUrl:"Webhook URL",webhookUrlHint:"Base URL for scheduling webhooks. DialStack appends tool-call paths automatically.",webhookUrlPlaceholder:"https://example.com/api/dialstack/webhooks",secret:"Webhook secret",secretHint:"Used to verify tool-call webhooks sent from this AI agent to your integration.",copySecret:"Copy webhook secret",rotateSecret:"Rotate secret"},save:"Save",saving:"Saving…",saved:"Saved.",errors:{nameRequired:"Name is required.",nameMaxLength:"Name must be {max} characters or fewer.",personaNameMaxLength:"Persona name must be {max} characters or fewer.",greetingNameMaxLength:"Greeting name must be {max} characters or fewer.",instructionsMaxLength:"Instructions must be {max} characters or fewer.",faqMaxItems:"FAQ supports up to {max} entries.",faqIncompleteEntry:"Every FAQ entry needs both a question and an answer.",faqFieldMaxLength:"FAQ fields must be {max} characters or fewer.",extensionNumeric:"Extension must contain only digits.",extensionUnavailable:"Extension number is already in use.",schedulingUrlMaxLength:"Webhook URL must be {max} characters or fewer.",schedulingUrlHttpsRequired:"Webhook URL must start with https://.",hostCreateRequired:"This form is waiting for the host app to create the AI agent.",hostSaveRequired:"This form is waiting for the host app to save the AI agent."}},voicemails:{title:"Voicemails",loading:"Loading voicemails...",empty:"No voicemails",noUserId:"Please set a user ID to load voicemails",transcription:"Transcription",summary:"Summary",sentiment:"Sentiment",sentimentPositive:"Positive",sentimentNeutral:"Neutral",sentimentNegative:"Negative",sentimentMixed:"Mixed",transcript:"Full Transcript",transcriptLoading:"Loading transcript...",transcriptNotAvailable:"Transcript not available",deleteConfirm:"Delete this voicemail?",deleteTitle:"Delete Voicemail",progress:"Playback progress"},callLogs:{title:"Call Logs",loading:"Loading call logs...",empty:"No call logs found",columns:{date:"Date",direction:"Direction",from:"From",to:"To",duration:"Duration",status:"Status",quality:"MOS"},directions:{inbound:"Inbound",outbound:"Outbound",internal:"Internal"},routedTo:"Routed to:",calledBy:"Called by:",statuses:{completed:"Completed",noAnswer:"No Answer",busy:"Busy",failed:"Failed",voicemail:"Voicemail"},quality:{good:"Good",fair:"Fair",poor:"Poor",unavailable:"N/A",unavailableTooltip:"No quality data available"}},callHistory:{title:"Call History",loading:"Loading call history...",empty:"No call history",noPhoneNumber:"Please set a phone number to load call history",error:"Unable to load call history",clickToCall:"Click to call",summaryNotAvailable:"Summary not available",relativeTime:{justNow:"Just now",minuteAgo:"1 min ago",minutesAgo:"{count} min ago",hourAgo:"1 hour ago",hoursAgo:"{count} hours ago",yesterday:"Yesterday"}},phoneNumberOrdering:{title:"Order Phone Numbers",steps:{search:"Search",select:"Select",confirm:"Confirm",route:"Route",done:"Done",stepOf:"Step {current} of {total}"},search:{title:"Search Available Numbers",subtitle:"Find available phone numbers by entering an area code or ZIP code.",searchType:"Search by",areaCode:"Area Code",zip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"e.g. 212",zipLabel:"ZIP Code",zipPlaceholder:"e.g. 10001",numberOfResults:"Quantity to display",search:"Search"},results:{title:"Available Numbers",phoneNumber:"Phone Number",state:"State",selectAll:"Select all",selected:"{count} selected",noResults:"No numbers available for this search",continue:"Continue",backToSearch:"Back to Search"},confirm:{title:"Confirm Order",subtitleOne:"You are about to order 1 phone number",subtitleOther:"You are about to order {count} phone numbers",description:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",continue:"Continue",back:"Back",billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:"{count} phone numbers at {rate} each per month.",detail_one:"{count} phone number at {rate} per month.",detail_other:"{count} phone numbers at {rate} each per month.",timing:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",noPrice:"These numbers are billable on this account.",noPrice_one:"This number is billable on this account.",noPrice_other:"These numbers are billable on this account.",notBilled:"This account is not billed, so ordering these numbers costs nothing."}},route:{title:"Choose call routing",subtitle:"Pick where these numbers should send calls once they activate. You can change this any time, or set it up later.",later:"Set up routing later",laterHint:"Configure each number from its detail page after it activates.",noTargets:"No routing destinations exist yet. You can set up routing after the numbers are added.",unnamed:"Untitled",extension:"ext. {ext}",back:"Back",type:{user:"User",dial_plan:"Dial plan",voice_app:"Voice app",queue:"Queue",ring_group:"Ring group",shared_voicemail:"Shared voicemail"}},ordering:{title:"Placing Order..."},complete:{titlePendingOne:"Order Submitted",titlePendingOther:"Order Submitted",titleCompleteOne:"Number Ready",titleCompleteOther:"Numbers Ready",titlePartialOne:"Partially Fulfilled",titlePartialOther:"Partially Fulfilled",descriptionPendingOne:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionPendingOther:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionCompleteOne:"Your phone number is now in your inventory and ready to be configured.",descriptionCompleteOther:"Your phone numbers are now in your inventory and ready to be configured.",descriptionPartialOne:"Some numbers could not be fulfilled by the carrier.",descriptionPartialOther:"Some numbers could not be fulfilled by the carrier.",checking:"Checking order status...",assignmentHint:"Numbers added to your inventory still need to be assigned to an extension or dial plan before they can receive calls.",orderMore:"Order More Numbers"},error:{title:"Order Failed",description:"The carrier was unable to fulfill your order.",tryAgain:"Try Again"},statuses:{pending:"Pending",complete:"Complete",partial:"Partial",failed:"Failed"}},phoneNumbers:{title:"Phone Numbers",loading:"Loading phone numbers...",empty:"No phone numbers",filterLabel:"Filter by status",search:{placeholder:"Search phone numbers...",noResults:"No phone numbers match your search"},filters:{active:"Active",in_progress:"In Progress",cancelled:"Cancelled"},columns:{phoneNumber:"Phone Number",status:"Status",callerID:"Outbound Caller ID",callerIDPrefix:"Inbound Caller ID Prefix",outbound:"Usage",carrier:"Carrier",transferDate:"Transfer Date",routingTarget:"Call Routing",cancelledDate:"Date Cancelled"},statuses:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",orderFailed:"Order Failed",portingDraft:"Port Draft",portingApproved:"Ready to Submit",portingSubmitted:"Port Submitted",portingException:"Port Issue",portingFoc:"Port Scheduled"},badges:{temporary:"Temporary"},outbound:{enabled:"Two-way",disabled:"Inbound only",fax:"Fax"},routingTarget:{notSet:"Not set",setAction:"Set routing",faxNotApplicable:"Not applicable"},routingTargetTypes:{user:"User",dialPlan:"Dial Plan",voiceApp:"Voice App",ringGroup:"Ring Group"}},accountOnboarding:{billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:{userSeat:{one:"{count} user seat at {rate} per month.",other:"{count} user seats at {rate} each per month."},phoneNumber:{one:"{count} phone number at {rate} per month.",other:"{count} phone numbers at {rate} each per month."}},noPrice:{userSeat:{one:"Adds {count} billable user seat to this account.",other:"Adds {count} billable user seats to this account."},phoneNumber:{one:"Adds {count} billable phone number to this account.",other:"Adds {count} billable phone numbers to this account."}},rateHeadline:{userSeat:"{rate}/month per user seat",phoneNumber:"{rate}/month per phone number"},rateDetail:{userSeat:"Each team member you add is billed at this rate.",phoneNumber:"Each number you add is billed at this rate."},noPriceRate:{userSeat:"Each team member you add is billable on this account.",phoneNumber:"Each number you add is billable on this account."},startsOnActivation:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed, so this costs nothing."},title:"Account Onboarding",breadcrumbAriaLabel:"Onboarding progress",loading:"Loading...",error:{title:"Unable to Load",description:"Something went wrong loading the onboarding wizard.",retry:"Try Again"},steps:{account:"Account Setup",numbers:"Phone Numbers",hardware:"Hardware Setup",complete:"Complete"},sidebar:{businessDetails:"Business Details",businessDetailsDesc:"Enter your company information",teamMembers:"Team Members",teamMembersDesc:"Add users and assign extensions",numberOptions:"Number Options",numberOptionsDesc:"Choose to port existing or get new numbers",callerId:"Caller ID",callerIdDesc:"Set caller ID for your numbers",directoryListing:"Directory Listing",directoryListingDesc:"Configure 411 directory listing",numberSetup:"Number Setup",numberSetupDesc:"Configure your phone numbers",verification:"Verification",verificationDesc:"Verify number status",deviceAssignment:"Device Assignment",deviceAssignmentDesc:"Assign devices to users"},account:{title:"Business Details",subtitle:"Enter your company information",details:{heading:"Account Details",companyNameLabel:"Company Name",companyNamePlaceholder:"Acme Corp",companyNameRequired:"Company name is required",emailLabel:"Primary Contact Email",emailPlaceholder:"admin@company.com",emailRequired:"Primary contact email is required",emailInvalid:"Enter a valid email address",phoneLabel:"Primary Contact Phone Number",phonePlaceholder:"(555) 123-4567",phoneRequired:"Primary contact phone number is required",phoneInvalid:"Enter a valid US phone number",primaryContactLabel:"Primary Contact",primaryContactPlaceholder:"Jane Doe",primaryContactRequired:"Primary contact is required",regionLabel:"Region",regionPlaceholder:"Select a region",timezoneLabel:"Timezone",timezonePlaceholder:"Select a timezone",timezoneRequired:"Timezone is required"},users:{heading:"Team Members",description:"Add users who will have phone extensions",nameLabel:"Full name",namePlaceholder:"John Doe",nameRequired:"Name is required",emailLabel:"Email",emailPlaceholder:"john@company.com",extensionLabel:"Extension",extensionPlaceholder:"ex. 103",addUser:"Add User",removeUser:"Remove",noUsers:"No team members added yet.",atLeastOne:"Add at least one team member to continue.",duplicateEmail:"A user with this email already exists."},location:{heading:"Business Location",description:"Add your business address for E911 and caller ID.",nameLabel:"Location Name",namePlaceholder:"Main Office",nameRequired:"Location name is required",addressLabel:"Address",searchPlaceholder:"Start typing an address...",searching:"Searching...",noResults:"No addresses found",enterManually:"Enter manually",searchInstead:"Search instead",edit:"Edit",addressRequired:"Address is required",houseNumberLabel:"#",houseNumberPlaceholder:"123",streetLabel:"Street",streetPlaceholder:"Main St",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select",postalCodeLabel:"ZIP",postalCodePlaceholder:"10001"},saving:"Saving...",saveError:"Failed to save. Please try again."},numbers:{title:"Phone Numbers",subtitle:"Choose how you'd like to set up your business numbers",defaultDialPlanName:"Onboarding Dial Plan",callerId:{title:"Caller ID Setup",subtitle:"Configure the name displayed when making outbound calls",inputLabel:"Caller ID Name",inputPlaceholder:"e.g. ACME Corp",inputHelp:"Max 15 characters. Letters, numbers, spaces, and hyphens only.",charCount:"{count}/15",submit:"Set Caller ID",submitting:"Submitting...",submittingAll:"Submitting caller IDs...",submitted:"Submitted",alreadySet:"Already configured",submitAll:"Set All Caller IDs",skipCallerId:"Skip",partialError:"Some caller IDs could not be set. Fix errors and retry, or skip.",validation:{required:"Caller ID name is required",tooLong:"Must be 15 characters or fewer",invalidChars:"Only letters, numbers, spaces, and hyphens allowed"},error:{submitFailed:"Failed to set caller ID. Please try again.",conflict:"A caller ID update is already in progress for this number."},directoryListing:{title:"Directory Listing (DA/DL)",info:"To update your directory listing, contact {platformName} support."},noDIDs:"No active phone numbers to configure."},directoryListing:{title:"Directory Listing",subtitle:"A directory listing feeds your business information into online directories and data aggregators, helping customers find you. It also reduces the chance of your outbound calls being flagged as spam by call-screening apps.",selectPrompt:"Select which number should be listed:",noneOption:"None — skip directory listing",noDIDs:"No eligible phone numbers to configure.",businessName:"Business Name",businessNamePlaceholder:"Enter business name for listing",businessNameHelp:"The name shown in directory listings and used for caller verification. Max 200 characters.",validation:{nameRequired:"Business name is required for the directory listing."}},overview:{heading:"Your Numbers",empty:"No telephone numbers yet. Request new numbers or port your existing ones.",requestNew:"Request New Numbers",requestNewDesc:"Get new business phone numbers instantly. Choose from available numbers in your area.",portExisting:"Port Existing Number",portExistingDesc:"Transfer your current business number to {platformName}. This typically takes 5–10 business days.",phoneNumber:"Phone Number",type:"Type",status:"Status",source:"Source",temporaryBanner:"A temporary number has been assigned to your account while you set up your permanent numbers.",loadError:"Failed to load telephone numbers. Please try again.",retry:"Retry"},status:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",order_failed:"Order Failed",porting_draft:"Port Draft",porting_submitted:"Port Submitted",porting_exception:"Port Exception",porting_foc:"Port Scheduled",porting_approved:"Ready to Submit"},source:{did:"Account",didTemporary:"Temporary",number_order:"New Order",port_order:"Port"},order:{searchTitle:"Search Available Numbers",searchSubtitle:"Find available numbers by entering an area code or ZIP code",searchByAreaCode:"Area Code",searchByZip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"212",zipLabel:"ZIP Code",zipPlaceholder:"10001",quantityLabel:"Quantity",search:"Search",searching:"Searching...",resultsTitle:"Available Numbers",resultsSubtitle:"Select the numbers you would like to order.",noResults:"No numbers found. Try a different search.",selectAll:"Select All",deselectAll:"Deselect All",selected:"selected",state:"State",confirmTitle:"Confirm Your Order",confirmSubtitle:"You are about to order {count} phone numbers",confirmSubtitle_one:"You are about to order {count} phone number",confirmSubtitle_other:"You are about to order {count} phone numbers",carrierNote:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",placing:"Placing Order...",ordering:"Ordering...",statusTitle:"Order Submitted",statusPending:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusStalled:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusComplete:"Your numbers have been activated.",statusFailed:"The order could not be completed.",statusPartial:"Some numbers were activated, but others failed.",done:"Done",orderMore:"Order More Numbers",continue:"Continue",error:"An error occurred while placing the order."},port:{numbersTitle:"Numbers to Port",numbersSubtitle:"Enter the numbers you want to transfer to {platformName}, or paste a whole list into any row.",phoneLabel:"Phone Number",phonePlaceholder:"(555) 123-4567",addAnother:"Add another number",numberLabel:"Phone number {row}",removeNumber:"Remove phone number {row}",duplicateOfRow:"Duplicate of row {row}",pasteHint:"Press Enter for another row. Pasting a list — one per line, commas, or a spreadsheet column — fills a row for each number.",readyCountZero:"No numbers yet",readyCountOne:"{count} number ready",readyCountOther:"{count} numbers ready",needsAttentionOne:"{count} row needs attention before you can continue",needsAttentionOther:"{count} rows need attention before you can continue",reasonInvalid:"Not a valid US phone number",reasonNotUs:"Only US numbers can be ported",reasonTollFree:"Toll-free numbers cannot be ported",reasonAmbiguous:"Too many digits for one number — if this is several, put one per row",reasonHasExtension:"Remove the extension",maxPerOrder:"{count} numbers — the maximum is {max} per order. Move {excess} into a second port order.",notPortableWithDetail:"{label} ({detail})",accountLimit:"You've reached the number of phone numbers this account can hold. Contact support to raise the limit, then try again.",numbersUnavailable:"Some of these numbers are already in use and can't be ported. The ones affected are marked above.",conflictAlreadyOnAccount:"You already have this number",conflictInServiceElsewhere:"Already in service — contact support to transfer it",checkEligibility:"Check Eligibility",checking:"Checking...",eligibilityTitle:"Port Eligibility",eligibilitySubtitle:"Review which numbers can be ported.",portable:"Portable",notPortable:"Not Portable",carrier:"Current Carrier",wireless:"Wireless",wirelessYes:"Yes",wirelessNo:"No",accountRequired:"Account # Required",continueWithPortable:"Continue with Portable Numbers",noPortable:"None of the entered numbers are eligible for porting.",subscriberTitle:"Subscriber Information",subscriberSubtitle:"Enter the details exactly as they appear on your current phone bill.",btnLabel:"Billing Telephone Number (BTN)",btnPlaceholder:"(555) 123-4567",businessNameLabel:"Business Name",businessNamePlaceholder:"Acme Corp",approverNameLabel:"Authorized Contact",approverNamePlaceholder:"John Doe",accountNumberLabel:"Account Number",accountNumberPlaceholder:"From your current carrier",pinLabel:"Account PIN",pinPlaceholder:"1234",addressHeading:"Service Address",houseNumberLabel:"Street Number",houseNumberPlaceholder:"123",streetNameLabel:"Street Name",streetNamePlaceholder:"Main St",line2Label:"Suite / Unit",line2Placeholder:"Suite 100",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select state",zipLabel:"ZIP Code",zipPlaceholder:"10001",focTitle:"Requested Port Date",focSubtitle:"Choose when you want the numbers transferred. Must be at least 5 business days out.",focDateLabel:"Port Date",focTimeLabel:"Port Time (Eastern)",focTimePlaceholder:"Select time",documentsTitle:"Supporting Documents",documentsSubtitle:"Upload your latest phone bill and optionally a Customer Service Record (CSR).",billCopyLabel:"Phone Bill Copy",billCopyDesc:"A recent bill from your current carrier showing the numbers to be ported.",billCopyRequired:"Required",csrLabel:"Customer Service Record (CSR)",csrDesc:"Optional but recommended — speeds up the porting process.",csrOptional:"Optional",uploadFile:"Choose File",fileSelected:"Selected:",noFileSelected:"No file selected",uploading:"Uploading...",reviewTitle:"Review & Approve",reviewSubtitle:"Verify all details before submitting your port request.",numbersSection:"Numbers",subscriberSection:"Subscriber",focSection:"Port Date",documentsSection:"Documents",signatureLabel:"Electronic Signature",signaturePlaceholder:"Type your full legal name",signatureHelp:"By signing, you authorize the transfer of the listed numbers to {platformName}.",approve:"Approve & Submit",submitting:"Submitting...",submittedTitle:"Port Request Submitted",submittedSubtitle:"Your port request has been submitted and is being processed.",submittedStatus:"Status",backToOverview:"Back to Numbers",carrierGroupsTitle:"Carrier Groups",carrierGroupsSubtitle:"Your numbers are with different carriers. Each carrier requires a separate port request.",carrierStart:"Start",carrierContinue:"Continue",carrierSubmitted:"Submitted",numberSingular:"number",numberPlural:"numbers"},validation:{areaCodeRequired:"Area code is required.",areaCodeFormat:"Enter a 3-digit area code.",cityRequired:"City is required.",stateRequired:"State is required.",zipRequired:"ZIP code is required.",zipFormat:"Enter a 5-digit ZIP code.",selectAtLeastOne:"Select at least one number.",phoneRequired:"At least one phone number is required.",phoneInvalid:"Enter a valid US phone number.",phoneDuplicate:"This number has already been entered.",btnRequired:"BTN is required.",btnInvalid:"Enter a valid US phone number.",businessNameRequired:"Business name is required.",approverNameRequired:"Authorized contact name is required.",houseNumberRequired:"Street number is required.",streetNameRequired:"Street name is required.",focDateRequired:"Port date is required.",focDateTooSoon:"Port date must be at least 5 business days from today.",focDateTooFar:"Port date must be within 30 days.",focTimeRequired:"Port time is required.",billCopyRequired:"A phone bill copy is required.",signatureRequired:"Signature is required.",eligibilityError:"Failed to check eligibility. Please try again.",submitError:"Failed to submit port request. Please try again."},nav:{back:"Back",next:"Next",cancel:"Cancel",backToSearch:"Back to Search",confirm:"Confirm"},gate:{noDIDsAvailable:"You need at least one phone number before selecting a primary number. Order or port a number first.",primaryRequired:"Please select a primary number to continue."}},hardware:{title:"Assign Devices",shippingAddress:"Shipping Address",subtitle:"Drag and drop devices to assign them to team members",noUsers:"No team members found. Add team members in the Account step first.",noDevices:"No devices are available for your account at the moment.",isDectBase:"This is a cordless handset base station",userLabel:"Team Member",selectUser:"Select a team member",selectUserRequired:"Please select a team member.",macLabel:"MAC Address",macPlaceholder:"00:04:13:AA:BB:CC",invalidMac:"Enter a valid 12-digit MAC address.",ipeiLabel:"Handset IPEI",ipeiPlaceholder:"03AABB1234567890CCDD",invalidIpei:"Enter a valid IPEI (hex digits only).",ipeiNotMac:"This looks like a MAC address, not an IPEI. An IPEI looks like 03AABB1234567890CCDD.",removeDevice:"Remove",unsupportedVendor:"This device is not currently supported. Our support team has been notified and will follow up.",duplicateMac:"This MAC address is already registered.",deviceNotFound:"Device was created but could not be found. Please try again.",handset:"handset",handsets:"handsets",addDeviceButton:"+ Add Device",addHandsetButton:"+ Handset",save:"Save",saving:"Saving...",cancel:"Cancel",dectBase:"Cordless Base",removeBaseFailed:"Failed to remove cordless base.",tableHeaderName:"Full name",tableHeaderExtension:"Extension",tableHeaderDevice:"Assigned Device",availableDevices:"Available Devices",allAssigned:"All devices have been assigned",dragDropHint:"Drag and drop device here",clickToAssign:"Click to assign",submitOrder:"Submit Order",assignAndComplete:"Save & Continue",unassign:"Unassign",deskPhone:"Desk phone",cordless:"Cordless",submitting:"Submitting...",gate:{noDevices:"No devices are available for your account. Please contact support to add devices before completing this step."}},complete:{title:"Wahoo!",subtitle:"It's time to start using your embedded voice system",e911:{loading:"Configuring emergency services...",pollingStatus:"Verifying emergency services registration...",verified:"E911 emergency address is verified.",processing:"E911 registration is being processed. This may take a few minutes.",pendingAfterPolling:"E911 registration submitted. Your phone service is active — emergency address verification will complete shortly.",addressStandardized:"Your address was standardized for emergency services accuracy.",primaryAssigned:"assigned as primary number for",errorTitle:"E911 configuration failed",errorDescription:"There was an error configuring emergency services. You can retry or configure manually later.",retryButton:"Retry",deferred:"E911 emergency services have not been fully configured. Each location with a phone number needs a verified emergency address before your phone service can be activated."}},stepComplete:{title:"{stepName} Complete",subtitle:"This step has been completed successfully.",done:"Done"},nav:{next:"Next",skip:"Skip",back:"Back",exit:"Finish"},legal:{prefix:"By continuing, you agree to the",and:"and",termsOfService:"Terms of Service",recipientTerms:"Recipient Terms of Service",privacyPolicy:"Privacy Policy"},ssa:{title:"Review and accept your subscription agreement",intro:"Before you can use your phone service, please review the Service Subscription Agreement below — including its emergency calling (911/E911) terms — and confirm your acceptance.",pricingTitle:"Your plan pricing",perUser:"Per user",perNumber:"Per phone number",perAiLocation:"Per AI location",perMonthSuffix:"/mo",agreementLabel:"Service Subscription Agreement",openInNewTab:"Open the full agreement in a new tab",accept:"Accept & Continue",submitting:"Recording your acceptance…",notPermitted:"Only the account owner can accept this agreement. Please ask them to sign in and accept it — phone service stays blocked until they do.",errors:{stale:"The agreement was updated. Please review the latest version and accept again.",pricingMissing:"Your plan pricing has not been finalized yet. Please contact your provider to continue.",generic:"We could not record your acceptance. Please try again.",retry:"Try again"},loadError:{title:"Unable to load your agreement",description:"We could not load your subscription agreement, which is required before you can continue. Please try again.",retry:"Try again",retrying:"Loading…"}}},onboardingPortal:{onboardingFlows:"ONBOARDING FLOWS",saveAndExit:"Save & Exit to Overview",back:"Back",helpSupport:"Help & Support",onboardingComplete:"Onboarding complete",rates:{title:"Your monthly rates",subtitle:"What you're billed at today.",perUser:"Per user",perPhoneNumber:"Per phone number",perVoiceAiLocation:"Per VoiceAI location",perMonth:"{rate}/month",rateNotSet:"Not set",pendingRate:"{rate}/month from {date}",pendingNote:"Rate changes take effect at the start of the next billing period.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed.",noRates:"No rates are set for this account yet.",unavailable:"Rates are unavailable right now."},overview:{label:"Overview",title:"Your Business Onboarding",subtitle:"Complete the steps below to set up your business phone system",progressTitle:"Onboarding Progress",flowsComplete:"{completed} of {total} flows complete",stepsTitle:"Onboarding Steps",complete:"Complete",progress:"Progress",completeSetup:"Complete Setup",continueSetup:"Continue Setup",review:"Review",needHelp:"Need help?",needHelpSubtitle:"Our team is here to help you get set up quickly",scheduleCall:"Schedule a Call",viewDocs:"View Documentation",accountDesc:"Set up your business profile, add team members, and configure your dial plan",numbersDesc:"Port existing numbers or request new business lines",hardwareDesc:"Assign phones to team members and track delivery",phoneStatusTitle:"Phone number status",phoneStatusSubtitle:"Track the status of your phone numbers",phoneStatusNumber:"Phone Number",phoneStatusType:"Type",phoneStatusStatus:"Status",phoneStatusTypeNew:"New",phoneStatusTypePort:"Port",phoneStatusProcessing:"Processing",phoneStatusComplete:"Complete",phoneStatusTemporary:"Temporary"},splash:{title:"Welcome\nto {platformName}",subtitle:"Let's get your business set up in 3 easy steps",start:"Start Onboarding",step1:"Account Details",step2:"Setup Phone Numbers",step3:"Assign Hardware"}},dialPlan:{title:"Dial Plan",loading:"Loading dial plan...",error:"Failed to load dial plan",empty:"No dial plan found",nodeTypes:{start:"Start",schedule:"Schedule",internalDial:"Internal Extension",voicemail:"Voicemail",externalDial:"External Number",voiceApp:"Voice App",menu:"IVR Menu",audioClip:"Audio Clip",hangUp:"Hang Up"},nodeDescriptions:{menu:"Play prompt and route by keypress",audioClip:"Play an audio clip",hangUp:"End the call"},exits:{open:"Open",closed:"Closed",holiday:"Holiday",next:"Next",timeout:"Timeout",invalid:"Invalid"},configLabels:{promptClip:"Prompt",audioClip:"Audio Clip",digit:"Digit",options:"Options",addOption:"Add Option",removeOption:"Remove",optionLabel:"Label",optionLabelPlaceholder:"e.g. Sales",routeHolidaySeparately:"Route holidays separately",routeHolidaySeparatelyHint:"When on, holidays route to a dedicated branch you wire below. Otherwise holidays follow the Closed exit."},resourceGroups:{audioClips:"Audio Clips"}}},v=m;
4582
+ "function"==typeof SuppressedError&&SuppressedError;const v={common:{loading:"Loading...",error:"Error",noResults:"No results",delete:"Delete",call:"Call",cancel:"Cancel",confirm:"Confirm",previous:"Previous",next:"Next",perPage:"Per page",showing:"Showing {start}-{end} of {total}",play:"Play",pause:"Pause"},softphone:{title:"Softphone",destinationPlaceholder:"Enter a number",call:"Call",backspace:"Delete",connecting:"Connecting…",reconnecting:"Reconnecting…",disconnected:"Disconnected",connectionError:"Connection error",callError:"Call failed",micPermissionError:"Microphone access is required — allow it and try again",dismiss:"Dismiss",unknownCaller:"Unknown",incomingCall:"Incoming call",answer:"Answer",decline:"Decline",hangUp:"Hang up",mute:"Mute",unmute:"Unmute",hold:"Hold",resume:"Resume",keypad:"Keypad",transfer:"Transfer",transferPlaceholder:"Transfer to…",transferSend:"Transfer",transferNow:"Transfer now",transferConsult:"Consult first",transferComplete:"Complete transfer",transferConsulting:"Consulting…",transferOriginalOnHold:"On hold",addCall:"Add call",addCallPlaceholder:"Number to dial",addCallSend:"Call",cancel:"Cancel",stateTrying:"Calling…",stateRinging:"Ringing…",stateActive:"In call",stateHeld:"On hold",stateEnded:"Call ended",done:"Done",audioDevices:"Audio",audioMicrophone:"Microphone",audioSpeaker:"Speaker",audioSystemDefault:"System default",audioUnnamedDevice:"Unnamed device",audioLabelsHidden:"Allow microphone access to see device names",audioDevicesUnsupported:"This browser cannot list audio devices",audioSpeakerUnsupported:"Choose your speaker in your device settings",audioMicrophoneLost:"Your microphone was disconnected — choose another",switchToCall:"Switch to this call",heldCallsLabel:"On hold",callWaiting:"Call waiting",emergencyPrompt:"Set your emergency location to be able to place external calls",emergencyHint:"Confirm your location before placing calls — required by 911 regulations for internet calling.",emergencyConfirm:"Yes, I'm here",emergencyNewLocation:"Set a new location",emergencyUseLocation:"Use my current location",emergencyLocating:"Getting your location…",emergencyNumber:"Number",emergencyStreet:"Street",emergencyUnit:"Unit (optional)",emergencyCity:"City",emergencyState:"State",emergencyPostalCode:"Postal code",emergencySave:"Confirm location",emergencySaving:"Saving…",emergencyBack:"Back"},aiAgent:{loading:"Loading AI agent…",loadFailed:"Failed to load AI agent: {message}",fields:{name:"Name",namePlaceholder:"Front Desk Agent",nameHint:"Internal label shown in lists and call logs. Not heard by callers.",extensionNumber:"Extension",extensionNumberPlaceholder:"700",extensionNumberHint:"Dial this extension from any phone on the account to reach the agent.",extensionChecking:"Checking extension...",personaName:"Persona name",personaNamePlaceholder:"e.g. Receptionist",personaNameHint:"How the agent introduces itself on calls.",greetingName:"Greeting name",greetingNamePlaceholder:"Your business name",greetingNameHintWithName:'Used in the call greeting (e.g. "Thanks for calling {name}").',greetingNameHintGeneric:'Used in the call greeting (e.g. "Thanks for calling [your business]").',instructions:"Instructions",instructionsPlaceholder:"Provide additional instructions for how the AI agent should behave during calls...",instructionsHint:"Plain-English guidance for the agent: tone, what to do, what to escalate.",faq:"FAQ",faqEmpty:"No FAQ entries yet. Add one to teach the agent a recurring question.",faqEntry:"Entry {index}",faqQuestion:"Question",faqAnswer:"Answer",faqQuestionLabel:"FAQ entry {index} question",faqAnswerLabel:"FAQ entry {index} answer",faqRemove:"Remove",faqRemoveLabel:"Remove FAQ entry {index}",faqAdd:"Add FAQ entry",scheduling:"Scheduling",schedulingHint:"Connect your AI agent to an external scheduling system. Clear the URL to disable scheduling.",webhookUrl:"Webhook URL",webhookUrlHint:"Base URL for scheduling webhooks. DialStack appends tool-call paths automatically.",webhookUrlPlaceholder:"https://example.com/api/dialstack/webhooks",secret:"Webhook secret",secretHint:"Used to verify tool-call webhooks sent from this AI agent to your integration.",copySecret:"Copy webhook secret",rotateSecret:"Rotate secret"},save:"Save",saving:"Saving…",saved:"Saved.",errors:{nameRequired:"Name is required.",nameMaxLength:"Name must be {max} characters or fewer.",personaNameMaxLength:"Persona name must be {max} characters or fewer.",greetingNameMaxLength:"Greeting name must be {max} characters or fewer.",instructionsMaxLength:"Instructions must be {max} characters or fewer.",faqMaxItems:"FAQ supports up to {max} entries.",faqIncompleteEntry:"Every FAQ entry needs both a question and an answer.",faqFieldMaxLength:"FAQ fields must be {max} characters or fewer.",extensionNumeric:"Extension must contain only digits.",extensionUnavailable:"Extension number is already in use.",schedulingUrlMaxLength:"Webhook URL must be {max} characters or fewer.",schedulingUrlHttpsRequired:"Webhook URL must start with https://.",hostCreateRequired:"This form is waiting for the host app to create the AI agent.",hostSaveRequired:"This form is waiting for the host app to save the AI agent."}},voicemails:{title:"Voicemails",loading:"Loading voicemails...",empty:"No voicemails",noUserId:"Please set a user ID to load voicemails",transcription:"Transcription",summary:"Summary",sentiment:"Sentiment",sentimentPositive:"Positive",sentimentNeutral:"Neutral",sentimentNegative:"Negative",sentimentMixed:"Mixed",transcript:"Full Transcript",transcriptLoading:"Loading transcript...",transcriptNotAvailable:"Transcript not available",deleteConfirm:"Delete this voicemail?",deleteTitle:"Delete Voicemail",progress:"Playback progress"},callLogs:{title:"Call Logs",loading:"Loading call logs...",empty:"No call logs found",columns:{date:"Date",direction:"Direction",from:"From",to:"To",duration:"Duration",status:"Status",quality:"MOS"},directions:{inbound:"Inbound",outbound:"Outbound",internal:"Internal"},routedTo:"Routed to:",calledBy:"Called by:",statuses:{completed:"Completed",noAnswer:"No Answer",busy:"Busy",failed:"Failed",voicemail:"Voicemail"},quality:{good:"Good",fair:"Fair",poor:"Poor",unavailable:"N/A",unavailableTooltip:"No quality data available"}},callHistory:{title:"Call History",loading:"Loading call history...",empty:"No call history",noPhoneNumber:"Please set a phone number to load call history",error:"Unable to load call history",clickToCall:"Click to call",summaryNotAvailable:"Summary not available",relativeTime:{justNow:"Just now",minuteAgo:"1 min ago",minutesAgo:"{count} min ago",hourAgo:"1 hour ago",hoursAgo:"{count} hours ago",yesterday:"Yesterday"}},phoneNumberOrdering:{title:"Order Phone Numbers",steps:{search:"Search",select:"Select",confirm:"Confirm",route:"Route",done:"Done",stepOf:"Step {current} of {total}"},search:{title:"Search Available Numbers",subtitle:"Find available phone numbers by entering an area code or ZIP code.",searchType:"Search by",areaCode:"Area Code",zip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"e.g. 212",zipLabel:"ZIP Code",zipPlaceholder:"e.g. 10001",numberOfResults:"Quantity to display",search:"Search"},results:{title:"Available Numbers",phoneNumber:"Phone Number",state:"State",selectAll:"Select all",selected:"{count} selected",noResults:"No numbers available for this search",continue:"Continue",backToSearch:"Back to Search"},confirm:{title:"Confirm Order",subtitleOne:"You are about to order 1 phone number",subtitleOther:"You are about to order {count} phone numbers",description:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",continue:"Continue",back:"Back",billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:"{count} phone numbers at {rate} each per month.",detail_one:"{count} phone number at {rate} per month.",detail_other:"{count} phone numbers at {rate} each per month.",timing:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",noPrice:"These numbers are billable on this account.",noPrice_one:"This number is billable on this account.",noPrice_other:"These numbers are billable on this account.",notBilled:"This account is not billed, so ordering these numbers costs nothing."}},route:{title:"Choose call routing",subtitle:"Pick where these numbers should send calls once they activate. You can change this any time, or set it up later.",later:"Set up routing later",laterHint:"Configure each number from its detail page after it activates.",noTargets:"No routing destinations exist yet. You can set up routing after the numbers are added.",unnamed:"Untitled",extension:"ext. {ext}",back:"Back",type:{user:"User",dial_plan:"Dial plan",voice_app:"Voice app",queue:"Queue",ring_group:"Ring group",shared_voicemail:"Shared voicemail"}},ordering:{title:"Placing Order..."},complete:{titlePendingOne:"Order Submitted",titlePendingOther:"Order Submitted",titleCompleteOne:"Number Ready",titleCompleteOther:"Numbers Ready",titlePartialOne:"Partially Fulfilled",titlePartialOther:"Partially Fulfilled",descriptionPendingOne:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionPendingOther:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",descriptionCompleteOne:"Your phone number is now in your inventory and ready to be configured.",descriptionCompleteOther:"Your phone numbers are now in your inventory and ready to be configured.",descriptionPartialOne:"Some numbers could not be fulfilled by the carrier.",descriptionPartialOther:"Some numbers could not be fulfilled by the carrier.",checking:"Checking order status...",assignmentHint:"Numbers added to your inventory still need to be assigned to an extension or dial plan before they can receive calls.",orderMore:"Order More Numbers"},error:{title:"Order Failed",description:"The carrier was unable to fulfill your order.",tryAgain:"Try Again"},statuses:{pending:"Pending",complete:"Complete",partial:"Partial",failed:"Failed"}},phoneNumbers:{title:"Phone Numbers",loading:"Loading phone numbers...",empty:"No phone numbers",filterLabel:"Filter by status",search:{placeholder:"Search phone numbers...",noResults:"No phone numbers match your search"},filters:{active:"Active",in_progress:"In Progress",cancelled:"Cancelled"},columns:{phoneNumber:"Phone Number",status:"Status",callerID:"Outbound Caller ID",callerIDPrefix:"Inbound Caller ID Prefix",outbound:"Usage",carrier:"Carrier",transferDate:"Transfer Date",routingTarget:"Call Routing",cancelledDate:"Date Cancelled"},statuses:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",orderFailed:"Order Failed",portingDraft:"Port Draft",portingApproved:"Ready to Submit",portingSubmitted:"Port Submitted",portingException:"Port Issue",portingFoc:"Port Scheduled"},badges:{temporary:"Temporary"},outbound:{enabled:"Two-way",disabled:"Inbound only",fax:"Fax"},routingTarget:{notSet:"Not set",setAction:"Set routing",faxNotApplicable:"Not applicable"},routingTargetTypes:{user:"User",dialPlan:"Dial Plan",voiceApp:"Voice App",ringGroup:"Ring Group"}},accountOnboarding:{billing:{label:"Billing impact",headline:"Adds {amount}/month to this account's bill",detail:{userSeat:{one:"{count} user seat at {rate} per month.",other:"{count} user seats at {rate} each per month."},phoneNumber:{one:"{count} phone number at {rate} per month.",other:"{count} phone numbers at {rate} each per month."}},noPrice:{userSeat:{one:"Adds {count} billable user seat to this account.",other:"Adds {count} billable user seats to this account."},phoneNumber:{one:"Adds {count} billable phone number to this account.",other:"Adds {count} billable phone numbers to this account."}},rateHeadline:{userSeat:"{rate}/month per user seat",phoneNumber:"{rate}/month per phone number"},rateDetail:{userSeat:"Each team member you add is billed at this rate.",phoneNumber:"Each number you add is billed at this rate."},noPriceRate:{userSeat:"Each team member you add is billable on this account.",phoneNumber:"Each number you add is billable on this account."},startsOnActivation:"Billing starts when each number activates.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed, so this costs nothing."},title:"Account Onboarding",breadcrumbAriaLabel:"Onboarding progress",loading:"Loading...",error:{title:"Unable to Load",description:"Something went wrong loading the onboarding wizard.",retry:"Try Again"},steps:{account:"Account Setup",numbers:"Phone Numbers",hardware:"Hardware Setup",complete:"Complete"},sidebar:{businessDetails:"Business Details",businessDetailsDesc:"Enter your company information",teamMembers:"Team Members",teamMembersDesc:"Add users and assign extensions",numberOptions:"Number Options",numberOptionsDesc:"Choose to port existing or get new numbers",callerId:"Caller ID",callerIdDesc:"Set caller ID for your numbers",directoryListing:"Directory Listing",directoryListingDesc:"Configure 411 directory listing",numberSetup:"Number Setup",numberSetupDesc:"Configure your phone numbers",verification:"Verification",verificationDesc:"Verify number status",deviceAssignment:"Device Assignment",deviceAssignmentDesc:"Assign devices to users"},account:{title:"Business Details",subtitle:"Enter your company information",details:{heading:"Account Details",companyNameLabel:"Company Name",companyNamePlaceholder:"Acme Corp",companyNameRequired:"Company name is required",emailLabel:"Primary Contact Email",emailPlaceholder:"admin@company.com",emailRequired:"Primary contact email is required",emailInvalid:"Enter a valid email address",phoneLabel:"Primary Contact Phone Number",phonePlaceholder:"(555) 123-4567",phoneRequired:"Primary contact phone number is required",phoneInvalid:"Enter a valid US phone number",primaryContactLabel:"Primary Contact",primaryContactPlaceholder:"Jane Doe",primaryContactRequired:"Primary contact is required",regionLabel:"Region",regionPlaceholder:"Select a region",timezoneLabel:"Timezone",timezonePlaceholder:"Select a timezone",timezoneRequired:"Timezone is required"},users:{heading:"Team Members",description:"Add users who will have phone extensions",nameLabel:"Full name",namePlaceholder:"John Doe",nameRequired:"Name is required",emailLabel:"Email",emailPlaceholder:"john@company.com",extensionLabel:"Extension",extensionPlaceholder:"ex. 103",addUser:"Add User",removeUser:"Remove",noUsers:"No team members added yet.",atLeastOne:"Add at least one team member to continue.",duplicateEmail:"A user with this email already exists."},location:{heading:"Business Location",description:"Add your business address for E911 and caller ID.",nameLabel:"Location Name",namePlaceholder:"Main Office",nameRequired:"Location name is required",addressLabel:"Address",searchPlaceholder:"Start typing an address...",searching:"Searching...",noResults:"No addresses found",enterManually:"Enter manually",searchInstead:"Search instead",edit:"Edit",addressRequired:"Address is required",houseNumberLabel:"#",houseNumberPlaceholder:"123",streetLabel:"Street",streetPlaceholder:"Main St",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select",postalCodeLabel:"ZIP",postalCodePlaceholder:"10001"},saving:"Saving...",saveError:"Failed to save. Please try again."},numbers:{title:"Phone Numbers",subtitle:"Choose how you'd like to set up your business numbers",defaultDialPlanName:"Onboarding Dial Plan",callerId:{title:"Caller ID Setup",subtitle:"Configure the name displayed when making outbound calls",inputLabel:"Caller ID Name",inputPlaceholder:"e.g. ACME Corp",inputHelp:"Max 15 characters. Letters, numbers, spaces, and hyphens only.",charCount:"{count}/15",submit:"Set Caller ID",submitting:"Submitting...",submittingAll:"Submitting caller IDs...",submitted:"Submitted",alreadySet:"Already configured",submitAll:"Set All Caller IDs",skipCallerId:"Skip",partialError:"Some caller IDs could not be set. Fix errors and retry, or skip.",validation:{required:"Caller ID name is required",tooLong:"Must be 15 characters or fewer",invalidChars:"Only letters, numbers, spaces, and hyphens allowed"},error:{submitFailed:"Failed to set caller ID. Please try again.",conflict:"A caller ID update is already in progress for this number."},directoryListing:{title:"Directory Listing (DA/DL)",info:"To update your directory listing, contact {platformName} support."},noDIDs:"No active phone numbers to configure."},directoryListing:{title:"Directory Listing",subtitle:"A directory listing feeds your business information into online directories and data aggregators, helping customers find you. It also reduces the chance of your outbound calls being flagged as spam by call-screening apps.",selectPrompt:"Select which number should be listed:",noneOption:"None — skip directory listing",noDIDs:"No eligible phone numbers to configure.",businessName:"Business Name",businessNamePlaceholder:"Enter business name for listing",businessNameHelp:"The name shown in directory listings and used for caller verification. Max 200 characters.",validation:{nameRequired:"Business name is required for the directory listing."}},overview:{heading:"Your Numbers",empty:"No telephone numbers yet. Request new numbers or port your existing ones.",requestNew:"Request New Numbers",requestNewDesc:"Get new business phone numbers instantly. Choose from available numbers in your area.",portExisting:"Port Existing Number",portExistingDesc:"Transfer your current business number to {platformName}. This typically takes 5–10 business days.",phoneNumber:"Phone Number",type:"Type",status:"Status",source:"Source",temporaryBanner:"A temporary number has been assigned to your account while you set up your permanent numbers.",loadError:"Failed to load telephone numbers. Please try again.",retry:"Retry"},status:{active:"Active",inactive:"Inactive",released:"Released",ordering:"Ordering",order_failed:"Order Failed",porting_draft:"Port Draft",porting_submitted:"Port Submitted",porting_exception:"Port Exception",porting_foc:"Port Scheduled",porting_approved:"Ready to Submit"},source:{did:"Account",didTemporary:"Temporary",number_order:"New Order",port_order:"Port"},order:{searchTitle:"Search Available Numbers",searchSubtitle:"Find available numbers by entering an area code or ZIP code",searchByAreaCode:"Area Code",searchByZip:"ZIP Code",areaCodeLabel:"Area Code",areaCodePlaceholder:"212",zipLabel:"ZIP Code",zipPlaceholder:"10001",quantityLabel:"Quantity",search:"Search",searching:"Searching...",resultsTitle:"Available Numbers",resultsSubtitle:"Select the numbers you would like to order.",noResults:"No numbers found. Try a different search.",selectAll:"Select All",deselectAll:"Deselect All",selected:"selected",state:"State",confirmTitle:"Confirm Your Order",confirmSubtitle:"You are about to order {count} phone numbers",confirmSubtitle_one:"You are about to order {count} phone number",confirmSubtitle_other:"You are about to order {count} phone numbers",carrierNote:"Your order will be submitted to the carrier for fulfillment. This usually completes within seconds but may take longer.",placeOrder:"Place Order",placing:"Placing Order...",ordering:"Ordering...",statusTitle:"Order Submitted",statusPending:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusStalled:"Your order has been submitted to the carrier. Fulfillment usually completes within seconds but may take longer.",statusComplete:"Your numbers have been activated.",statusFailed:"The order could not be completed.",statusPartial:"Some numbers were activated, but others failed.",done:"Done",orderMore:"Order More Numbers",continue:"Continue",error:"An error occurred while placing the order."},port:{numbersTitle:"Numbers to Port",numbersSubtitle:"Enter the numbers you want to transfer to {platformName}, or paste a whole list into any row.",phoneLabel:"Phone Number",phonePlaceholder:"(555) 123-4567",addAnother:"Add another number",numberLabel:"Phone number {row}",removeNumber:"Remove phone number {row}",duplicateOfRow:"Duplicate of row {row}",pasteHint:"Press Enter for another row. Pasting a list — one per line, commas, or a spreadsheet column — fills a row for each number.",readyCountZero:"No numbers yet",readyCountOne:"{count} number ready",readyCountOther:"{count} numbers ready",needsAttentionOne:"{count} row needs attention before you can continue",needsAttentionOther:"{count} rows need attention before you can continue",reasonInvalid:"Not a valid US phone number",reasonNotUs:"Only US numbers can be ported",reasonTollFree:"Toll-free numbers cannot be ported",reasonAmbiguous:"Too many digits for one number — if this is several, put one per row",reasonHasExtension:"Remove the extension",maxPerOrder:"{count} numbers — the maximum is {max} per order. Move {excess} into a second port order.",notPortableWithDetail:"{label} ({detail})",accountLimit:"You've reached the number of phone numbers this account can hold. Contact support to raise the limit, then try again.",numbersUnavailable:"Some of these numbers are already in use and can't be ported. The ones affected are marked above.",conflictAlreadyOnAccount:"You already have this number",conflictInServiceElsewhere:"Already in service — contact support to transfer it",checkEligibility:"Check Eligibility",checking:"Checking...",eligibilityTitle:"Port Eligibility",eligibilitySubtitle:"Review which numbers can be ported.",portable:"Portable",notPortable:"Not Portable",carrier:"Current Carrier",wireless:"Wireless",wirelessYes:"Yes",wirelessNo:"No",accountRequired:"Account # Required",continueWithPortable:"Continue with Portable Numbers",noPortable:"None of the entered numbers are eligible for porting.",subscriberTitle:"Subscriber Information",subscriberSubtitle:"Enter the details exactly as they appear on your current phone bill.",btnLabel:"Billing Telephone Number (BTN)",btnPlaceholder:"(555) 123-4567",businessNameLabel:"Business Name",businessNamePlaceholder:"Acme Corp",approverNameLabel:"Authorized Contact",approverNamePlaceholder:"John Doe",accountNumberLabel:"Account Number",accountNumberPlaceholder:"From your current carrier",pinLabel:"Account PIN",pinPlaceholder:"1234",addressHeading:"Service Address",houseNumberLabel:"Street Number",houseNumberPlaceholder:"123",streetNameLabel:"Street Name",streetNamePlaceholder:"Main St",line2Label:"Suite / Unit",line2Placeholder:"Suite 100",cityLabel:"City",cityPlaceholder:"New York",stateLabel:"State",statePlaceholder:"Select state",zipLabel:"ZIP Code",zipPlaceholder:"10001",focTitle:"Requested Port Date",focSubtitle:"Choose when you want the numbers transferred. Must be at least 5 business days out.",focDateLabel:"Port Date",focTimeLabel:"Port Time (Eastern)",focTimePlaceholder:"Select time",documentsTitle:"Supporting Documents",documentsSubtitle:"Upload your latest phone bill and optionally a Customer Service Record (CSR).",billCopyLabel:"Phone Bill Copy",billCopyDesc:"A recent bill from your current carrier showing the numbers to be ported.",billCopyRequired:"Required",csrLabel:"Customer Service Record (CSR)",csrDesc:"Optional but recommended — speeds up the porting process.",csrOptional:"Optional",uploadFile:"Choose File",fileSelected:"Selected:",noFileSelected:"No file selected",uploading:"Uploading...",reviewTitle:"Review & Approve",reviewSubtitle:"Verify all details before submitting your port request.",numbersSection:"Numbers",subscriberSection:"Subscriber",focSection:"Port Date",documentsSection:"Documents",signatureLabel:"Electronic Signature",signaturePlaceholder:"Type your full legal name",signatureHelp:"By signing, you authorize the transfer of the listed numbers to {platformName}.",approve:"Approve & Submit",submitting:"Submitting...",submittedTitle:"Port Request Submitted",submittedSubtitle:"Your port request has been submitted and is being processed.",submittedStatus:"Status",backToOverview:"Back to Numbers",carrierGroupsTitle:"Carrier Groups",carrierGroupsSubtitle:"Your numbers are with different carriers. Each carrier requires a separate port request.",carrierStart:"Start",carrierContinue:"Continue",carrierSubmitted:"Submitted",numberSingular:"number",numberPlural:"numbers"},validation:{areaCodeRequired:"Area code is required.",areaCodeFormat:"Enter a 3-digit area code.",cityRequired:"City is required.",stateRequired:"State is required.",zipRequired:"ZIP code is required.",zipFormat:"Enter a 5-digit ZIP code.",selectAtLeastOne:"Select at least one number.",phoneRequired:"At least one phone number is required.",phoneInvalid:"Enter a valid US phone number.",phoneDuplicate:"This number has already been entered.",btnRequired:"BTN is required.",btnInvalid:"Enter a valid US phone number.",businessNameRequired:"Business name is required.",approverNameRequired:"Authorized contact name is required.",houseNumberRequired:"Street number is required.",streetNameRequired:"Street name is required.",focDateRequired:"Port date is required.",focDateTooSoon:"Port date must be at least 5 business days from today.",focDateTooFar:"Port date must be within 30 days.",focTimeRequired:"Port time is required.",billCopyRequired:"A phone bill copy is required.",signatureRequired:"Signature is required.",eligibilityError:"Failed to check eligibility. Please try again.",submitError:"Failed to submit port request. Please try again."},nav:{back:"Back",next:"Next",cancel:"Cancel",backToSearch:"Back to Search",confirm:"Confirm"},gate:{noDIDsAvailable:"You need at least one phone number before selecting a primary number. Order or port a number first.",primaryRequired:"Please select a primary number to continue."}},hardware:{title:"Assign Devices",shippingAddress:"Shipping Address",subtitle:"Drag and drop devices to assign them to team members",noUsers:"No team members found. Add team members in the Account step first.",noDevices:"No devices are available for your account at the moment.",isDectBase:"This is a cordless handset base station",userLabel:"Team Member",selectUser:"Select a team member",selectUserRequired:"Please select a team member.",macLabel:"MAC Address",macPlaceholder:"00:04:13:AA:BB:CC",invalidMac:"Enter a valid 12-digit MAC address.",ipeiLabel:"Handset IPEI",ipeiPlaceholder:"03AABB1234567890CCDD",invalidIpei:"Enter a valid IPEI (hex digits only).",ipeiNotMac:"This looks like a MAC address, not an IPEI. An IPEI looks like 03AABB1234567890CCDD.",removeDevice:"Remove",unsupportedVendor:"This device is not currently supported. Our support team has been notified and will follow up.",duplicateMac:"This MAC address is already registered.",deviceNotFound:"Device was created but could not be found. Please try again.",handset:"handset",handsets:"handsets",addDeviceButton:"+ Add Device",addHandsetButton:"+ Handset",save:"Save",saving:"Saving...",cancel:"Cancel",dectBase:"Cordless Base",removeBaseFailed:"Failed to remove cordless base.",tableHeaderName:"Full name",tableHeaderExtension:"Extension",tableHeaderDevice:"Assigned Device",availableDevices:"Available Devices",allAssigned:"All devices have been assigned",dragDropHint:"Drag and drop device here",clickToAssign:"Click to assign",submitOrder:"Submit Order",assignAndComplete:"Save & Continue",unassign:"Unassign",deskPhone:"Desk phone",cordless:"Cordless",submitting:"Submitting...",gate:{noDevices:"No devices are available for your account. Please contact support to add devices before completing this step."}},complete:{title:"Wahoo!",subtitle:"It's time to start using your embedded voice system",e911:{loading:"Configuring emergency services...",pollingStatus:"Verifying emergency services registration...",verified:"E911 emergency address is verified.",processing:"E911 registration is being processed. This may take a few minutes.",pendingAfterPolling:"E911 registration submitted. Your phone service is active — emergency address verification will complete shortly.",addressStandardized:"Your address was standardized for emergency services accuracy.",primaryAssigned:"assigned as primary number for",errorTitle:"E911 configuration failed",errorDescription:"There was an error configuring emergency services. You can retry or configure manually later.",retryButton:"Retry",deferred:"E911 emergency services have not been fully configured. Each location with a phone number needs a verified emergency address before your phone service can be activated."}},stepComplete:{title:"{stepName} Complete",subtitle:"This step has been completed successfully.",done:"Done"},nav:{next:"Next",skip:"Skip",back:"Back",exit:"Finish"},legal:{prefix:"By continuing, you agree to the",and:"and",termsOfService:"Terms of Service",recipientTerms:"Recipient Terms of Service",privacyPolicy:"Privacy Policy"},ssa:{title:"Review and accept your subscription agreement",intro:"Before you can use your phone service, please review the Service Subscription Agreement below — including its emergency calling (911/E911) terms — and confirm your acceptance.",pricingTitle:"Your plan pricing",perUser:"Per user",perNumber:"Per phone number",perAiLocation:"Per AI location",perMonthSuffix:"/mo",agreementLabel:"Service Subscription Agreement",openInNewTab:"Open the full agreement in a new tab",accept:"Accept & Continue",submitting:"Recording your acceptance…",notPermitted:"Only the account owner can accept this agreement. Please ask them to sign in and accept it — phone service stays blocked until they do.",errors:{stale:"The agreement was updated. Please review the latest version and accept again.",pricingMissing:"Your plan pricing has not been finalized yet. Please contact your provider to continue.",generic:"We could not record your acceptance. Please try again.",retry:"Try again"},loadError:{title:"Unable to load your agreement",description:"We could not load your subscription agreement, which is required before you can continue. Please try again.",retry:"Try again",retrying:"Loading…"}}},onboardingPortal:{onboardingFlows:"ONBOARDING FLOWS",saveAndExit:"Save & Exit to Overview",back:"Back",helpSupport:"Help & Support",onboardingComplete:"Onboarding complete",rates:{title:"Your monthly rates",subtitle:"What you're billed at today.",perUser:"Per user",perPhoneNumber:"Per phone number",perVoiceAiLocation:"Per VoiceAI location",perMonth:"{rate}/month",rateNotSet:"Not set",pendingRate:"{rate}/month from {date}",pendingNote:"Rate changes take effect at the start of the next billing period.",taxesAndFees:"Taxes and fees are additional.",notBilled:"This account is not billed.",noRates:"No rates are set for this account yet.",unavailable:"Rates are unavailable right now."},overview:{label:"Overview",title:"Your Business Onboarding",subtitle:"Complete the steps below to set up your business phone system",progressTitle:"Onboarding Progress",flowsComplete:"{completed} of {total} flows complete",stepsTitle:"Onboarding Steps",complete:"Complete",progress:"Progress",completeSetup:"Complete Setup",continueSetup:"Continue Setup",review:"Review",needHelp:"Need help?",needHelpSubtitle:"Our team is here to help you get set up quickly",scheduleCall:"Schedule a Call",viewDocs:"View Documentation",accountDesc:"Set up your business profile, add team members, and configure your dial plan",numbersDesc:"Port existing numbers or request new business lines",hardwareDesc:"Assign phones to team members and track delivery",phoneStatusTitle:"Phone number status",phoneStatusSubtitle:"Track the status of your phone numbers",phoneStatusNumber:"Phone Number",phoneStatusType:"Type",phoneStatusStatus:"Status",phoneStatusTypeNew:"New",phoneStatusTypePort:"Port",phoneStatusProcessing:"Processing",phoneStatusComplete:"Complete",phoneStatusTemporary:"Temporary"},splash:{title:"Welcome\nto {platformName}",subtitle:"Let's get your business set up in 3 easy steps",start:"Start Onboarding",step1:"Account Details",step2:"Setup Phone Numbers",step3:"Assign Hardware"}},dialPlan:{title:"Dial Plan",loading:"Loading dial plan...",error:"Failed to load dial plan",empty:"No dial plan found",nodeTypes:{start:"Start",schedule:"Schedule",internalDial:"Internal Extension",voicemail:"Voicemail",externalDial:"External Number",voiceApp:"Voice App",menu:"IVR Menu",audioClip:"Audio Clip",hangUp:"Hang Up"},nodeDescriptions:{menu:"Play prompt and route by keypress",audioClip:"Play an audio clip",hangUp:"End the call"},exits:{open:"Open",closed:"Closed",holiday:"Holiday",next:"Next",timeout:"Timeout",invalid:"Invalid"},configLabels:{promptClip:"Prompt",audioClip:"Audio Clip",digit:"Digit",options:"Options",addOption:"Add Option",removeOption:"Remove",optionLabel:"Label",optionLabelPlaceholder:"e.g. Sales",routeHolidaySeparately:"Route holidays separately",routeHolidaySeparatelyHint:"When on, holidays route to a dedicated branch you wire below. Otherwise holidays follow the Closed exit."},resourceGroups:{audioClips:"Audio Clips"}}},f=v;
4583
4583
 
4584
4584
  const SoftphoneContext = createContext(null);
4585
4585
  // Stands in for the phone while `usePhone` has none — before the first construct
@@ -4609,7 +4609,7 @@ const DISCONNECTED_PHONE = {
4609
4609
  reconnectWithEmergency: notConnected,
4610
4610
  };
4611
4611
  // eslint-disable-next-line react/function-component-definition -- generic component; a `React.FC` arrow can't carry the <Extra> type parameter, so this must stay a function declaration
4612
- function SoftphoneProviderBase({ token, apiBaseUrl, onTokenExpiring, iceServers, storage, ringback, createSignalingSocket, onAppResume, emergencyAddressId, autoConnect = true, appearance, locale = v, defaultCountry = 'US', onConnectionStateChange, onIncomingCall, onCallStarted, onCallEnded, onError, extra, children, }) {
4612
+ function SoftphoneProviderBase({ token, apiBaseUrl, onTokenExpiring, iceServers, storage, ringback, createSignalingSocket, onAppResume, emergencyAddressId, autoConnect = true, appearance, locale = f, defaultCountry = 'US', onConnectionStateChange, onIncomingCall, onCallStarted, onCallEnded, onError, extra, children, }) {
4613
4613
  const { lastError, handleError, clearError } = useLastError(onError);
4614
4614
  // Key on appearance CONTENT, not object identity, so a host passing an inline
4615
4615
  // `appearance={{ theme }}` literal (new object each render) doesn't recompute