@jackle.dev/zalox 1.0.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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -0
  3. package/dist/cli/commands/admin.d.ts +17 -0
  4. package/dist/cli/commands/admin.d.ts.map +1 -0
  5. package/dist/cli/commands/admin.js +359 -0
  6. package/dist/cli/commands/admin.js.map +1 -0
  7. package/dist/cli/commands/auth.d.ts +3 -0
  8. package/dist/cli/commands/auth.d.ts.map +1 -0
  9. package/dist/cli/commands/auth.js +88 -0
  10. package/dist/cli/commands/auth.js.map +1 -0
  11. package/dist/cli/commands/autoreply.d.ts +12 -0
  12. package/dist/cli/commands/autoreply.d.ts.map +1 -0
  13. package/dist/cli/commands/autoreply.js +162 -0
  14. package/dist/cli/commands/autoreply.js.map +1 -0
  15. package/dist/cli/commands/bulk.d.ts +9 -0
  16. package/dist/cli/commands/bulk.d.ts.map +1 -0
  17. package/dist/cli/commands/bulk.js +169 -0
  18. package/dist/cli/commands/bulk.js.map +1 -0
  19. package/dist/cli/commands/config.d.ts +14 -0
  20. package/dist/cli/commands/config.d.ts.map +1 -0
  21. package/dist/cli/commands/config.js +122 -0
  22. package/dist/cli/commands/config.js.map +1 -0
  23. package/dist/cli/commands/conv.d.ts +3 -0
  24. package/dist/cli/commands/conv.d.ts.map +1 -0
  25. package/dist/cli/commands/conv.js +229 -0
  26. package/dist/cli/commands/conv.js.map +1 -0
  27. package/dist/cli/commands/daemon.d.ts +13 -0
  28. package/dist/cli/commands/daemon.d.ts.map +1 -0
  29. package/dist/cli/commands/daemon.js +102 -0
  30. package/dist/cli/commands/daemon.js.map +1 -0
  31. package/dist/cli/commands/export.d.ts +10 -0
  32. package/dist/cli/commands/export.d.ts.map +1 -0
  33. package/dist/cli/commands/export.js +98 -0
  34. package/dist/cli/commands/export.js.map +1 -0
  35. package/dist/cli/commands/friend.d.ts +13 -0
  36. package/dist/cli/commands/friend.d.ts.map +1 -0
  37. package/dist/cli/commands/friend.js +337 -0
  38. package/dist/cli/commands/friend.js.map +1 -0
  39. package/dist/cli/commands/group-settings.d.ts +11 -0
  40. package/dist/cli/commands/group-settings.d.ts.map +1 -0
  41. package/dist/cli/commands/group-settings.js +154 -0
  42. package/dist/cli/commands/group-settings.js.map +1 -0
  43. package/dist/cli/commands/group.d.ts +14 -0
  44. package/dist/cli/commands/group.d.ts.map +1 -0
  45. package/dist/cli/commands/group.js +365 -0
  46. package/dist/cli/commands/group.js.map +1 -0
  47. package/dist/cli/commands/license.d.ts +13 -0
  48. package/dist/cli/commands/license.d.ts.map +1 -0
  49. package/dist/cli/commands/license.js +218 -0
  50. package/dist/cli/commands/license.js.map +1 -0
  51. package/dist/cli/commands/listen.d.ts +3 -0
  52. package/dist/cli/commands/listen.d.ts.map +1 -0
  53. package/dist/cli/commands/listen.js +177 -0
  54. package/dist/cli/commands/listen.js.map +1 -0
  55. package/dist/cli/commands/me.d.ts +9 -0
  56. package/dist/cli/commands/me.d.ts.map +1 -0
  57. package/dist/cli/commands/me.js +135 -0
  58. package/dist/cli/commands/me.js.map +1 -0
  59. package/dist/cli/commands/msg.d.ts +11 -0
  60. package/dist/cli/commands/msg.d.ts.map +1 -0
  61. package/dist/cli/commands/msg.js +255 -0
  62. package/dist/cli/commands/msg.js.map +1 -0
  63. package/dist/cli/commands/profile.d.ts +3 -0
  64. package/dist/cli/commands/profile.d.ts.map +1 -0
  65. package/dist/cli/commands/profile.js +50 -0
  66. package/dist/cli/commands/profile.js.map +1 -0
  67. package/dist/cli/commands/schedule.d.ts +12 -0
  68. package/dist/cli/commands/schedule.d.ts.map +1 -0
  69. package/dist/cli/commands/schedule.js +175 -0
  70. package/dist/cli/commands/schedule.js.map +1 -0
  71. package/dist/cli/commands/serve.d.ts +3 -0
  72. package/dist/cli/commands/serve.d.ts.map +1 -0
  73. package/dist/cli/commands/serve.js +87 -0
  74. package/dist/cli/commands/serve.js.map +1 -0
  75. package/dist/cli/commands/template.d.ts +12 -0
  76. package/dist/cli/commands/template.d.ts.map +1 -0
  77. package/dist/cli/commands/template.js +163 -0
  78. package/dist/cli/commands/template.js.map +1 -0
  79. package/dist/cli/index.d.ts +3 -0
  80. package/dist/cli/index.d.ts.map +1 -0
  81. package/dist/cli/index.js +116 -0
  82. package/dist/cli/index.js.map +1 -0
  83. package/dist/cli/output.d.ts +63 -0
  84. package/dist/cli/output.d.ts.map +1 -0
  85. package/dist/cli/output.js +144 -0
  86. package/dist/cli/output.js.map +1 -0
  87. package/dist/core/autoreply.d.ts +57 -0
  88. package/dist/core/autoreply.d.ts.map +1 -0
  89. package/dist/core/autoreply.js +159 -0
  90. package/dist/core/autoreply.js.map +1 -0
  91. package/dist/core/bulk.d.ts +36 -0
  92. package/dist/core/bulk.d.ts.map +1 -0
  93. package/dist/core/bulk.js +117 -0
  94. package/dist/core/bulk.js.map +1 -0
  95. package/dist/core/client.d.ts +8 -0
  96. package/dist/core/client.d.ts.map +1 -0
  97. package/dist/core/client.js +91 -0
  98. package/dist/core/client.js.map +1 -0
  99. package/dist/core/daemon.d.ts +30 -0
  100. package/dist/core/daemon.d.ts.map +1 -0
  101. package/dist/core/daemon.js +213 -0
  102. package/dist/core/daemon.js.map +1 -0
  103. package/dist/core/dm-commands.d.ts +41 -0
  104. package/dist/core/dm-commands.d.ts.map +1 -0
  105. package/dist/core/dm-commands.js +313 -0
  106. package/dist/core/dm-commands.js.map +1 -0
  107. package/dist/core/export.d.ts +20 -0
  108. package/dist/core/export.d.ts.map +1 -0
  109. package/dist/core/export.js +92 -0
  110. package/dist/core/export.js.map +1 -0
  111. package/dist/core/gate.d.ts +39 -0
  112. package/dist/core/gate.d.ts.map +1 -0
  113. package/dist/core/gate.js +75 -0
  114. package/dist/core/gate.js.map +1 -0
  115. package/dist/core/group-settings.d.ts +35 -0
  116. package/dist/core/group-settings.d.ts.map +1 -0
  117. package/dist/core/group-settings.js +70 -0
  118. package/dist/core/group-settings.js.map +1 -0
  119. package/dist/core/index.d.ts +22 -0
  120. package/dist/core/index.d.ts.map +1 -0
  121. package/dist/core/index.js +12 -0
  122. package/dist/core/index.js.map +1 -0
  123. package/dist/core/license.d.ts +103 -0
  124. package/dist/core/license.d.ts.map +1 -0
  125. package/dist/core/license.js +444 -0
  126. package/dist/core/license.js.map +1 -0
  127. package/dist/core/scheduler.d.ts +45 -0
  128. package/dist/core/scheduler.d.ts.map +1 -0
  129. package/dist/core/scheduler.js +203 -0
  130. package/dist/core/scheduler.js.map +1 -0
  131. package/dist/core/templates.d.ts +35 -0
  132. package/dist/core/templates.d.ts.map +1 -0
  133. package/dist/core/templates.js +107 -0
  134. package/dist/core/templates.js.map +1 -0
  135. package/dist/core/types.d.ts +57 -0
  136. package/dist/core/types.d.ts.map +1 -0
  137. package/dist/core/types.js +10 -0
  138. package/dist/core/types.js.map +1 -0
  139. package/dist/server/api.d.ts +2 -0
  140. package/dist/server/api.d.ts.map +1 -0
  141. package/dist/server/api.js +79 -0
  142. package/dist/server/api.js.map +1 -0
  143. package/dist/server/index.d.ts +16 -0
  144. package/dist/server/index.d.ts.map +1 -0
  145. package/dist/server/index.js +48 -0
  146. package/dist/server/index.js.map +1 -0
  147. package/dist/server/license-api.d.ts +55 -0
  148. package/dist/server/license-api.d.ts.map +1 -0
  149. package/dist/server/license-api.js +496 -0
  150. package/dist/server/license-api.js.map +1 -0
  151. package/dist/server/middleware.d.ts +18 -0
  152. package/dist/server/middleware.d.ts.map +1 -0
  153. package/dist/server/middleware.js +92 -0
  154. package/dist/server/middleware.js.map +1 -0
  155. package/dist/server/webhook.d.ts +10 -0
  156. package/dist/server/webhook.d.ts.map +1 -0
  157. package/dist/server/webhook.js +53 -0
  158. package/dist/server/webhook.js.map +1 -0
  159. package/dist/server/ws.d.ts +66 -0
  160. package/dist/server/ws.d.ts.map +1 -0
  161. package/dist/server/ws.js +203 -0
  162. package/dist/server/ws.js.map +1 -0
  163. package/dist/utils/cache.d.ts +35 -0
  164. package/dist/utils/cache.d.ts.map +1 -0
  165. package/dist/utils/cache.js +78 -0
  166. package/dist/utils/cache.js.map +1 -0
  167. package/dist/utils/config.d.ts +16 -0
  168. package/dist/utils/config.d.ts.map +1 -0
  169. package/dist/utils/config.js +88 -0
  170. package/dist/utils/config.js.map +1 -0
  171. package/dist/utils/logger.d.ts +17 -0
  172. package/dist/utils/logger.d.ts.map +1 -0
  173. package/dist/utils/logger.js +51 -0
  174. package/dist/utils/logger.js.map +1 -0
  175. package/package.json +74 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * ZaloX — Group Settings
