chainlesschain 0.81.0 → 0.132.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 (110) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/commands/agent-network.js +254 -1
  4. package/src/commands/audit.js +302 -0
  5. package/src/commands/automation.js +271 -1
  6. package/src/commands/codegen.js +224 -0
  7. package/src/commands/collab.js +341 -0
  8. package/src/commands/compliance.js +1035 -0
  9. package/src/commands/cowork.js +221 -0
  10. package/src/commands/dbevo.js +284 -0
  11. package/src/commands/dev.js +252 -0
  12. package/src/commands/did.js +358 -0
  13. package/src/commands/encrypt.js +341 -0
  14. package/src/commands/export.js +256 -1
  15. package/src/commands/fusion.js +258 -0
  16. package/src/commands/governance.js +325 -0
  17. package/src/commands/hardening.js +411 -0
  18. package/src/commands/hook.js +148 -0
  19. package/src/commands/import.js +252 -0
  20. package/src/commands/incentive.js +322 -0
  21. package/src/commands/infra.js +244 -0
  22. package/src/commands/instinct.js +260 -0
  23. package/src/commands/ipfs.js +318 -0
  24. package/src/commands/kg.js +387 -0
  25. package/src/commands/llm.js +263 -0
  26. package/src/commands/mcp.js +221 -0
  27. package/src/commands/memory.js +248 -0
  28. package/src/commands/multimodal.js +296 -0
  29. package/src/commands/nlprog.js +356 -0
  30. package/src/commands/note.js +244 -0
  31. package/src/commands/ops.js +354 -0
  32. package/src/commands/orchestrate.js +166 -0
  33. package/src/commands/org.js +277 -0
  34. package/src/commands/p2p.js +390 -0
  35. package/src/commands/perception.js +290 -0
  36. package/src/commands/permmem.js +251 -0
  37. package/src/commands/plugin-ecosystem.js +273 -0
  38. package/src/commands/pqc.js +393 -0
  39. package/src/commands/quantization.js +351 -0
  40. package/src/commands/rcache.js +271 -0
  41. package/src/commands/recommend.js +340 -0
  42. package/src/commands/runtime.js +307 -0
  43. package/src/commands/scim.js +262 -0
  44. package/src/commands/session.js +258 -0
  45. package/src/commands/skill.js +267 -1
  46. package/src/commands/social.js +256 -0
  47. package/src/commands/sso.js +186 -1
  48. package/src/commands/sync.js +256 -0
  49. package/src/commands/tech.js +338 -0
  50. package/src/commands/tenant.js +351 -0
  51. package/src/commands/tokens.js +269 -0
  52. package/src/commands/trust.js +249 -0
  53. package/src/commands/wallet.js +277 -0
  54. package/src/commands/workflow.js +171 -0
  55. package/src/index.js +4 -0
  56. package/src/lib/agent-coordinator.js +325 -0
  57. package/src/lib/agent-network.js +387 -0
  58. package/src/lib/agent-router.js +395 -0
  59. package/src/lib/aiops.js +478 -0
  60. package/src/lib/audit-logger.js +379 -0
  61. package/src/lib/automation-engine.js +330 -0
  62. package/src/lib/autonomous-developer.js +350 -0
  63. package/src/lib/code-agent.js +323 -0
  64. package/src/lib/collaboration-governance.js +364 -0
  65. package/src/lib/community-governance.js +436 -0
  66. package/src/lib/compliance-manager.js +434 -0
  67. package/src/lib/content-recommendation.js +469 -0
  68. package/src/lib/crypto-manager.js +350 -0
  69. package/src/lib/dbevo.js +338 -0
  70. package/src/lib/decentral-infra.js +340 -0
  71. package/src/lib/did-manager.js +367 -0
  72. package/src/lib/hardening-manager.js +348 -0
  73. package/src/lib/hook-manager.js +380 -0
  74. package/src/lib/instinct-manager.js +332 -0
  75. package/src/lib/ipfs-storage.js +334 -0
  76. package/src/lib/knowledge-exporter.js +381 -0
  77. package/src/lib/knowledge-graph.js +432 -0
  78. package/src/lib/knowledge-importer.js +379 -0
  79. package/src/lib/llm-providers.js +391 -0
  80. package/src/lib/mcp-registry.js +333 -0
  81. package/src/lib/memory-manager.js +330 -0
  82. package/src/lib/multimodal.js +346 -0
  83. package/src/lib/nl-programming.js +343 -0
  84. package/src/lib/note-versioning.js +327 -0
  85. package/src/lib/org-manager.js +323 -0
  86. package/src/lib/p2p-manager.js +387 -0
  87. package/src/lib/perception.js +346 -0
  88. package/src/lib/perf-tuning.js +4 -1
  89. package/src/lib/permanent-memory.js +320 -0
  90. package/src/lib/plugin-ecosystem.js +377 -0
  91. package/src/lib/pqc-manager.js +368 -0
  92. package/src/lib/protocol-fusion.js +417 -0
  93. package/src/lib/quantization.js +325 -0
  94. package/src/lib/response-cache.js +327 -0
  95. package/src/lib/scim-manager.js +329 -0
  96. package/src/lib/session-manager.js +329 -0
  97. package/src/lib/skill-loader.js +377 -0
  98. package/src/lib/social-manager.js +326 -0
  99. package/src/lib/sso-manager.js +332 -0
  100. package/src/lib/sync-manager.js +326 -0
  101. package/src/lib/tech-learning-engine.js +369 -0
  102. package/src/lib/tenant-saas.js +460 -0
  103. package/src/lib/threat-intel.js +335 -0
  104. package/src/lib/token-incentive.js +293 -0
  105. package/src/lib/token-tracker.js +329 -0
  106. package/src/lib/trust-security.js +390 -0
  107. package/src/lib/ueba.js +389 -0
  108. package/src/lib/universal-runtime.js +325 -0
  109. package/src/lib/wallet-manager.js +326 -0
  110. package/src/lib/workflow-engine.js +322 -0
