commons-proxy 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +757 -0
  3. package/bin/cli.js +146 -0
  4. package/package.json +97 -0
  5. package/public/Complaint Details.pdf +0 -0
  6. package/public/Cyber Crime Portal.pdf +0 -0
  7. package/public/app.js +229 -0
  8. package/public/css/src/input.css +523 -0
  9. package/public/css/style.css +1 -0
  10. package/public/favicon.png +0 -0
  11. package/public/index.html +549 -0
  12. package/public/js/components/account-manager.js +356 -0
  13. package/public/js/components/add-account-modal.js +414 -0
  14. package/public/js/components/claude-config.js +420 -0
  15. package/public/js/components/dashboard/charts.js +605 -0
  16. package/public/js/components/dashboard/filters.js +362 -0
  17. package/public/js/components/dashboard/stats.js +110 -0
  18. package/public/js/components/dashboard.js +236 -0
  19. package/public/js/components/logs-viewer.js +100 -0
  20. package/public/js/components/models.js +36 -0
  21. package/public/js/components/server-config.js +349 -0
  22. package/public/js/config/constants.js +102 -0
  23. package/public/js/data-store.js +375 -0
  24. package/public/js/settings-store.js +58 -0
  25. package/public/js/store.js +99 -0
  26. package/public/js/translations/en.js +367 -0
  27. package/public/js/translations/id.js +412 -0
  28. package/public/js/translations/pt.js +308 -0
  29. package/public/js/translations/tr.js +358 -0
  30. package/public/js/translations/zh.js +373 -0
  31. package/public/js/utils/account-actions.js +189 -0
  32. package/public/js/utils/error-handler.js +96 -0
  33. package/public/js/utils/model-config.js +42 -0
  34. package/public/js/utils/ui-logger.js +143 -0
  35. package/public/js/utils/validators.js +77 -0
  36. package/public/js/utils.js +69 -0
  37. package/public/proxy-server-64.png +0 -0
  38. package/public/views/accounts.html +361 -0
  39. package/public/views/dashboard.html +484 -0
  40. package/public/views/logs.html +97 -0
  41. package/public/views/models.html +331 -0
  42. package/public/views/settings.html +1327 -0
  43. package/src/account-manager/credentials.js +378 -0
  44. package/src/account-manager/index.js +462 -0
  45. package/src/account-manager/onboarding.js +112 -0
  46. package/src/account-manager/rate-limits.js +369 -0
  47. package/src/account-manager/storage.js +160 -0
  48. package/src/account-manager/strategies/base-strategy.js +109 -0
  49. package/src/account-manager/strategies/hybrid-strategy.js +339 -0
  50. package/src/account-manager/strategies/index.js +79 -0
  51. package/src/account-manager/strategies/round-robin-strategy.js +76 -0
  52. package/src/account-manager/strategies/sticky-strategy.js +138 -0
  53. package/src/account-manager/strategies/trackers/health-tracker.js +162 -0
  54. package/src/account-manager/strategies/trackers/index.js +9 -0
  55. package/src/account-manager/strategies/trackers/quota-tracker.js +120 -0
  56. package/src/account-manager/strategies/trackers/token-bucket-tracker.js +155 -0
  57. package/src/auth/database.js +169 -0
  58. package/src/auth/oauth.js +548 -0
  59. package/src/auth/token-extractor.js +117 -0
  60. package/src/cli/accounts.js +648 -0
  61. package/src/cloudcode/index.js +29 -0
  62. package/src/cloudcode/message-handler.js +510 -0
  63. package/src/cloudcode/model-api.js +248 -0
  64. package/src/cloudcode/rate-limit-parser.js +235 -0
  65. package/src/cloudcode/request-builder.js +93 -0
  66. package/src/cloudcode/session-manager.js +47 -0
  67. package/src/cloudcode/sse-parser.js +121 -0
  68. package/src/cloudcode/sse-streamer.js +293 -0
  69. package/src/cloudcode/streaming-handler.js +615 -0
  70. package/src/config.js +125 -0
  71. package/src/constants.js +407 -0
  72. package/src/errors.js +242 -0
  73. package/src/fallback-config.js +29 -0
  74. package/src/format/content-converter.js +193 -0
  75. package/src/format/index.js +20 -0
  76. package/src/format/request-converter.js +255 -0
  77. package/src/format/response-converter.js +120 -0
  78. package/src/format/schema-sanitizer.js +673 -0
  79. package/src/format/signature-cache.js +88 -0
  80. package/src/format/thinking-utils.js +648 -0
  81. package/src/index.js +148 -0
  82. package/src/modules/usage-stats.js +205 -0
  83. package/src/providers/anthropic-provider.js +258 -0
  84. package/src/providers/base-provider.js +157 -0
  85. package/src/providers/cloudcode.js +94 -0
  86. package/src/providers/copilot.js +399 -0
  87. package/src/providers/github-provider.js +287 -0
  88. package/src/providers/google-provider.js +192 -0
  89. package/src/providers/index.js +211 -0
  90. package/src/providers/openai-compatible.js +265 -0
  91. package/src/providers/openai-provider.js +271 -0
  92. package/src/providers/openrouter-provider.js +325 -0
  93. package/src/providers/setup.js +83 -0
  94. package/src/server.js +870 -0
  95. package/src/utils/claude-config.js +245 -0
  96. package/src/utils/helpers.js +51 -0
  97. package/src/utils/logger.js +142 -0
  98. package/src/utils/native-module-helper.js +162 -0
  99. package/src/webui/index.js +1134 -0