3
+ *
4
+ * Per-group configuration for auto-reply, welcome messages, anti-spam, etc.
5
+ * Settings stored in ~/.openclaw/zalox/group-settings.json
6
+ */
7
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { getConfigDir, ensureConfigDir } from '../utils/config.js';
10
+ // ── Helpers ──────────────────────────────────────────────
11
+ function getSettingsPath() {
12
+ return join(getConfigDir(), 'group-settings.json');
13
+ }
14
+ function loadSettings() {
15
+ const path = getSettingsPath();
16
+ if (!existsSync(path))
17
+ return {};
18
+ try {
19
+ return JSON.parse(readFileSync(path, 'utf-8'));
20
+ }
21
+ catch {
22
+ return {};
23
+ }
24
+ }
25
+ function saveSettings(settings) {
26
+ ensureConfigDir();
27
+ writeFileSync(getSettingsPath(), JSON.stringify(settings, null, 2));
28
+ }
29
+ // ── Core Functions ───────────────────────────────────────
30
+ /**
31
+ * Get settings for a specific group.
32
+ */
33
+ export function getGroupSettings(groupId) {
34
+ const settings = loadSettings();
35
+ return (settings[groupId] || {
36
+ autoReplyEnabled: true,
37
+ antiSpamEnabled: false,
38
+ });
39
+ }
40
+ /**
41
+ * Update settings for a specific group.
42
+ */
43
+ export function setGroupSettings(groupId, update) {
44
+ const settings = loadSettings();
45
+ const current = settings[groupId] || {
46
+ autoReplyEnabled: true,
47
+ antiSpamEnabled: false,
48
+ };
49
+ settings[groupId] = { ...current, ...update };
50
+ saveSettings(settings);
51
+ return settings[groupId];
52
+ }
53
+ /**
54
+ * Get all group settings.
55
+ */
56
+ export function getAllGroupSettings() {
57
+ return loadSettings();
58
+ }
59
+ /**
60
+ * Delete settings for a specific group.
61
+ */
62
+ export function deleteGroupSettings(groupId) {
63
+ const settings = loadSettings();
64
+ if (!settings[groupId])
65
+ return false;
66
+ delete settings[groupId];
67
+ saveSettings(settings);
68
+ return true;
69
+ }
70
+ //# sourceMappingURL=group-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-settings.js","sourceRoot":"","sources":["../../src/core/group-settings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAkBnE,4DAA4D;AAE5D,SAAS,eAAe;IACtB,OAAO,IAAI,CAAC,YAAY,EAAE,EAAE,qBAAqB,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,QAAuB;IAC3C,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,eAAe,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,4DAA4D;AAE5D;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,OAAO,CACL,QAAQ,CAAC,OAAO,CAAC,IAAI;QACnB,gBAAgB,EAAE,IAAI;QACtB,eAAe,EAAE,KAAK;KACvB,CACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,MAAmC;IAEnC,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI;QACnC,gBAAgB,EAAE,IAAI;QACtB,eAAe,EAAE,KAAK;KACvB,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;IAC9C,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,YAAY,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,22 @@
1
+ export { getApi, login, loginQR, getApiInstance, clearApiInstance, saveProfileCredentials, } from "./client.js";
2
+ export { validateLicense, generateDeviceCode, activateLicense, removeLicense, checkFeature, checkLimit, getTierFeatures, getAllTierFeatures, overrideFeature, setExpiration, loadLicense, saveLicense, } from "./license.js";
3
+ export { gate, gateLimit, gateCheck, isFeatureEnabled, getCurrentTier, } from "./gate.js";
4
+ export { createTemplate, listTemplates, getTemplate, deleteTemplate, renderTemplate, } from "./templates.js";
5
+ export { addJob, listJobs, removeJob, toggleJob, getNextJobs, runScheduler, } from "./scheduler.js";
6
+ export { addRule, listRules, removeRule, toggleRule, matchRules, renderResponse, } from "./autoreply.js";
7
+ export { bulkSend, getBulkUsage, } from "./bulk.js";
8
+ export { exportFriends, exportGroups, exportConversations, } from "./export.js";
9
+ export { getGroupSettings, setGroupSettings, getAllGroupSettings, deleteGroupSettings, } from "./group-settings.js";
10
+ export type { ZaloXConfig, ProfileConfig, SavedCredentials, ZaloXSettings, ZaloXClientOptions, LoginResult, QRLoginOptions, } from "./types.js";
11
+ export { startDaemon, getDaemonStats, } from "./daemon.js";
12
+ export { handleDmCommand, } from "./dm-commands.js";
13
+ export type { DaemonOptions, DaemonStats, } from "./daemon.js";
14
+ export type { DmCommandContext, DmCommandResult, } from "./dm-commands.js";
15
+ export type { LicenseTier, LicenseFile, FeatureFlags, FeatureName, LicenseStatus, GateResult, } from "./license.js";
16
+ export type { Template } from "./templates.js";
17
+ export type { ScheduledJob } from "./scheduler.js";
18
+ export type { AutoReplyRule, MatchContext } from "./autoreply.js";
19
+ export type { BulkSendOptions, BulkSendResult } from "./bulk.js";
20
+ export type { ExportFormat } from "./export.js";
21
+ export type { GroupSettings, GroupSettingsEntry } from "./group-settings.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,KAAK,EACL,OAAO,EACP,cAAc,EACd,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,IAAI,EACJ,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,cAAc,GACf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,EACd,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,MAAM,EACN,QAAQ,EACR,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,OAAO,EACP,SAAS,EACT,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,QAAQ,EACR,YAAY,GACb,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAElE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export { getApi, login, loginQR, getApiInstance, clearApiInstance, saveProfileCredentials, } from "./client.js";
2
+ export { validateLicense, generateDeviceCode, activateLicense, removeLicense, checkFeature, checkLimit, getTierFeatures, getAllTierFeatures, overrideFeature, setExpiration, loadLicense, saveLicense, } from "./license.js";
3
+ export { gate, gateLimit, gateCheck, isFeatureEnabled, getCurrentTier, } from "./gate.js";
4
+ export { createTemplate, listTemplates, getTemplate, deleteTemplate, renderTemplate, } from "./templates.js";
5
+ export { addJob, listJobs, removeJob, toggleJob, getNextJobs, runScheduler, } from "./scheduler.js";
6
+ export { addRule, listRules, removeRule, toggleRule, matchRules, renderResponse, } from "./autoreply.js";
7
+ export { bulkSend, getBulkUsage, } from "./bulk.js";
8
+ export { exportFriends, exportGroups, exportConversations, } from "./export.js";
9
+ export { getGroupSettings, setGroupSettings, getAllGroupSettings, deleteGroupSettings, } from "./group-settings.js";
10
+ export { startDaemon, getDaemonStats, } from "./daemon.js";
11
+ export { handleDmCommand, } from "./dm-commands.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,KAAK,EACL,OAAO,EACP,cAAc,EACd,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,IAAI,EACJ,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,cAAc,GACf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,EACd,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,MAAM,EACN,QAAQ,EACR,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,OAAO,EACP,SAAS,EACT,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,QAAQ,EACR,YAAY,GACb,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAY7B,OAAO,EACL,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,eAAe,GAChB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * ZaloX — License System
3
+ *
4
+ * Device-bound licensing with feature gating.
5
+ * License tiers: free, starter, pro, team
6
+ *
7
+ * Features are gated by tier + limits (e.g., max groups, max profiles).
8
+ * License file stored locally; periodic online verification.
9
+ */
10
+ export type LicenseTier = 'free' | 'starter' | 'pro' | 'team';
11
+ export interface LicenseFile {
12
+ key: string;
13
+ tier: LicenseTier;
14
+ deviceCode: string;
15
+ activatedAt: string;
16
+ expiresAt: string | null;
17
+ lastVerifiedAt: string;
18
+ maxDevices: number;
19
+ features: FeatureFlags;
20
+ owner?: string;
21
+ email?: string;
22
+ }
23
+ export interface FeatureFlags {
24
+ maxProfiles: number;
25
+ maxGroups: number;
26
+ sendImages: boolean;
27
+ sendFiles: boolean;
28
+ sendStickers: boolean;
29
+ listener: boolean;
30
+ listenerAutoRestart: boolean;
31
+ restApi: boolean;
32
+ webhooks: boolean;
33
+ bulkSend: boolean;
34
+ bulkSendLimit: number;
35
+ scheduling: boolean;
36
+ autoReply: boolean;
37
+ templates: boolean;
38
+ export: boolean;
39
+ friendManagement: boolean;
40
+ groupManagement: boolean;
41
+ }
42
+ export declare function generateDeviceCode(): string;
43
+ export declare function loadLicense(): LicenseFile | null;
44
+ export declare function saveLicense(license: LicenseFile): void;
45
+ export declare function removeLicense(): void;
46
+ export interface LicenseStatus {
47
+ valid: boolean;
48
+ tier: LicenseTier;
49
+ features: FeatureFlags;
50
+ deviceCode: string;
51
+ error?: string;
52
+ license?: LicenseFile;
53
+ }
54
+ export declare function validateLicense(): LicenseStatus;
55
+ export type FeatureName = keyof FeatureFlags;
56
+ export interface GateResult {
57
+ allowed: boolean;
58
+ tier: LicenseTier;
59
+ feature: string;
60
+ reason?: string;
61
+ upgradeHint?: string;
62
+ }
63
+ /**
64
+ * Check if a feature is allowed under current license.
65
+ * Returns gate result with upgrade hint if blocked.
66
+ */
67
+ export declare function checkFeature(feature: FeatureName): GateResult;
68
+ /**
69
+ * Check a numeric limit (e.g., maxProfiles, maxGroups).
70
+ * Returns whether currentCount is within the limit.
71
+ */
72
+ export declare function checkLimit(feature: FeatureName, currentCount: number): GateResult;
73
+ /**
74
+ * Activate a license key.
75
+ * Tries online activation first, falls back to offline validation.
76
+ *
77
+ * Key format: ZALOX-{TIER}-{RANDOM}-{CHECKSUM}
78
+ * Example: ZALOX-PRO-A1B2C3D4-E5F6
79
+ */
80
+ export declare function activateLicense(key: string): Promise<LicenseStatus>;
81
+ /**
82
+ * Periodic online verification of license.
83
+ * Call this on startup or periodically (e.g., daily).
84
+ */
85
+ export declare function verifyLicenseOnline(): Promise<LicenseStatus>;
86
+ /**
87
+ * Override a specific feature flag in the current license.
88
+ * Useful for trials, promotions, or admin override.
89
+ */
90
+ export declare function overrideFeature(feature: FeatureName, value: boolean | number): boolean;
91
+ /**
92
+ * Extend or set expiration date.
93
+ */
94
+ export declare function setExpiration(expiresAt: string | null): boolean;
95
+ /**
96
+ * Get tier features (for display/comparison).
97
+ */
98
+ export declare function getTierFeatures(tier: LicenseTier): FeatureFlags;
99
+ /**
100
+ * Get all tier features (for pricing page).
101
+ */
102
+ export declare function getAllTierFeatures(): Record<LicenseTier, FeatureFlags>;
103
+ //# sourceMappingURL=license.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../../src/core/license.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAqFD,wBAAgB,kBAAkB,IAAI,MAAM,CA0B3C;AAQD,wBAAgB,WAAW,IAAI,WAAW,GAAG,IAAI,CAQhD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAGtD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,wBAAgB,eAAe,IAAI,aAAa,CA+C/C;AAID,MAAM,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAiC7D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,UAAU,CAyBjF;AAoBD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA6FzE;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CA2ClE;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAOtF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAM/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,CAE/D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAEtE"}
@@ -0,0 +1,444 @@
1
+ /**
2
+ * ZaloX — License System
3
+ *
4
+ * Device-bound licensing with feature gating.
5
+ * License tiers: free, starter, pro, team
6
+ *
7
+ * Features are gated by tier + limits (e.g., max groups, max profiles).
8
+ * License file stored locally; periodic online verification.
9
+ */
10
+ import { createHash } from 'crypto';
11
+ import { hostname, userInfo, platform, arch, cpus, networkInterfaces } from 'os';
12
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
13
+ import { join } from 'path';
14
+ import { getConfigDir, ensureConfigDir } from '../utils/config.js';
15
+ // ── Default feature flags per tier ───────────────────────
16
+ const TIER_FEATURES = {
17
+ free: {
18
+ maxProfiles: 1,
19
+ maxGroups: 1,
20
+ sendImages: false,
21
+ sendFiles: false,
22
+ sendStickers: false,
23
+ listener: true,
24
+ listenerAutoRestart: false,
25
+ restApi: false,
26
+ webhooks: false,
27
+ bulkSend: false,
28
+ bulkSendLimit: 0,
29
+ scheduling: false,
30
+ autoReply: false,
31
+ templates: false,
32
+ export: false,
33
+ friendManagement: true,
34
+ groupManagement: false,
35
+ },
36
+ starter: {
37
+ maxProfiles: 2,
38
+ maxGroups: 5,
39
+ sendImages: true,
40
+ sendFiles: false,
41
+ sendStickers: false,
42
+ listener: true,
43
+ listenerAutoRestart: true,
44
+ restApi: false,
45
+ webhooks: false,
46
+ bulkSend: false,
47
+ bulkSendLimit: 0,
48
+ scheduling: false,
49
+ autoReply: false,
50
+ templates: true,
51
+ export: false,
52
+ friendManagement: true,
53
+ groupManagement: true,
54
+ },
55
+ pro: {
56
+ maxProfiles: -1, // unlimited
57
+ maxGroups: -1,
58
+ sendImages: true,
59
+ sendFiles: true,
60
+ sendStickers: true,
61
+ listener: true,
62
+ listenerAutoRestart: true,
63
+ restApi: true,
64
+ webhooks: true,
65
+ bulkSend: true,
66
+ bulkSendLimit: 1000,
67
+ scheduling: true,
68
+ autoReply: true,
69
+ templates: true,
70
+ export: true,
71
+ friendManagement: true,
72
+ groupManagement: true,
73
+ },
74
+ team: {
75
+ maxProfiles: -1,
76
+ maxGroups: -1,
77
+ sendImages: true,
78
+ sendFiles: true,
79
+ sendStickers: true,
80
+ listener: true,
81
+ listenerAutoRestart: true,
82
+ restApi: true,
83
+ webhooks: true,
84
+ bulkSend: true,
85
+ bulkSendLimit: 5000,
86
+ scheduling: true,
87
+ autoReply: true,
88
+ templates: true,
89
+ export: true,
90
+ friendManagement: true,
91
+ groupManagement: true,
92
+ },
93
+ };
94
+ // ── Device Fingerprint ──────────────────────────────────
95
+ export function generateDeviceCode() {
96
+ const parts = [
97
+ hostname(),
98
+ userInfo().username,
99
+ platform(),
100
+ arch(),
101
+ cpus()[0]?.model || 'unknown-cpu',
102
+ ];
103
+ // Get first non-internal MAC address
104
+ const nets = networkInterfaces();
105
+ let mac = 'no-mac';
106
+ for (const name of Object.keys(nets)) {
107
+ for (const net of nets[name] || []) {
108
+ if (!net.internal && net.mac && net.mac !== '00:00:00:00:00:00') {
109
+ mac = net.mac;
110
+ break;
111
+ }
112
+ }
113
+ if (mac !== 'no-mac')
114
+ break;
115
+ }
116
+ parts.push(mac);
117
+ const hash = createHash('sha256').update(parts.join('|')).digest('hex');
118
+ // Format as ZX-XXXXXXXX (readable)
119
+ return `ZX-${hash.substring(0, 8).toUpperCase()}`;
120
+ }
121
+ // ── License File Management ─────────────────────────────
122
+ function getLicensePath() {
123
+ return join(getConfigDir(), 'license.json');
124
+ }
125
+ export function loadLicense() {
126
+ const path = getLicensePath();
127
+ if (!existsSync(path))
128
+ return null;
129
+ try {
130
+ return JSON.parse(readFileSync(path, 'utf-8'));
131
+ }
132
+ catch {
133
+ return null;
134
+ }
135
+ }
136
+ export function saveLicense(license) {
137
+ ensureConfigDir();
138
+ writeFileSync(getLicensePath(), JSON.stringify(license, null, 2));
139
+ }
140
+ export function removeLicense() {
141
+ const path = getLicensePath();
142
+ if (existsSync(path)) {
143
+ unlinkSync(path);
144
+ }
145
+ }
146
+ export function validateLicense() {
147
+ const deviceCode = generateDeviceCode();
148
+ const license = loadLicense();
149
+ // No license → free tier
150
+ if (!license) {
151
+ return {
152
+ valid: true,
153
+ tier: 'free',
154
+ features: TIER_FEATURES.free,
155
+ deviceCode,
156
+ };
157
+ }
158
+ // Check device binding
159
+ if (license.deviceCode !== deviceCode) {
160
+ return {
161
+ valid: false,
162
+ tier: 'free',
163
+ features: TIER_FEATURES.free,
164
+ deviceCode,
165
+ error: `License bound to different device (expected ${license.deviceCode}, got ${deviceCode})`,
166
+ };
167
+ }
168
+ // Check expiration
169
+ if (license.expiresAt) {
170
+ const expires = new Date(license.expiresAt);
171
+ if (expires < new Date()) {
172
+ return {
173
+ valid: false,
174
+ tier: 'free',
175
+ features: TIER_FEATURES.free,
176
+ deviceCode,
177
+ error: `License expired on ${license.expiresAt}`,
178
+ };
179
+ }
180
+ }
181
+ // Valid license
182
+ return {
183
+ valid: true,
184
+ tier: license.tier,
185
+ features: license.features || TIER_FEATURES[license.tier],
186
+ deviceCode,
187
+ license,
188
+ };
189
+ }
190
+ /**
191
+ * Check if a feature is allowed under current license.
192
+ * Returns gate result with upgrade hint if blocked.
193
+ */
194
+ export function checkFeature(feature) {
195
+ const status = validateLicense();
196
+ const flags = status.features;
197
+ const value = flags[feature];
198
+ // Boolean features
199
+ if (typeof value === 'boolean') {
200
+ if (value) {
201
+ return { allowed: true, tier: status.tier, feature };
202
+ }
203
+ const minTier = getMinTierForFeature(feature);
204
+ return {
205
+ allowed: false,
206
+ tier: status.tier,
207
+ feature,
208
+ reason: `"${feature}" requires ${minTier} license or higher`,
209
+ upgradeHint: `Upgrade to ${minTier}: zalox license upgrade`,
210
+ };
211
+ }
212
+ // Numeric limits (-1 = unlimited)
213
+ if (typeof value === 'number' && value === 0) {
214
+ const minTier = getMinTierForFeature(feature);
215
+ return {
216
+ allowed: false,
217
+ tier: status.tier,
218
+ feature,
219
+ reason: `"${feature}" requires ${minTier} license or higher`,
220
+ upgradeHint: `Upgrade to ${minTier}: zalox license upgrade`,
221
+ };
222
+ }
223
+ return { allowed: true, tier: status.tier, feature };
224
+ }
225
+ /**
226
+ * Check a numeric limit (e.g., maxProfiles, maxGroups).
227
+ * Returns whether currentCount is within the limit.
228
+ */
229
+ export function checkLimit(feature, currentCount) {
230
+ const status = validateLicense();
231
+ const limit = status.features[feature];
232
+ if (typeof limit !== 'number') {
233
+ return { allowed: true, tier: status.tier, feature };
234
+ }
235
+ // -1 = unlimited
236
+ if (limit === -1) {
237
+ return { allowed: true, tier: status.tier, feature };
238
+ }
239
+ if (currentCount >= limit) {
240
+ const minTier = getMinTierForFeature(feature);
241
+ return {
242
+ allowed: false,
243
+ tier: status.tier,
244
+ feature,
245
+ reason: `Limit reached: ${currentCount}/${limit} (${feature})`,
246
+ upgradeHint: `Upgrade to ${minTier} for higher limits: zalox license upgrade`,
247
+ };
248
+ }
249
+ return { allowed: true, tier: status.tier, feature };
250
+ }
251
+ /**
252
+ * Find the minimum tier that enables a feature.
253
+ */
254
+ function getMinTierForFeature(feature) {
255
+ const tiers = ['starter', 'pro', 'team'];
256
+ for (const tier of tiers) {
257
+ const val = TIER_FEATURES[tier][feature];
258
+ if (typeof val === 'boolean' && val)
259
+ return tier;
260
+ if (typeof val === 'number' && val !== 0)
261
+ return tier;
262
+ }
263
+ return 'pro';
264
+ }
265
+ // ── License Activation ──────────────────────────────────
266
+ // License server URL (set via env or config)
267
+ const LICENSE_SERVER_URL = process.env.ZALOX_LICENSE_SERVER || '';
268
+ /**
269
+ * Activate a license key.
270
+ * Tries online activation first, falls back to offline validation.
271
+ *
272
+ * Key format: ZALOX-{TIER}-{RANDOM}-{CHECKSUM}
273
+ * Example: ZALOX-PRO-A1B2C3D4-E5F6
274
+ */
275
+ export async function activateLicense(key) {
276
+ const deviceCode = generateDeviceCode();
277
+ // Parse key format
278
+ const parts = key.toUpperCase().split('-');
279
+ if (parts.length < 4 || parts[0] !== 'ZALOX') {
280
+ return {
281
+ valid: false,
282
+ tier: 'free',
283
+ features: TIER_FEATURES.free,
284
+ deviceCode,
285
+ error: 'Invalid license key format. Expected: ZALOX-TIER-XXXXXXXX-XXXX',
286
+ };
287
+ }
288
+ const tierStr = parts[1].toLowerCase();
289
+ if (!['starter', 'pro', 'team'].includes(tierStr)) {
290
+ return {
291
+ valid: false,
292
+ tier: 'free',
293
+ features: TIER_FEATURES.free,
294
+ deviceCode,
295
+ error: `Invalid tier "${parts[1]}". Valid: STARTER, PRO, TEAM`,
296
+ };
297
+ }
298
+ // Try online activation first
299
+ if (LICENSE_SERVER_URL) {
300
+ try {
301
+ const res = await fetch(`${LICENSE_SERVER_URL}/api/license/activate`, {
302
+ method: 'POST',
303
+ headers: { 'Content-Type': 'application/json' },
304
+ body: JSON.stringify({
305
+ key: key.toUpperCase(),
306
+ deviceCode,
307
+ hostname: hostname(),
308
+ platform: `${platform()}-${arch()}`,
309
+ }),
310
+ signal: AbortSignal.timeout(10000),
311
+ });
312
+ const data = await res.json();
313
+ if (data.ok && data.tier) {
314
+ const tier = data.tier;
315
+ const features = data.features || { ...TIER_FEATURES[tier] };
316
+ const license = {
317
+ key: key.toUpperCase(),
318
+ tier,
319
+ deviceCode,
320
+ activatedAt: new Date().toISOString(),
321
+ expiresAt: data.expiresAt || null,
322
+ lastVerifiedAt: new Date().toISOString(),
323
+ maxDevices: tier === 'team' ? 5 : 1,
324
+ features,
325
+ };
326
+ saveLicense(license);
327
+ return { valid: true, tier, features, deviceCode, license };
328
+ }
329
+ else {
330
+ return {
331
+ valid: false,
332
+ tier: 'free',
333
+ features: TIER_FEATURES.free,
334
+ deviceCode,
335
+ error: data.error || 'Server rejected activation',
336
+ };
337
+ }
338
+ }
339
+ catch (err) {
340
+ // Server unreachable — fall through to offline
341
+ console.warn('License server unreachable, using offline validation...');
342
+ }
343
+ }
344
+ // Offline activation (fallback)
345
+ const tier = tierStr;
346
+ const features = { ...TIER_FEATURES[tier] };
347
+ const license = {
348
+ key: key.toUpperCase(),
349
+ tier,
350
+ deviceCode,
351
+ activatedAt: new Date().toISOString(),
352
+ expiresAt: null,
353
+ lastVerifiedAt: new Date().toISOString(),
354
+ maxDevices: tier === 'team' ? 5 : 1,
355
+ features,
356
+ };
357
+ saveLicense(license);
358
+ return { valid: true, tier, features, deviceCode, license };
359
+ }
360
+ /**
361
+ * Periodic online verification of license.
362
+ * Call this on startup or periodically (e.g., daily).
363
+ */
364
+ export async function verifyLicenseOnline() {
365
+ const status = validateLicense();
366
+ if (!status.valid || status.tier === 'free' || !LICENSE_SERVER_URL) {
367
+ return status;
368
+ }
369
+ const license = loadLicense();
370
+ if (!license)
371
+ return status;
372
+ try {
373
+ const res = await fetch(`${LICENSE_SERVER_URL}/api/license/verify`, {
374
+ method: 'POST',
375
+ headers: { 'Content-Type': 'application/json' },
376
+ body: JSON.stringify({
377
+ key: license.key,
378
+ deviceCode: license.deviceCode,
379
+ }),
380
+ signal: AbortSignal.timeout(10000),
381
+ });
382
+ const data = await res.json();
383
+ if (data.ok && data.valid) {
384
+ // Update local license with server data
385
+ license.lastVerifiedAt = new Date().toISOString();
386
+ if (data.features)
387
+ license.features = data.features;
388
+ saveLicense(license);
389
+ return { ...status, features: license.features };
390
+ }
391
+ else {
392
+ // Server says invalid — revoke locally
393
+ removeLicense();
394
+ return {
395
+ valid: false,
396
+ tier: 'free',
397
+ features: TIER_FEATURES.free,
398
+ deviceCode: status.deviceCode,
399
+ error: data.error || 'License verification failed',
400
+ };
401
+ }
402
+ }
403
+ catch {
404
+ // Server unreachable — keep existing license (grace period)
405
+ return status;
406
+ }
407
+ }
408
+ // ── Feature flag override (for admin/testing) ───────────
409
+ /**
410
+ * Override a specific feature flag in the current license.
411
+ * Useful for trials, promotions, or admin override.
412
+ */
413
+ export function overrideFeature(feature, value) {
414
+ const license = loadLicense();
415
+ if (!license)
416
+ return false;
417
+ license.features[feature] = value;
418
+ saveLicense(license);
419
+ return true;
420
+ }
421
+ /**
422
+ * Extend or set expiration date.
423
+ */
424
+ export function setExpiration(expiresAt) {
425
+ const license = loadLicense();
426
+ if (!license)
427
+ return false;
428
+ license.expiresAt = expiresAt;
429
+ saveLicense(license);
430
+ return true;
431
+ }
432
+ /**
433
+ * Get tier features (for display/comparison).
434
+ */
435
+ export function getTierFeatures(tier) {
436
+ return { ...TIER_FEATURES[tier] };
437
+ }
438
+ /**
439
+ * Get all tier features (for pricing page).
440
+ */
441
+ export function getAllTierFeatures() {
442
+ return { ...TIER_FEATURES };
443
+ }
444
+ //# sourceMappingURL=license.js.map