@@ -769,3 +769,328 @@ export function _resetState() {
769
769
  startedAt: Date.now(),
770
770
  };
771
771
  }
772
+
773
+ /* ═════════════════════════════════════════════════════════ *
774
+ * Phase 63 V2 — Plugin Maturity + Runtime Task Lifecycle
775
+ * ═════════════════════════════════════════════════════════ */
776
+
777
+ export const PLUGIN_MATURITY_V2 = Object.freeze({
778
+ DRAFT: "draft",
779
+ ACTIVE: "active",
780
+ DEPRECATED: "deprecated",
781
+ RETIRED: "retired",
782
+ });
783
+
784
+ export const RUNTIME_TASK_V2 = Object.freeze({
785
+ QUEUED: "queued",
786
+ RUNNING: "running",
787
+ COMPLETED: "completed",
788
+ FAILED: "failed",
789
+ CANCELED: "canceled",
790
+ });
791
+
792
+ const PLUGIN_TRANSITIONS_V2 = new Map([
793
+ ["draft", new Set(["active", "retired"])],
794
+ ["active", new Set(["deprecated", "retired"])],
795
+ ["deprecated", new Set(["active", "retired"])],
796
+ ]);
797
+ const PLUGIN_TERMINALS_V2 = new Set(["retired"]);
798
+
799
+ const RUNTIME_TASK_TRANSITIONS_V2 = new Map([
800
+ ["queued", new Set(["running", "canceled", "failed"])],
801
+ ["running", new Set(["completed", "failed", "canceled"])],
802
+ ]);
803
+ const RUNTIME_TASK_TERMINALS_V2 = new Set(["completed", "failed", "canceled"]);
804
+
805
+ export const RT_DEFAULT_MAX_ACTIVE_PLUGINS_PER_OWNER = 40;
806
+ export const RT_DEFAULT_MAX_RUNNING_TASKS_PER_OWNER = 5;
807
+ export const RT_DEFAULT_PLUGIN_IDLE_MS = 90 * 86400000; // 90d
808
+ export const RT_DEFAULT_TASK_STUCK_MS = 4 * 3600000; // 4h
809
+
810
+ let _maxActivePluginsPerOwnerV2 = RT_DEFAULT_MAX_ACTIVE_PLUGINS_PER_OWNER;
811
+ let _maxRunningTasksPerOwnerV2 = RT_DEFAULT_MAX_RUNNING_TASKS_PER_OWNER;
812
+ let _pluginIdleMsV2 = RT_DEFAULT_PLUGIN_IDLE_MS;
813
+ let _taskStuckMsV2 = RT_DEFAULT_TASK_STUCK_MS;
814
+
815
+ function _positiveIntV2(n, label) {
816
+ const v = Math.floor(Number(n));
817
+ if (!Number.isFinite(v) || v <= 0)
818
+ throw new Error(`${label} must be a positive integer`);
819
+ return v;
820
+ }
821
+
822
+ export function getDefaultMaxActivePluginsPerOwnerV2() {
823
+ return RT_DEFAULT_MAX_ACTIVE_PLUGINS_PER_OWNER;
824
+ }
825
+ export function getMaxActivePluginsPerOwnerV2() {
826
+ return _maxActivePluginsPerOwnerV2;
827
+ }
828
+ export function setMaxActivePluginsPerOwnerV2(n) {
829
+ return (_maxActivePluginsPerOwnerV2 = _positiveIntV2(
830
+ n,
831
+ "maxActivePluginsPerOwner",
832
+ ));
833
+ }
834
+ export function getDefaultMaxRunningTasksPerOwnerV2() {
835
+ return RT_DEFAULT_MAX_RUNNING_TASKS_PER_OWNER;
836
+ }
837
+ export function getMaxRunningTasksPerOwnerV2() {
838
+ return _maxRunningTasksPerOwnerV2;
839
+ }
840
+ export function setMaxRunningTasksPerOwnerV2(n) {
841
+ return (_maxRunningTasksPerOwnerV2 = _positiveIntV2(
842
+ n,
843
+ "maxRunningTasksPerOwner",
844
+ ));
845
+ }
846
+ export function getDefaultPluginIdleMsV2() {
847
+ return RT_DEFAULT_PLUGIN_IDLE_MS;
848
+ }
849
+ export function getPluginIdleMsV2() {
850
+ return _pluginIdleMsV2;
851
+ }
852
+ export function setPluginIdleMsV2(ms) {
853
+ return (_pluginIdleMsV2 = _positiveIntV2(ms, "pluginIdleMs"));
854
+ }
855
+ export function getDefaultTaskStuckMsV2() {
856
+ return RT_DEFAULT_TASK_STUCK_MS;
857
+ }
858
+ export function getTaskStuckMsV2() {
859
+ return _taskStuckMsV2;
860
+ }
861
+ export function setTaskStuckMsV2(ms) {
862
+ return (_taskStuckMsV2 = _positiveIntV2(ms, "taskStuckMs"));
863
+ }
864
+
865
+ const _pluginsV2 = new Map();
866
+ const _runtimeTasksV2 = new Map();
867
+
868
+ export function registerPluginV2(
869
+ _db,
870
+ { pluginId, ownerId, name, version, initialStatus, metadata } = {},
871
+ ) {
872
+ if (!pluginId) throw new Error("pluginId is required");
873
+ if (!ownerId) throw new Error("ownerId is required");
874
+ if (_pluginsV2.has(pluginId))
875
+ throw new Error(`Plugin ${pluginId} already exists`);
876
+ const status = initialStatus || PLUGIN_MATURITY_V2.DRAFT;
877
+ if (!Object.values(PLUGIN_MATURITY_V2).includes(status))
878
+ throw new Error(`Invalid initial status: ${status}`);
879
+ if (PLUGIN_TERMINALS_V2.has(status))
880
+ throw new Error(`Cannot register in terminal status: ${status}`);
881
+ if (status === PLUGIN_MATURITY_V2.ACTIVE) {
882
+ if (getActivePluginCount(ownerId) >= _maxActivePluginsPerOwnerV2)
883
+ throw new Error(
884
+ `Owner ${ownerId} reached active-plugin cap (${_maxActivePluginsPerOwnerV2})`,
885
+ );
886
+ }
887
+ const now = Date.now();
888
+ const record = {
889
+ pluginId,
890
+ ownerId,
891
+ name: name || "",
892
+ version: version || "0.0.0",
893
+ status,
894
+ metadata: metadata || {},
895
+ createdAt: now,
896
+ updatedAt: now,
897
+ lastInvokedAt: now,
898
+ };
899
+ _pluginsV2.set(pluginId, record);
900
+ return { ...record, metadata: { ...record.metadata } };
901
+ }
902
+
903
+ export function getPluginV2(pluginId) {
904
+ const r = _pluginsV2.get(pluginId);
905
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
906
+ }
907
+
908
+ export function setPluginMaturityV2(_db, pluginId, newStatus, patch = {}) {
909
+ const record = _pluginsV2.get(pluginId);
910
+ if (!record) throw new Error(`Unknown plugin: ${pluginId}`);
911
+ if (!Object.values(PLUGIN_MATURITY_V2).includes(newStatus))
912
+ throw new Error(`Invalid status: ${newStatus}`);
913
+ const allowed = PLUGIN_TRANSITIONS_V2.get(record.status) || new Set();
914
+ if (!allowed.has(newStatus))
915
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
916
+ if (newStatus === PLUGIN_MATURITY_V2.ACTIVE) {
917
+ if (getActivePluginCount(record.ownerId) >= _maxActivePluginsPerOwnerV2)
918
+ throw new Error(
919
+ `Owner ${record.ownerId} reached active-plugin cap (${_maxActivePluginsPerOwnerV2})`,
920
+ );
921
+ }
922
+ record.status = newStatus;
923
+ record.updatedAt = Date.now();
924
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
925
+ if (patch.metadata)
926
+ record.metadata = { ...record.metadata, ...patch.metadata };
927
+ return { ...record, metadata: { ...record.metadata } };
928
+ }
929
+
930
+ export function activatePluginV2(db, id, reason) {
931
+ return setPluginMaturityV2(db, id, PLUGIN_MATURITY_V2.ACTIVE, { reason });
932
+ }
933
+ export function deprecatePluginV2(db, id, reason) {
934
+ return setPluginMaturityV2(db, id, PLUGIN_MATURITY_V2.DEPRECATED, { reason });
935
+ }
936
+ export function retirePluginV2(db, id, reason) {
937
+ return setPluginMaturityV2(db, id, PLUGIN_MATURITY_V2.RETIRED, { reason });
938
+ }
939
+
940
+ export function touchPluginInvocation(pluginId) {
941
+ const record = _pluginsV2.get(pluginId);
942
+ if (!record) throw new Error(`Unknown plugin: ${pluginId}`);
943
+ record.lastInvokedAt = Date.now();
944
+ record.updatedAt = record.lastInvokedAt;
945
+ return { ...record, metadata: { ...record.metadata } };
946
+ }
947
+
948
+ export function enqueueRuntimeTaskV2(
949
+ _db,
950
+ { taskId, ownerId, pluginId, kind, metadata } = {},
951
+ ) {
952
+ if (!taskId) throw new Error("taskId is required");
953
+ if (!ownerId) throw new Error("ownerId is required");
954
+ if (!pluginId) throw new Error("pluginId is required");
955
+ if (!kind) throw new Error("kind is required");
956
+ if (_runtimeTasksV2.has(taskId))
957
+ throw new Error(`Task ${taskId} already exists`);
958
+ const now = Date.now();
959
+ const record = {
960
+ taskId,
961
+ ownerId,
962
+ pluginId,
963
+ kind,
964
+ status: RUNTIME_TASK_V2.QUEUED,
965
+ metadata: metadata || {},
966
+ createdAt: now,
967
+ updatedAt: now,
968
+ };
969
+ _runtimeTasksV2.set(taskId, record);
970
+ return { ...record, metadata: { ...record.metadata } };
971
+ }
972
+
973
+ export function getRuntimeTaskV2(taskId) {
974
+ const r = _runtimeTasksV2.get(taskId);
975
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
976
+ }
977
+
978
+ export function setRuntimeTaskStatusV2(_db, taskId, newStatus, patch = {}) {
979
+ const record = _runtimeTasksV2.get(taskId);
980
+ if (!record) throw new Error(`Unknown task: ${taskId}`);
981
+ if (!Object.values(RUNTIME_TASK_V2).includes(newStatus))
982
+ throw new Error(`Invalid status: ${newStatus}`);
983
+ const allowed = RUNTIME_TASK_TRANSITIONS_V2.get(record.status) || new Set();
984
+ if (!allowed.has(newStatus))
985
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
986
+ if (newStatus === RUNTIME_TASK_V2.RUNNING) {
987
+ if (getRunningTaskCount(record.ownerId) >= _maxRunningTasksPerOwnerV2)
988
+ throw new Error(
989
+ `Owner ${record.ownerId} reached running-task cap (${_maxRunningTasksPerOwnerV2})`,
990
+ );
991
+ record.startedAt = Date.now();
992
+ }
993
+ record.status = newStatus;
994
+ record.updatedAt = Date.now();
995
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
996
+ if (patch.metadata)
997
+ record.metadata = { ...record.metadata, ...patch.metadata };
998
+ return { ...record, metadata: { ...record.metadata } };
999
+ }
1000
+
1001
+ export function startRuntimeTask(db, id, reason) {
1002
+ return setRuntimeTaskStatusV2(db, id, RUNTIME_TASK_V2.RUNNING, { reason });
1003
+ }
1004
+ export function completeRuntimeTask(db, id, reason) {
1005
+ return setRuntimeTaskStatusV2(db, id, RUNTIME_TASK_V2.COMPLETED, { reason });
1006
+ }
1007
+ export function failRuntimeTask(db, id, reason) {
1008
+ return setRuntimeTaskStatusV2(db, id, RUNTIME_TASK_V2.FAILED, { reason });
1009
+ }
1010
+ export function cancelRuntimeTask(db, id, reason) {
1011
+ return setRuntimeTaskStatusV2(db, id, RUNTIME_TASK_V2.CANCELED, { reason });
1012
+ }
1013
+
1014
+ export function getActivePluginCount(ownerId) {
1015
+ let n = 0;
1016
+ for (const r of _pluginsV2.values()) {
1017
+ if (r.status !== PLUGIN_MATURITY_V2.ACTIVE) continue;
1018
+ if (ownerId && r.ownerId !== ownerId) continue;
1019
+ n++;
1020
+ }
1021
+ return n;
1022
+ }
1023
+
1024
+ export function getRunningTaskCount(ownerId) {
1025
+ let n = 0;
1026
+ for (const r of _runtimeTasksV2.values()) {
1027
+ if (r.status !== RUNTIME_TASK_V2.RUNNING) continue;
1028
+ if (ownerId && r.ownerId !== ownerId) continue;
1029
+ n++;
1030
+ }
1031
+ return n;
1032
+ }
1033
+
1034
+ export function autoRetireIdlePlugins(_db, nowMs) {
1035
+ const now = nowMs ?? Date.now();
1036
+ const flipped = [];
1037
+ for (const r of _pluginsV2.values()) {
1038
+ if (
1039
+ r.status === PLUGIN_MATURITY_V2.ACTIVE ||
1040
+ r.status === PLUGIN_MATURITY_V2.DEPRECATED
1041
+ ) {
1042
+ if (now - r.lastInvokedAt > _pluginIdleMsV2) {
1043
+ r.status = PLUGIN_MATURITY_V2.RETIRED;
1044
+ r.updatedAt = now;
1045
+ r.lastReason = "idle";
1046
+ flipped.push(r.pluginId);
1047
+ }
1048
+ }
1049
+ }
1050
+ return { flipped, count: flipped.length };
1051
+ }
1052
+
1053
+ export function autoFailStuckRuntimeTasks(_db, nowMs) {
1054
+ const now = nowMs ?? Date.now();
1055
+ const flipped = [];
1056
+ for (const r of _runtimeTasksV2.values()) {
1057
+ if (r.status === RUNTIME_TASK_V2.RUNNING) {
1058
+ const anchor = r.startedAt || r.createdAt;
1059
+ if (now - anchor > _taskStuckMsV2) {
1060
+ r.status = RUNTIME_TASK_V2.FAILED;
1061
+ r.updatedAt = now;
1062
+ r.lastReason = "stuck_timeout";
1063
+ flipped.push(r.taskId);
1064
+ }
1065
+ }
1066
+ }
1067
+ return { flipped, count: flipped.length };
1068
+ }
1069
+
1070
+ export function getRuntimeStatsV2() {
1071
+ const pluginsByStatus = {};
1072
+ for (const s of Object.values(PLUGIN_MATURITY_V2)) pluginsByStatus[s] = 0;
1073
+ const tasksByStatus = {};
1074
+ for (const s of Object.values(RUNTIME_TASK_V2)) tasksByStatus[s] = 0;
1075
+ for (const r of _pluginsV2.values()) pluginsByStatus[r.status]++;
1076
+ for (const r of _runtimeTasksV2.values()) tasksByStatus[r.status]++;
1077
+ return {
1078
+ totalPluginsV2: _pluginsV2.size,
1079
+ totalTasksV2: _runtimeTasksV2.size,
1080
+ maxActivePluginsPerOwner: _maxActivePluginsPerOwnerV2,
1081
+ maxRunningTasksPerOwner: _maxRunningTasksPerOwnerV2,
1082
+ pluginIdleMs: _pluginIdleMsV2,
1083
+ taskStuckMs: _taskStuckMsV2,
1084
+ pluginsByStatus,
1085
+ tasksByStatus,
1086
+ };
1087
+ }
1088
+
1089
+ export function _resetStateV2() {
1090
+ _maxActivePluginsPerOwnerV2 = RT_DEFAULT_MAX_ACTIVE_PLUGINS_PER_OWNER;
1091
+ _maxRunningTasksPerOwnerV2 = RT_DEFAULT_MAX_RUNNING_TASKS_PER_OWNER;
1092
+ _pluginIdleMsV2 = RT_DEFAULT_PLUGIN_IDLE_MS;
1093
+ _taskStuckMsV2 = RT_DEFAULT_TASK_STUCK_MS;
1094
+ _pluginsV2.clear();
1095
+ _runtimeTasksV2.clear();
1096
+ }
@@ -346,3 +346,329 @@ export function getWalletSummary(db) {
346
346
  transactionCount: txns?.c || 0,
347
347
  };