@@ -0,0 +1,367 @@
1
+ /**
2
+ * English Translations
3
+ */
4
+ window.translations = window.translations || {};
5
+ window.translations.en = {
6
+ dashboard: "Dashboard",
7
+ models: "Models",
8
+ accounts: "Accounts",
9
+ logs: "Logs",
10
+ settings: "Settings",
11
+ online: "ONLINE",
12
+ offline: "OFFLINE",
13
+ totalAccounts: "TOTAL ACCOUNTS",
14
+ active: "ACTIVE",
15
+ operational: "Operational",
16
+ rateLimited: "RATE LIMITED",
17
+ quotasDepleted: "{count}/{total} Quotas Depleted",
18
+ quotasDepletedTitle: "QUOTAS DEPLETED",
19
+ outOfTracked: "Out of {total} Tracked",
20
+ cooldown: "Cooldown",
21
+ searchPlaceholder: "Search models...",
22
+ allAccounts: "All Accounts",
23
+ stat: "STAT",
24
+ modelIdentity: "MODEL IDENTITY",
25
+ globalQuota: "GLOBAL QUOTA",
26
+ nextReset: "NEXT RESET",
27
+ distribution: "ACCOUNT DISTRIBUTION",
28
+ systemConfig: "System Configuration",
29
+ language: "Language",
30
+ pollingInterval: "Polling Interval",
31
+ maxDisplayLogs: "Max Displayed Logs",
32
+ showExhausted: "Show Exhausted Models",
33
+ showExhaustedDesc: "Display models even if they have 0% remaining quota.",
34
+ compactMode: "Compact Mode",
35
+ compactModeDesc: "Reduce padding in tables for higher information density.",
36
+ saveChanges: "Save Changes",
37
+ autoScroll: "Auto-scroll",
38
+ clearLogs: "Clear Logs",
39
+ accountManagement: "Account Management",
40
+ manageTokens: "Manage Google Account tokens and authorization states",
41
+ addAccount: "Add Account",
42
+ status: "STATUS",
43
+ enabled: "ENABLED",
44
+ health: "STATUS",
45
+ accountEmail: "ACCOUNT (EMAIL)",
46
+ source: "SOURCE",
47
+ projectId: "PROJECT ID",
48
+ sessionState: "SESSION STATE",
49
+ operations: "OPERATIONS",
50
+ delete: "Delete",
51
+ fix: "Fix",
52
+ confirmDelete: "Are you sure you want to remove this account?",
53
+ cannotDeleteDatabase: "Cannot delete: This account is from IDE database (read-only)",
54
+ connectGoogle: "Connect Google Account",
55
+ reauthenticated: "re-authenticated",
56
+ added: "added",
57
+ successfully: "successfully",
58
+ accountAddedSuccess: "Account added successfully",
59
+ accountReauthSuccess: "Account re-authenticated successfully",
60
+ failedToGetAuthUrl: "Failed to get auth URL",
61
+ failedToStartOAuth: "Failed to start OAuth flow",
62
+ oauthInProgress: "OAuth in progress. Please complete authentication in the popup window...",
63
+ family: "Family",
64
+ model: "Model",
65
+ activeSuffix: "Active",
66
+ // Tabs
67
+ tabInterface: "Interface",
68
+ tabClaude: "Claude CLI",
69
+ tabModels: "Models",
70
+ tabServer: "Server Settings",
71
+ // Dashboard
72
+ linkedAccounts: "Linked Accounts",
73
+ noSignal: "NO SIGNAL DETECTED",
74
+ establishingUplink: "ESTABLISHING UPLINK...",
75
+ goToAccounts: "Go to Accounts",
76
+ // Settings - Models
77
+ modelsDesc: "Configure model visibility, pinning, and request routing.",
78
+ modelsPageDesc: "Real-time quota and status for all available models.",
79
+ showHidden: "Show Hidden Models",
80
+ hideHidden: "Hide Hidden Models",
81
+ hiddenOn: "Hidden: ON",
82
+ hiddenOff: "Hidden: OFF",
83
+ modelId: "Model ID",
84
+ actions: "Actions",
85
+ pinToTop: "Pin to top",
86
+ toggleVisibility: "Toggle Visibility",
87
+ noModels: "NO MODELS DETECTED",
88
+ modelMappingHint: "Server-side model routing. Claude Code users: see 'Claude CLI' tab for client-side setup.",
89
+ modelMapping: "Mapping (Target Model ID)",
90
+ // Settings - Claude
91
+ proxyConnection: "Proxy Connection",
92
+ modelSelection: "Model Selection",
93
+ defaultModelAliases: "DEFAULT MODEL ALIASES",
94
+ opusAlias: "Opus Alias",
95
+ sonnetAlias: "Sonnet Alias",
96
+ haikuAlias: "Haiku Alias",
97
+ claudeSettingsAlertPrefix: "Settings below directly modify",
98
+ claudeSettingsAlertSuffix: "Restart Claude CLI to apply.",
99
+ applyToClaude: "Apply to Claude CLI",
100
+ // Presets
101
+ configPresets: "Configuration Presets",
102
+ saveAsPreset: "Save as Preset",
103
+ deletePreset: "Delete Preset",
104
+ loadPreset: "Load preset into form",
105
+ load: "Load",
106
+ presetHint: "Select a preset to load it. Click \"Apply to Claude CLI\" to save changes.",
107
+ presetLoaded: "Preset loaded. Click \"Apply to Claude CLI\" to save.",
108
+ presetSaved: "Preset saved",
109
+ presetDeleted: "Preset deleted",
110
+ unsavedChangesTitle: "Unsaved Changes",
111
+ unsavedChangesMessage: "Your current configuration doesn't match any saved preset. If you switch, your current unsaved settings will be lost.",
112
+ loadAnyway: "Load Anyway",
113
+ savePresetTitle: "Save Preset",
114
+ savePresetDesc: "Save the current configuration as a reusable preset.",
115
+ presetName: "Preset Name",
116
+ presetNamePlaceholder: "e.g., My Work Setup",
117
+ savePreset: "Save Preset",
118
+ // Settings - Server
119
+ port: "Port",
120
+ uiVersion: "UI Version",
121
+ debugMode: "Debug Mode",
122
+ environment: "Environment",
123
+ serverReadOnly: "Settings managed via config.json. Restart server to apply changes.",
124
+ advancedSettings: "Advanced Settings",
125
+ reloadConfigTitle: "Reload Account Config",
126
+ reloadConfigDesc: "Force reload accounts.json from disk",
127
+ reload: "Reload",
128
+ // Config Specific
129
+ primaryModel: "Primary Model",
130
+ subAgentModel: "Sub-agent Model",
131
+ advancedOverrides: "Default Model Overrides",
132
+ opusModel: "Opus Model",
133
+ sonnetModel: "Sonnet Model",
134
+ haikuModel: "Haiku Model",
135
+ authToken: "Auth Token",
136
+ saveConfig: "Save to Claude CLI settings",
137
+ envVar: "Env",
138
+ // New Keys
139
+ systemName: "COMMONSPROXY",
140
+ systemDesc: "UNIVERSAL PROXY SYSTEM",
141
+ connectGoogleDesc: "Connect a Google Workspace account to increase your API quota limit. The account will be used to proxy Claude requests via CommonsProxy.",
142
+ useCliCommand: "Use CLI Command",
143
+ close: "Close",
144
+ requestVolume: "Request Volume",
145
+ filter: "Filter",
146
+ all: "All",
147
+ none: "None",
148
+ noDataTracked: "No data tracked yet",
149
+ selectFamilies: "Select families to display",
150
+ selectModels: "Select models to display",
151
+ noLogsMatch: "No logs match filter",
152
+ connecting: "CONNECTING",
153
+ main: "Main",
154
+ system: "System",
155
+ refreshData: "Refresh Data",
156
+ connectionLost: "Connection Lost",
157
+ lastUpdated: "Last Updated",
158
+ grepLogs: "grep logs...",
159
+ noMatchingModels: "No matching models",
160
+ typeToSearch: "Type to search or select...",
161
+ or: "OR",
162
+ refreshingAccount: "Refreshing {email}...",
163
+ refreshedAccount: "Refreshed {email}",
164
+ refreshFailed: "Refresh failed",
165
+ accountToggled: "Account {email} {status}",
166
+ toggleFailed: "Toggle failed",
167
+ reauthenticating: "Re-authenticating {email}...",
168
+ authUrlFailed: "Failed to get auth URL",
169
+ deletedAccount: "Deleted {email}",
170
+ deleteFailed: "Delete failed",
171
+ accountsReloaded: "Accounts reloaded",
172
+ reloadFailed: "Reload failed",
173
+ claudeConfigSaved: "Claude configuration saved",
174
+ claudeConfigRestored: "Claude CLI restored to defaults",
175
+ saveConfigFailed: "Failed to save configuration",
176
+ restoreConfigFailed: "Failed to restore configuration",
177
+ restoreDefault: "Restore Default",
178
+ confirmRestoreTitle: "Confirm Restore",
179
+ confirmRestoreMessage: "Are you sure you want to restore Claude CLI to default settings? This will remove proxy configuration.",
180
+ confirmRestore: "Confirm Restore",
181
+ claudeActive: "Claude Active",
182
+ claudeEmpty: "Claude Empty",
183
+ geminiActive: "Gemini Active",
184
+ geminiEmpty: "Gemini Empty",
185
+ synced: "SYNCED",
186
+ syncing: "SYNCING...",
187
+ // Time range labels
188
+ last1Hour: "Last 1H",
189
+ last6Hours: "Last 6H",
190
+ last24Hours: "Last 24H",
191
+ last7Days: "Last 7D",
192
+ allTime: "All Time",
193
+ groupBy: "Group By",
194
+ // Additional
195
+ reloading: "Reloading...",
196
+ reloaded: "Reloaded",
197
+ lines: "lines",
198
+ enabledSeeLogs: "Enabled (See Logs)",
199
+ production: "Production",
200
+ configSaved: "Configuration Saved",
201
+ enterPassword: "Enter Web UI Password:",
202
+ ready: "READY",
203
+ depleted: "Depleted",
204
+ timeH: "H",
205
+ timeM: "M",
206
+ familyClaude: "Claude",
207
+ familyGemini: "Gemini",
208
+ familyOther: "Other",
209
+ enabledStatus: "enabled",
210
+ disabledStatus: "disabled",
211
+ logLevelInfo: "INFO",
212
+ logLevelSuccess: "SUCCESS",
213
+ logLevelWarn: "WARN",
214
+ logLevelError: "ERR",
215
+ totalColon: "Total:",
216
+ todayColon: "Today:",
217
+ hour1Colon: "1H:",
218
+ frequentModels: "Frequent",
219
+ smartTitle: "Auto-select top 5 most used models (24h)",
220
+ activeCount: "{count} Active",
221
+ allCaps: "ALL",
222
+ claudeCaps: "CLAUDE",
223
+ geminiCaps: "GEMINI",
224
+ modelMapping: "Mapping (Target Model ID)",
225
+ systemInfo: "System Information",
226
+ refresh: "Refresh",
227
+ runtimeConfig: "Runtime Configuration",
228
+ debugDesc: "Enable detailed logging (See Logs tab)",
229
+ networkRetry: "Network Retry Settings",
230
+ maxRetries: "Max Retries",
231
+ retryBaseDelay: "Retry Base Delay (ms)",
232
+ retryMaxDelay: "Retry Max Delay (ms)",
233
+ persistentSessions: "Persistent Sessions",
234
+ persistTokenDesc: "Save OAuth sessions to disk for faster restarts",
235
+ rateLimiting: "Account Rate Limiting & Timeouts",
236
+ defaultCooldown: "Default Cooldown",
237
+ defaultCooldownDesc: "Fallback cooldown when API doesn't provide a reset time.",
238
+ maxWaitThreshold: "Max Wait Before Error",
239
+ maxWaitDesc: "If all accounts are rate-limited longer than this, error immediately instead of waiting.",
240
+ // Error Handling Tuning
241
+ errorHandlingTuning: "Error Handling Tuning",
242
+ rateLimitDedupWindow: "Rate Limit Dedup Window",
243
+ rateLimitDedupWindowDesc: "Prevents concurrent retry storms when multiple requests hit rate limits simultaneously.",
244
+ maxConsecutiveFailures: "Max Consecutive Failures",
245
+ maxConsecutiveFailuresDesc: "Number of consecutive failures before applying extended cooldown to an account.",
246
+ extendedCooldown: "Extended Cooldown",
247
+ extendedCooldownDesc: "Cooldown duration applied after max consecutive failures reached.",
248
+ maxCapacityRetries: "Max Capacity Retries",
249
+ maxCapacityRetriesDesc: "Maximum retries for capacity exhaustion before switching accounts.",
250
+ saveConfigServer: "Save Configuration",
251
+ serverRestartAlert: "Changes saved to {path}. Restart server to apply some settings.",
252
+ changePassword: "Change WebUI Password",
253
+ changePasswordDesc: "Update the password for accessing this dashboard",
254
+ currentPassword: "Current Password",
255
+ newPassword: "New Password",
256
+ confirmNewPassword: "Confirm New Password",
257
+ passwordEmptyDesc: "Leave empty if no password set",
258
+ passwordLengthDesc: "At least 6 characters",
259
+ passwordConfirmDesc: "Re-enter new password",
260
+ cancel: "Cancel",
261
+ passwordsNotMatch: "Passwords do not match",
262
+ passwordTooShort: "Password must be at least 6 characters",
263
+ // Dashboard drill-down
264
+ clickToViewAllAccounts: "Click to view all accounts",
265
+ clickToViewModels: "Click to view Models page",
266
+ clickToViewLimitedAccounts: "Click to view rate-limited accounts",
267
+ clickToFilterClaude: "Click to filter Claude models",
268
+ clickToFilterGemini: "Click to filter Gemini models",
269
+ // Accounts page
270
+ searchAccounts: "Search accounts...",
271
+ noAccountsYet: "No Accounts Yet",
272
+ noAccountsDesc: "Get started by adding a Google account via OAuth, or use the CLI command to import credentials.",
273
+ addFirstAccount: "Add Your First Account",
274
+ noSearchResults: "No accounts match your search",
275
+ clearSearch: "Clear Search",
276
+ disabledAccountsNote: "<strong>Disabled accounts</strong> will not be used for request routing but remain in the configuration. Dashboard statistics only include enabled accounts.",
277
+ dangerousOperation: "⚠️ Dangerous Operation",
278
+ confirmDeletePrompt: "Are you sure you want to delete account",
279
+ deleteWarning: "⚠️ This action cannot be undone. All configuration and historical records will be permanently deleted.",
280
+ // OAuth progress
281
+ oauthWaiting: "Waiting for OAuth authorization...",
282
+ oauthWaitingDesc: "Please complete the authentication in the popup window. This may take up to 2 minutes.",
283
+ oauthCancelled: "OAuth authorization cancelled",
284
+ oauthTimeout: "⏱️ OAuth authorization timed out. Please try again.",
285
+ oauthWindowClosed: "OAuth window was closed. Authorization may be incomplete.",
286
+ cancelOAuth: "Cancel",
287
+ // MCP CLI & Gemini 1M
288
+ mcpCliExperimental: "Experimental MCP CLI",
289
+ mcpCliDesc: "Enables experimental MCP integration for reliable tool usage with reduced context consumption.",
290
+ gemini1mMode: "Gemini 1M Context Mode",
291
+ gemini1mDesc: "Appends [1m] suffix to Gemini models for 1M context window support.",
292
+ gemini1mWarning: "⚠ Large context may reduce Gemini-3-Pro performance.",
293
+ clickToSet: "Click to configure...",
294
+ none: "None",
295
+ // Quota Distribution
296
+ quotaDistribution: "Quota Distribution",
297
+ resetsIn: "Resets in {time}",
298
+ noQuotaData: "No quota data available for this account yet.",
299
+ // Manual OAuth Mode
300
+ manualMode: "Manual Mode",
301
+ manualModeDesc: "(for environments where callback cannot reach)",
302
+ authLinkLabel: "Authorization Link:",
303
+ linkCopied: "Link copied to clipboard",
304
+ pasteCallbackLabel: "Paste callback URL or code:",
305
+ pasteCallbackPlaceholder: "http://localhost:51121/oauth-callback?code=... or 4/0xxx...",
306
+ completeAuth: "Complete Authorization",
307
+ authFailed: "Authorization failed",
308
+ // Import/Export
309
+ export: "Export",
310
+ import: "Import",
311
+ exportAccounts: "Export Accounts",
312
+ importAccounts: "Import Accounts",
313
+ exportSuccess: "Exported {count} accounts",
314
+ exportFailed: "Export failed",
315
+ importSuccess: "Import complete:",
316
+ importFailed: "Import failed",
317
+ // UI Elements
318
+ pageTitle: "CommonsProxy Console",
319
+ live: "Live",
320
+ tier: "Tier",
321
+ quota: "Quota",
322
+ tierUltra: "Ultra",
323
+ tierPro: "Pro",
324
+ tierFree: "Free",
325
+ menu: "Menu",
326
+ github: "GitHub",
327
+ noData: "No data",
328
+ // Error Messages
329
+ operationFailed: "Operation failed",
330
+ unknownError: "Unknown error",
331
+ presetNameRequired: "Preset name is required",
332
+ saveFailed: "Save failed",
333
+ failedToSavePreset: "Failed to save preset",
334
+ noPresetSelected: "No preset selected",
335
+ deletePresetConfirm: "Delete preset \"{name}\"?",
336
+ failedToDeletePreset: "Failed to delete preset",
337
+ failedToChangePassword: "Failed to change password",
338
+ passwordChangedSuccess: "Password changed successfully",
339
+ debugModeToggled: "Debug mode {status}",
340
+ tokenCacheToggled: "Token cache {status}",
341
+ failedToUpdateTokenCache: "Failed to update token cache",
342
+ failedToUpdateDebugMode: "Failed to update debug mode",
343
+ failedToRefreshAccount: "Failed to refresh account",
344
+ failedToDeleteAccount: "Failed to delete account",
345
+ failedToReloadAccounts: "Failed to reload accounts",
346
+ failedToUpdateModelConfig: "Failed to update model config",
347
+ fieldUpdated: "{displayName} updated to {value}",
348
+ failedToUpdateField: "Failed to update {displayName}",
349
+ // Account Selection Strategy
350
+ accountSelectionStrategy: "Account Selection Strategy",
351
+ selectionStrategy: "Selection Strategy",
352
+ strategyStickyLabel: "Sticky (Cache Optimized)",
353
+ strategyRoundRobinLabel: "Round Robin (Load Balanced)",
354
+ strategyHybridLabel: "Hybrid (Smart Distribution)",
355
+ strategyStickyDesc: "Stays on same account until rate-limited. Best for prompt caching.",
356
+ strategyRoundRobinDesc: "Rotates to next account on every request. Maximum throughput.",
357
+ strategyHybridDesc: "Smart selection based on health, tokens, and freshness.",
358
+ strategyUpdated: "Strategy updated to: {strategy}",
359
+ failedToUpdateStrategy: "Failed to update strategy",
360
+ invalidStrategy: "Invalid strategy selected",
361
+ // Validation Messages
362
+ mustBeValidNumber: "{fieldName} must be a valid number",
363
+ mustBeAtLeast: "{fieldName} must be at least {min}",
364
+ mustBeAtMost: "{fieldName} must be at most {max}",
365
+ cannotBeEmpty: "{fieldName} cannot be empty",
366
+ mustBeTrueOrFalse: "Value must be true or false",
367
+ };