348
348
  }
349
+
350
+ /* ═══════════════════════════════════════════════════════════════
351
+ * V2 Surface — In-memory wallet-maturity + transaction-lifecycle
352
+ * layer. Independent of the SQLite tables; tracks wallet
353
+ * provisioning + tx submission/settlement with caps and auto-flip.
354
+ * ═══════════════════════════════════════════════════════════════ */
355
+
356
+ export const WALLET_MATURITY_V2 = Object.freeze({
357
+ PROVISIONAL: "provisional",
358
+ ACTIVE: "active",
359
+ FROZEN: "frozen",
360
+ RETIRED: "retired",
361
+ });
362
+
363
+ export const TX_LIFECYCLE_V2 = Object.freeze({
364
+ PENDING: "pending",
365
+ SUBMITTED: "submitted",
366
+ CONFIRMED: "confirmed",
367
+ FAILED: "failed",
368
+ REJECTED: "rejected",
369
+ });
370
+
371
+ const WALLET_TRANSITIONS_V2 = new Map([
372
+ ["provisional", new Set(["active", "retired"])],
373
+ ["active", new Set(["frozen", "retired"])],
374
+ ["frozen", new Set(["active", "retired"])],
375
+ ["retired", new Set()],
376
+ ]);
377
+ const WALLET_TERMINALS_V2 = new Set(["retired"]);
378
+
379
+ const TX_TRANSITIONS_V2 = new Map([
380
+ ["pending", new Set(["submitted", "rejected"])],
381
+ ["submitted", new Set(["confirmed", "failed"])],
382
+ ["confirmed", new Set()],
383
+ ["failed", new Set()],
384
+ ["rejected", new Set()],
385
+ ]);
386
+ const TX_TERMINALS_V2 = new Set(["confirmed", "failed", "rejected"]);
387
+
388
+ export const WALLET_DEFAULT_MAX_ACTIVE_WALLETS_PER_OWNER = 10;
389
+ export const WALLET_DEFAULT_MAX_PENDING_TX_PER_WALLET = 25;
390
+ export const WALLET_DEFAULT_WALLET_IDLE_MS = 1000 * 60 * 60 * 24 * 180; // 180 days
391
+ export const WALLET_DEFAULT_TX_STUCK_MS = 1000 * 60 * 60 * 24; // 1 day
392
+
393
+ const _walletsV2 = new Map();
394
+ const _txsV2 = new Map();
395
+ let _maxActiveWalletsPerOwnerV2 = WALLET_DEFAULT_MAX_ACTIVE_WALLETS_PER_OWNER;
396
+ let _maxPendingTxPerWalletV2 = WALLET_DEFAULT_MAX_PENDING_TX_PER_WALLET;
397
+ let _walletIdleMsV2 = WALLET_DEFAULT_WALLET_IDLE_MS;
398
+ let _txStuckMsV2 = WALLET_DEFAULT_TX_STUCK_MS;
399
+
400
+ function _posIntWalletV2(n, label) {
401
+ const v = Math.floor(Number(n));
402
+ if (!Number.isFinite(v) || v <= 0)
403
+ throw new Error(`${label} must be a positive integer`);
404
+ return v;
405
+ }
406
+
407
+ export function getMaxActiveWalletsPerOwnerV2() {
408
+ return _maxActiveWalletsPerOwnerV2;
409
+ }
410
+ export function setMaxActiveWalletsPerOwnerV2(n) {
411
+ _maxActiveWalletsPerOwnerV2 = _posIntWalletV2(n, "maxActiveWalletsPerOwner");
412
+ }
413
+ export function getMaxPendingTxPerWalletV2() {
414
+ return _maxPendingTxPerWalletV2;
415
+ }
416
+ export function setMaxPendingTxPerWalletV2(n) {
417
+ _maxPendingTxPerWalletV2 = _posIntWalletV2(n, "maxPendingTxPerWallet");
418
+ }
419
+ export function getWalletIdleMsV2() {
420
+ return _walletIdleMsV2;
421
+ }
422
+ export function setWalletIdleMsV2(n) {
423
+ _walletIdleMsV2 = _posIntWalletV2(n, "walletIdleMs");
424
+ }
425
+ export function getTxStuckMsV2() {
426
+ return _txStuckMsV2;
427
+ }
428
+ export function setTxStuckMsV2(n) {
429
+ _txStuckMsV2 = _posIntWalletV2(n, "txStuckMs");
430
+ }
431
+
432
+ export function getActiveWalletCountV2(owner) {
433
+ let n = 0;
434
+ for (const w of _walletsV2.values()) {
435
+ if (w.owner === owner && w.maturity === "active") n += 1;
436
+ }
437
+ return n;
438
+ }
439
+
440
+ export function getPendingTxCountV2(walletId) {
441
+ let n = 0;
442
+ for (const t of _txsV2.values()) {
443
+ if (
444
+ t.walletId === walletId &&
445
+ (t.status === "pending" || t.status === "submitted")
446
+ )
447
+ n += 1;
448
+ }
449
+ return n;
450
+ }
451
+
452
+ function _copyWalletV2(w) {
453
+ return { ...w, metadata: { ...w.metadata } };
454
+ }
455
+ function _copyTxV2(t) {
456
+ return { ...t, metadata: { ...t.metadata } };
457
+ }
458
+
459
+ export function registerWalletV2(
460
+ id,
461
+ { owner, address, metadata = {}, now = Date.now() } = {},
462
+ ) {
463
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
464
+ if (!owner || typeof owner !== "string")
465
+ throw new Error("owner must be a string");
466
+ if (!address || typeof address !== "string")
467
+ throw new Error("address must be a string");
468
+ if (_walletsV2.has(id)) throw new Error(`wallet ${id} already exists`);
469
+ const w = {
470
+ id,
471
+ owner,
472
+ address,
473
+ maturity: "provisional",
474
+ createdAt: now,
475
+ lastSeenAt: now,
476
+ activatedAt: null,
477
+ metadata: { ...metadata },
478
+ };
479
+ _walletsV2.set(id, w);
480
+ return _copyWalletV2(w);
481
+ }
482
+
483
+ export function getWalletV2(id) {
484
+ const w = _walletsV2.get(id);
485
+ return w ? _copyWalletV2(w) : null;
486
+ }
487
+
488
+ export function listWalletsV2({ owner, maturity } = {}) {
489
+ const out = [];
490
+ for (const w of _walletsV2.values()) {
491
+ if (owner && w.owner !== owner) continue;
492
+ if (maturity && w.maturity !== maturity) continue;
493
+ out.push(_copyWalletV2(w));
494
+ }
495
+ return out;
496
+ }
497
+
498
+ export function setWalletMaturityV2(id, next, { now = Date.now() } = {}) {
499
+ const w = _walletsV2.get(id);
500
+ if (!w) throw new Error(`wallet ${id} not found`);
501
+ if (!WALLET_TRANSITIONS_V2.has(next))
502
+ throw new Error(`unknown wallet maturity: ${next}`);
503
+ if (WALLET_TERMINALS_V2.has(w.maturity))
504
+ throw new Error(`wallet ${id} is in terminal state ${w.maturity}`);
505
+ const allowed = WALLET_TRANSITIONS_V2.get(w.maturity);
506
+ if (!allowed.has(next))
507
+ throw new Error(`cannot transition wallet from ${w.maturity} to ${next}`);
508
+ if (next === "active") {
509
+ if (w.maturity === "provisional") {
510
+ const count = getActiveWalletCountV2(w.owner);
511
+ if (count >= _maxActiveWalletsPerOwnerV2)
512
+ throw new Error(
513
+ `owner ${w.owner} already at active-wallet cap (${_maxActiveWalletsPerOwnerV2})`,
514
+ );
515
+ }
516
+ if (!w.activatedAt) w.activatedAt = now;
517
+ }
518
+ w.maturity = next;
519
+ w.lastSeenAt = now;
520
+ return _copyWalletV2(w);
521
+ }
522
+
523
+ export function activateWalletV2(id, opts) {
524
+ return setWalletMaturityV2(id, "active", opts);
525
+ }
526
+ export function freezeWalletV2(id, opts) {
527
+ return setWalletMaturityV2(id, "frozen", opts);
528
+ }
529
+ export function retireWalletV2(id, opts) {
530
+ return setWalletMaturityV2(id, "retired", opts);
531
+ }
532
+
533
+ export function touchWalletV2(id, { now = Date.now() } = {}) {
534
+ const w = _walletsV2.get(id);
535
+ if (!w) throw new Error(`wallet ${id} not found`);
536
+ w.lastSeenAt = now;
537
+ return _copyWalletV2(w);
538
+ }
539
+
540
+ export function createTxV2(
541
+ id,
542
+ { walletId, kind, amount, metadata = {}, now = Date.now() } = {},
543
+ ) {
544
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
545
+ if (!walletId || typeof walletId !== "string")
546
+ throw new Error("walletId must be a string");
547
+ if (!kind || typeof kind !== "string")
548
+ throw new Error("kind must be a string");
549
+ if (!_walletsV2.has(walletId))
550
+ throw new Error(`wallet ${walletId} not found`);
551
+ if (_txsV2.has(id)) throw new Error(`tx ${id} already exists`);
552
+ const count = getPendingTxCountV2(walletId);
553
+ if (count >= _maxPendingTxPerWalletV2)
554
+ throw new Error(
555
+ `wallet ${walletId} already at pending-tx cap (${_maxPendingTxPerWalletV2})`,
556
+ );
557
+ const t = {
558
+ id,
559
+ walletId,
560
+ kind,
561
+ amount: amount ?? null,
562
+ status: "pending",
563
+ createdAt: now,
564
+ lastSeenAt: now,
565
+ submittedAt: null,
566
+ settledAt: null,
567
+ metadata: { ...metadata },
568
+ };
569
+ _txsV2.set(id, t);
570
+ return _copyTxV2(t);
571
+ }
572
+
573
+ export function getTxV2(id) {
574
+ const t = _txsV2.get(id);
575
+ return t ? _copyTxV2(t) : null;
576
+ }
577
+
578
+ export function listTxsV2({ walletId, status } = {}) {
579
+ const out = [];
580
+ for (const t of _txsV2.values()) {
581
+ if (walletId && t.walletId !== walletId) continue;
582
+ if (status && t.status !== status) continue;
583
+ out.push(_copyTxV2(t));
584
+ }
585
+ return out;
586
+ }
587
+
588
+ export function setTxStatusV2(id, next, { now = Date.now() } = {}) {
589
+ const t = _txsV2.get(id);
590
+ if (!t) throw new Error(`tx ${id} not found`);
591
+ if (!TX_TRANSITIONS_V2.has(next))
592
+ throw new Error(`unknown tx status: ${next}`);
593
+ if (TX_TERMINALS_V2.has(t.status))
594
+ throw new Error(`tx ${id} is in terminal state ${t.status}`);
595
+ const allowed = TX_TRANSITIONS_V2.get(t.status);
596
+ if (!allowed.has(next))
597
+ throw new Error(`cannot transition tx from ${t.status} to ${next}`);
598
+ if (next === "submitted" && !t.submittedAt) t.submittedAt = now;
599
+ if (TX_TERMINALS_V2.has(next) && !t.settledAt) t.settledAt = now;
600
+ t.status = next;
601
+ t.lastSeenAt = now;
602
+ return _copyTxV2(t);
603
+ }
604
+
605
+ export function submitTxV2(id, opts) {
606
+ return setTxStatusV2(id, "submitted", opts);
607
+ }
608
+ export function confirmTxV2(id, opts) {
609
+ return setTxStatusV2(id, "confirmed", opts);
610
+ }
611
+ export function failTxV2(id, opts) {
612
+ return setTxStatusV2(id, "failed", opts);
613
+ }
614
+ export function rejectTxV2(id, opts) {
615
+ return setTxStatusV2(id, "rejected", opts);
616
+ }
617
+
618
+ export function autoRetireIdleWalletsV2({ now = Date.now() } = {}) {
619
+ const flipped = [];
620
+ for (const w of _walletsV2.values()) {
621
+ if (w.maturity === "retired" || w.maturity === "provisional") continue;
622
+ if (now - w.lastSeenAt > _walletIdleMsV2) {
623
+ w.maturity = "retired";
624
+ w.lastSeenAt = now;
625
+ flipped.push(_copyWalletV2(w));
626
+ }
627
+ }
628
+ return flipped;
629
+ }
630
+
631
+ export function autoFailStuckTxV2({ now = Date.now() } = {}) {
632
+ const flipped = [];
633
+ for (const t of _txsV2.values()) {
634
+ if (t.status !== "submitted") continue;
635
+ const ref = t.submittedAt ?? t.lastSeenAt;
636
+ if (now - ref > _txStuckMsV2) {
637
+ t.status = "failed";
638
+ t.lastSeenAt = now;
639
+ if (!t.settledAt) t.settledAt = now;
640
+ flipped.push(_copyTxV2(t));
641
+ }
642
+ }
643
+ return flipped;
644
+ }
645
+
646
+ export function getWalletManagerStatsV2() {
647
+ const walletsByMaturity = {};
648
+ for (const v of Object.values(WALLET_MATURITY_V2)) walletsByMaturity[v] = 0;
649
+ for (const w of _walletsV2.values()) walletsByMaturity[w.maturity] += 1;
650
+
651
+ const txsByStatus = {};
652
+ for (const v of Object.values(TX_LIFECYCLE_V2)) txsByStatus[v] = 0;
653
+ for (const t of _txsV2.values()) txsByStatus[t.status] += 1;
654
+
655
+ return {
656
+ totalWalletsV2: _walletsV2.size,
657
+ totalTxsV2: _txsV2.size,
658
+ maxActiveWalletsPerOwner: _maxActiveWalletsPerOwnerV2,
659
+ maxPendingTxPerWallet: _maxPendingTxPerWalletV2,
660
+ walletIdleMs: _walletIdleMsV2,
661
+ txStuckMs: _txStuckMsV2,
662
+ walletsByMaturity,
663
+ txsByStatus,
664
+ };
665
+ }
666
+
667
+ export function _resetStateWalletManagerV2() {
668
+ _walletsV2.clear();
669
+ _txsV2.clear();
670
+ _maxActiveWalletsPerOwnerV2 = WALLET_DEFAULT_MAX_ACTIVE_WALLETS_PER_OWNER;
671
+ _maxPendingTxPerWalletV2 = WALLET_DEFAULT_MAX_PENDING_TX_PER_WALLET;
672
+ _walletIdleMsV2 = WALLET_DEFAULT_WALLET_IDLE_MS;
673
+ _txStuckMsV2 = WALLET_DEFAULT_TX_STUCK_MS;
674
+ }