chainlesschain 0.66.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 (143) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +380 -0
  4. package/src/commands/agent-network.js +254 -1
  5. package/src/commands/audit.js +302 -0
  6. package/src/commands/automation.js +271 -1
  7. package/src/commands/bi.js +348 -0
  8. package/src/commands/codegen.js +224 -0
  9. package/src/commands/collab.js +341 -0
  10. package/src/commands/compliance.js +1035 -0
  11. package/src/commands/cowork.js +221 -0
  12. package/src/commands/crosschain.js +218 -0
  13. package/src/commands/dbevo.js +284 -0
  14. package/src/commands/dev.js +252 -0
  15. package/src/commands/did.js +358 -0
  16. package/src/commands/dlp.js +341 -0
  17. package/src/commands/encrypt.js +341 -0
  18. package/src/commands/evomap.js +394 -0
  19. package/src/commands/export.js +256 -1
  20. package/src/commands/federation.js +283 -0
  21. package/src/commands/fusion.js +258 -0
  22. package/src/commands/governance.js +325 -0
  23. package/src/commands/hardening.js +411 -0
  24. package/src/commands/hook.js +148 -0
  25. package/src/commands/import.js +252 -0
  26. package/src/commands/incentive.js +322 -0
  27. package/src/commands/inference.js +318 -0
  28. package/src/commands/infra.js +244 -0
  29. package/src/commands/instinct.js +260 -0
  30. package/src/commands/ipfs.js +318 -0
  31. package/src/commands/kg.js +387 -0
  32. package/src/commands/llm.js +263 -0
  33. package/src/commands/lowcode.js +356 -0
  34. package/src/commands/marketplace.js +256 -0
  35. package/src/commands/mcp.js +221 -0
  36. package/src/commands/memory.js +248 -0
  37. package/src/commands/multimodal.js +296 -0
  38. package/src/commands/nlprog.js +356 -0
  39. package/src/commands/note.js +244 -0
  40. package/src/commands/ops.js +354 -0
  41. package/src/commands/orchestrate.js +166 -0
  42. package/src/commands/org.js +277 -0
  43. package/src/commands/p2p.js +390 -0
  44. package/src/commands/perception.js +290 -0
  45. package/src/commands/permmem.js +251 -0
  46. package/src/commands/plugin-ecosystem.js +273 -0
  47. package/src/commands/pqc.js +393 -0
  48. package/src/commands/privacy.js +321 -0
  49. package/src/commands/quantization.js +351 -0
  50. package/src/commands/rcache.js +271 -0
  51. package/src/commands/recommend.js +340 -0
  52. package/src/commands/reputation.js +261 -0
  53. package/src/commands/runtime.js +307 -0
  54. package/src/commands/scim.js +262 -0
  55. package/src/commands/session.js +258 -0
  56. package/src/commands/siem.js +246 -0
  57. package/src/commands/skill.js +267 -1
  58. package/src/commands/sla.js +259 -0
  59. package/src/commands/social.js +256 -0
  60. package/src/commands/sso.js +186 -1
  61. package/src/commands/stress.js +230 -0
  62. package/src/commands/sync.js +256 -0
  63. package/src/commands/tech.js +338 -0
  64. package/src/commands/tenant.js +351 -0
  65. package/src/commands/terraform.js +245 -0
  66. package/src/commands/tokens.js +269 -0
  67. package/src/commands/trust.js +249 -0
  68. package/src/commands/wallet.js +277 -0
  69. package/src/commands/workflow.js +171 -0
  70. package/src/commands/zkp.js +335 -0
  71. package/src/index.js +4 -0
  72. package/src/lib/a2a-protocol.js +451 -0
  73. package/src/lib/agent-coordinator.js +325 -0
  74. package/src/lib/agent-network.js +387 -0
  75. package/src/lib/agent-router.js +395 -0
  76. package/src/lib/aiops.js +478 -0
  77. package/src/lib/app-builder.js +239 -0
  78. package/src/lib/audit-logger.js +379 -0
  79. package/src/lib/automation-engine.js +330 -0
  80. package/src/lib/autonomous-developer.js +350 -0
  81. package/src/lib/bi-engine.js +338 -0
  82. package/src/lib/code-agent.js +323 -0
  83. package/src/lib/collaboration-governance.js +364 -0
  84. package/src/lib/community-governance.js +436 -0
  85. package/src/lib/compliance-manager.js +434 -0
  86. package/src/lib/content-recommendation.js +469 -0
  87. package/src/lib/cross-chain.js +345 -0
  88. package/src/lib/crypto-manager.js +350 -0
  89. package/src/lib/dbevo.js +338 -0
  90. package/src/lib/decentral-infra.js +340 -0
  91. package/src/lib/did-manager.js +367 -0
  92. package/src/lib/dlp-engine.js +389 -0
  93. package/src/lib/evomap-federation.js +177 -0
  94. package/src/lib/evomap-governance.js +276 -0
  95. package/src/lib/federation-hardening.js +259 -0
  96. package/src/lib/hardening-manager.js +348 -0
  97. package/src/lib/hook-manager.js +380 -0
  98. package/src/lib/inference-network.js +330 -0
  99. package/src/lib/instinct-manager.js +332 -0
  100. package/src/lib/ipfs-storage.js +334 -0
  101. package/src/lib/knowledge-exporter.js +381 -0
  102. package/src/lib/knowledge-graph.js +432 -0
  103. package/src/lib/knowledge-importer.js +379 -0
  104. package/src/lib/llm-providers.js +391 -0
  105. package/src/lib/mcp-registry.js +333 -0
  106. package/src/lib/memory-manager.js +330 -0
  107. package/src/lib/multimodal.js +346 -0
  108. package/src/lib/nl-programming.js +343 -0
  109. package/src/lib/note-versioning.js +327 -0
  110. package/src/lib/org-manager.js +323 -0
  111. package/src/lib/p2p-manager.js +387 -0
  112. package/src/lib/perception.js +346 -0
  113. package/src/lib/perf-tuning.js +4 -1
  114. package/src/lib/permanent-memory.js +320 -0
  115. package/src/lib/plugin-ecosystem.js +377 -0
  116. package/src/lib/pqc-manager.js +368 -0
  117. package/src/lib/privacy-computing.js +427 -0
  118. package/src/lib/protocol-fusion.js +417 -0
  119. package/src/lib/quantization.js +325 -0
  120. package/src/lib/reputation-optimizer.js +299 -0
  121. package/src/lib/response-cache.js +327 -0
  122. package/src/lib/scim-manager.js +329 -0
  123. package/src/lib/session-manager.js +329 -0
  124. package/src/lib/siem-exporter.js +333 -0
  125. package/src/lib/skill-loader.js +377 -0
  126. package/src/lib/skill-marketplace.js +325 -0
  127. package/src/lib/sla-manager.js +275 -0
  128. package/src/lib/social-manager.js +326 -0
  129. package/src/lib/sso-manager.js +332 -0
  130. package/src/lib/stress-tester.js +330 -0
  131. package/src/lib/sync-manager.js +326 -0
  132. package/src/lib/tech-learning-engine.js +369 -0
  133. package/src/lib/tenant-saas.js +460 -0
  134. package/src/lib/terraform-manager.js +363 -0
  135. package/src/lib/threat-intel.js +335 -0
  136. package/src/lib/token-incentive.js +293 -0
  137. package/src/lib/token-tracker.js +329 -0
  138. package/src/lib/trust-security.js +390 -0
  139. package/src/lib/ueba.js +389 -0
  140. package/src/lib/universal-runtime.js +325 -0
  141. package/src/lib/wallet-manager.js +326 -0
  142. package/src/lib/workflow-engine.js +322 -0
  143. package/src/lib/zkp-engine.js +274 -0
@@ -242,3 +242,330 @@ export function revertToVersion(db, noteId, version) {
242
242
  title: targetVersion.title,
243
243
  };
244
244
  }
245
+
246
+ /* ═══════════════════════════════════════════════════════════════
247
+ * V2 Surface — Note governance layer.
248
+ * Tracks per-author note maturity + per-note revision lifecycle
249
+ * independent of legacy SQLite note_versions table.
250
+ * ═══════════════════════════════════════════════════════════════ */
251
+
252
+ export const NOTE_MATURITY_V2 = Object.freeze({
253
+ DRAFT: "draft",
254
+ ACTIVE: "active",
255
+ LOCKED: "locked",
256
+ ARCHIVED: "archived",
257
+ });
258
+
259
+ export const REVISION_LIFECYCLE_V2 = Object.freeze({
260
+ PROPOSED: "proposed",
261
+ REVIEWED: "reviewed",
262
+ APPLIED: "applied",
263
+ SUPERSEDED: "superseded",
264
+ DISCARDED: "discarded",
265
+ });
266
+
267
+ const NOTE_TRANSITIONS_V2 = new Map([
268
+ ["draft", new Set(["active", "archived"])],
269
+ ["active", new Set(["locked", "archived"])],
270
+ ["locked", new Set(["active", "archived"])],
271
+ ["archived", new Set()],
272
+ ]);
273
+ const NOTE_TERMINALS_V2 = new Set(["archived"]);
274
+
275
+ const REV_TRANSITIONS_V2 = new Map([
276
+ ["proposed", new Set(["reviewed", "discarded"])],
277
+ ["reviewed", new Set(["applied", "discarded", "superseded"])],
278
+ ["applied", new Set(["superseded"])],
279
+ ["superseded", new Set()],
280
+ ["discarded", new Set()],
281
+ ]);
282
+ const REV_TERMINALS_V2 = new Set(["superseded", "discarded"]);
283
+
284
+ export const NOTE_DEFAULT_MAX_ACTIVE_NOTES_PER_AUTHOR = 100;
285
+ export const NOTE_DEFAULT_MAX_OPEN_REVS_PER_NOTE = 10;
286
+ export const NOTE_DEFAULT_NOTE_IDLE_MS = 1000 * 60 * 60 * 24 * 30; // 30 days
287
+ export const NOTE_DEFAULT_REV_STUCK_MS = 1000 * 60 * 60 * 24 * 7; // 7 days
288
+
289
+ const _notesV2 = new Map();
290
+ const _revsV2 = new Map();
291
+ let _maxActiveNotesPerAuthorV2 = NOTE_DEFAULT_MAX_ACTIVE_NOTES_PER_AUTHOR;
292
+ let _maxOpenRevsPerNoteV2 = NOTE_DEFAULT_MAX_OPEN_REVS_PER_NOTE;
293
+ let _noteIdleMsV2 = NOTE_DEFAULT_NOTE_IDLE_MS;
294
+ let _revStuckMsV2 = NOTE_DEFAULT_REV_STUCK_MS;
295
+
296
+ function _posIntNoteV2(n, label) {
297
+ const v = Math.floor(Number(n));
298
+ if (!Number.isFinite(v) || v <= 0)
299
+ throw new Error(`${label} must be a positive integer`);
300
+ return v;
301
+ }
302
+
303
+ export function getMaxActiveNotesPerAuthorV2() {
304
+ return _maxActiveNotesPerAuthorV2;
305
+ }
306
+ export function setMaxActiveNotesPerAuthorV2(n) {
307
+ _maxActiveNotesPerAuthorV2 = _posIntNoteV2(n, "maxActiveNotesPerAuthor");
308
+ }
309
+ export function getMaxOpenRevsPerNoteV2() {
310
+ return _maxOpenRevsPerNoteV2;
311
+ }
312
+ export function setMaxOpenRevsPerNoteV2(n) {
313
+ _maxOpenRevsPerNoteV2 = _posIntNoteV2(n, "maxOpenRevsPerNote");
314
+ }
315
+ export function getNoteIdleMsV2() {
316
+ return _noteIdleMsV2;
317
+ }
318
+ export function setNoteIdleMsV2(n) {
319
+ _noteIdleMsV2 = _posIntNoteV2(n, "noteIdleMs");
320
+ }
321
+ export function getRevStuckMsV2() {
322
+ return _revStuckMsV2;
323
+ }
324
+ export function setRevStuckMsV2(n) {
325
+ _revStuckMsV2 = _posIntNoteV2(n, "revStuckMs");
326
+ }
327
+
328
+ export function getActiveNoteCountV2(authorId) {
329
+ let n = 0;
330
+ for (const note of _notesV2.values()) {
331
+ if (note.authorId === authorId && note.status === "active") n += 1;
332
+ }
333
+ return n;
334
+ }
335
+
336
+ export function getOpenRevCountV2(noteId) {
337
+ let n = 0;
338
+ for (const r of _revsV2.values()) {
339
+ if (
340
+ r.noteId === noteId &&
341
+ (r.status === "proposed" || r.status === "reviewed")
342
+ )
343
+ n += 1;
344
+ }
345
+ return n;
346
+ }
347
+
348
+ function _copyNoteV2(n) {
349
+ return { ...n, metadata: { ...n.metadata } };
350
+ }
351
+ function _copyRevV2(r) {
352
+ return { ...r, metadata: { ...r.metadata } };
353
+ }
354
+
355
+ export function registerNoteV2(
356
+ id,
357
+ { authorId, title, metadata = {}, now = Date.now() } = {},
358
+ ) {
359
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
360
+ if (!authorId || typeof authorId !== "string")
361
+ throw new Error("authorId must be a string");
362
+ if (!title || typeof title !== "string")
363
+ throw new Error("title must be a string");
364
+ if (_notesV2.has(id)) throw new Error(`note ${id} already exists`);
365
+ const note = {
366
+ id,
367
+ authorId,
368
+ title,
369
+ status: "draft",
370
+ createdAt: now,
371
+ lastSeenAt: now,
372
+ activatedAt: null,
373
+ archivedAt: null,
374
+ metadata: { ...metadata },
375
+ };
376
+ _notesV2.set(id, note);
377
+ return _copyNoteV2(note);
378
+ }
379
+
380
+ export function getNoteV2(id) {
381
+ const note = _notesV2.get(id);
382
+ return note ? _copyNoteV2(note) : null;
383
+ }
384
+
385
+ export function listNotesV2({ authorId, status } = {}) {
386
+ const out = [];
387
+ for (const note of _notesV2.values()) {
388
+ if (authorId && note.authorId !== authorId) continue;
389
+ if (status && note.status !== status) continue;
390
+ out.push(_copyNoteV2(note));
391
+ }
392
+ return out;
393
+ }
394
+
395
+ export function setNoteStatusV2(id, next, { now = Date.now() } = {}) {
396
+ const note = _notesV2.get(id);
397
+ if (!note) throw new Error(`note ${id} not found`);
398
+ if (!NOTE_TRANSITIONS_V2.has(next))
399
+ throw new Error(`unknown note status: ${next}`);
400
+ if (NOTE_TERMINALS_V2.has(note.status))
401
+ throw new Error(`note ${id} is in terminal state ${note.status}`);
402
+ const allowed = NOTE_TRANSITIONS_V2.get(note.status);
403
+ if (!allowed.has(next))
404
+ throw new Error(`cannot transition note from ${note.status} to ${next}`);
405
+ if (next === "active") {
406
+ if (note.status === "draft") {
407
+ const count = getActiveNoteCountV2(note.authorId);
408
+ if (count >= _maxActiveNotesPerAuthorV2)
409
+ throw new Error(
410
+ `author ${note.authorId} already at active-note cap (${_maxActiveNotesPerAuthorV2})`,
411
+ );
412
+ }
413
+ if (!note.activatedAt) note.activatedAt = now;
414
+ }
415
+ if (next === "archived" && !note.archivedAt) note.archivedAt = now;
416
+ note.status = next;
417
+ note.lastSeenAt = now;
418
+ return _copyNoteV2(note);
419
+ }
420
+
421
+ export function activateNoteV2(id, opts) {
422
+ return setNoteStatusV2(id, "active", opts);
423
+ }
424
+ export function lockNoteV2(id, opts) {
425
+ return setNoteStatusV2(id, "locked", opts);
426
+ }
427
+ export function archiveNoteV2(id, opts) {
428
+ return setNoteStatusV2(id, "archived", opts);
429
+ }
430
+
431
+ export function touchNoteV2(id, { now = Date.now() } = {}) {
432
+ const note = _notesV2.get(id);
433
+ if (!note) throw new Error(`note ${id} not found`);
434
+ note.lastSeenAt = now;
435
+ return _copyNoteV2(note);
436
+ }
437
+
438
+ export function createRevisionV2(
439
+ id,
440
+ { noteId, summary, metadata = {}, now = Date.now() } = {},
441
+ ) {
442
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
443
+ if (!noteId || typeof noteId !== "string")
444
+ throw new Error("noteId must be a string");
445
+ if (!summary || typeof summary !== "string")
446
+ throw new Error("summary must be a string");
447
+ if (_revsV2.has(id)) throw new Error(`revision ${id} already exists`);
448
+ const count = getOpenRevCountV2(noteId);
449
+ if (count >= _maxOpenRevsPerNoteV2)
450
+ throw new Error(
451
+ `note ${noteId} already at open-revision cap (${_maxOpenRevsPerNoteV2})`,
452
+ );
453
+ const r = {
454
+ id,
455
+ noteId,
456
+ summary,
457
+ status: "proposed",
458
+ createdAt: now,
459
+ lastSeenAt: now,
460
+ reviewedAt: null,
461
+ appliedAt: null,
462
+ settledAt: null,
463
+ metadata: { ...metadata },
464
+ };
465
+ _revsV2.set(id, r);
466
+ return _copyRevV2(r);
467
+ }
468
+
469
+ export function getRevisionV2(id) {
470
+ const r = _revsV2.get(id);
471
+ return r ? _copyRevV2(r) : null;
472
+ }
473
+
474
+ export function listRevisionsV2({ noteId, status } = {}) {
475
+ const out = [];
476
+ for (const r of _revsV2.values()) {
477
+ if (noteId && r.noteId !== noteId) continue;
478
+ if (status && r.status !== status) continue;
479
+ out.push(_copyRevV2(r));
480
+ }
481
+ return out;
482
+ }
483
+
484
+ export function setRevisionStatusV2(id, next, { now = Date.now() } = {}) {
485
+ const r = _revsV2.get(id);
486
+ if (!r) throw new Error(`revision ${id} not found`);
487
+ if (!REV_TRANSITIONS_V2.has(next))
488
+ throw new Error(`unknown revision status: ${next}`);
489
+ if (REV_TERMINALS_V2.has(r.status))
490
+ throw new Error(`revision ${id} is in terminal state ${r.status}`);
491
+ const allowed = REV_TRANSITIONS_V2.get(r.status);
492
+ if (!allowed.has(next))
493
+ throw new Error(`cannot transition revision from ${r.status} to ${next}`);
494
+ if (next === "reviewed" && !r.reviewedAt) r.reviewedAt = now;
495
+ if (next === "applied" && !r.appliedAt) r.appliedAt = now;
496
+ if (REV_TERMINALS_V2.has(next) && !r.settledAt) r.settledAt = now;
497
+ r.status = next;
498
+ r.lastSeenAt = now;
499
+ return _copyRevV2(r);
500
+ }
501
+
502
+ export function reviewRevisionV2(id, opts) {
503
+ return setRevisionStatusV2(id, "reviewed", opts);
504
+ }
505
+ export function applyRevisionV2(id, opts) {
506
+ return setRevisionStatusV2(id, "applied", opts);
507
+ }
508
+ export function supersedeRevisionV2(id, opts) {
509
+ return setRevisionStatusV2(id, "superseded", opts);
510
+ }
511
+ export function discardRevisionV2(id, opts) {
512
+ return setRevisionStatusV2(id, "discarded", opts);
513
+ }
514
+
515
+ export function autoLockIdleNotesV2({ now = Date.now() } = {}) {
516
+ const flipped = [];
517
+ for (const note of _notesV2.values()) {
518
+ if (note.status !== "active") continue;
519
+ if (now - note.lastSeenAt > _noteIdleMsV2) {
520
+ note.status = "locked";
521
+ note.lastSeenAt = now;
522
+ flipped.push(_copyNoteV2(note));
523
+ }
524
+ }
525
+ return flipped;
526
+ }
527
+
528
+ export function autoDiscardStaleRevisionsV2({ now = Date.now() } = {}) {
529
+ const flipped = [];
530
+ for (const r of _revsV2.values()) {
531
+ if (r.status !== "proposed" && r.status !== "reviewed") continue;
532
+ if (now - r.lastSeenAt > _revStuckMsV2) {
533
+ r.status = "discarded";
534
+ r.lastSeenAt = now;
535
+ if (!r.settledAt) r.settledAt = now;
536
+ flipped.push(_copyRevV2(r));
537
+ }
538
+ }
539
+ return flipped;
540
+ }
541
+
542
+ export function getNoteVersioningStatsV2() {
543
+ const notesByStatus = {};
544
+ for (const v of Object.values(NOTE_MATURITY_V2)) notesByStatus[v] = 0;
545
+ for (const note of _notesV2.values()) notesByStatus[note.status] += 1;
546
+
547
+ const revisionsByStatus = {};
548
+ for (const v of Object.values(REVISION_LIFECYCLE_V2))
549
+ revisionsByStatus[v] = 0;
550
+ for (const r of _revsV2.values()) revisionsByStatus[r.status] += 1;
551
+
552
+ return {
553
+ totalNotesV2: _notesV2.size,
554
+ totalRevisionsV2: _revsV2.size,
555
+ maxActiveNotesPerAuthor: _maxActiveNotesPerAuthorV2,
556
+ maxOpenRevsPerNote: _maxOpenRevsPerNoteV2,
557
+ noteIdleMs: _noteIdleMsV2,
558
+ revStuckMs: _revStuckMsV2,
559
+ notesByStatus,
560
+ revisionsByStatus,
561
+ };
562
+ }
563
+
564
+ export function _resetStateNoteVersioningV2() {
565
+ _notesV2.clear();
566
+ _revsV2.clear();
567
+ _maxActiveNotesPerAuthorV2 = NOTE_DEFAULT_MAX_ACTIVE_NOTES_PER_AUTHOR;
568
+ _maxOpenRevsPerNoteV2 = NOTE_DEFAULT_MAX_OPEN_REVS_PER_NOTE;
569
+ _noteIdleMsV2 = NOTE_DEFAULT_NOTE_IDLE_MS;
570
+ _revStuckMsV2 = NOTE_DEFAULT_REV_STUCK_MS;
571
+ }
@@ -422,3 +422,326 @@ export function getOrgSummary(db, orgId) {
422
422
  pendingApprovals: pending?.c || 0,
423
423
  };
424
424
  }
425
+
426
+ /* ═══════════════════════════════════════════════════════════════
427
+ * V2 Surface — In-memory org-maturity + member-lifecycle layer.
428
+ * Independent of the SQLite tables above; tracks org governance and
429
+ * member onboarding/offboarding transitions with caps and auto-flip.
430
+ * ═══════════════════════════════════════════════════════════════ */
431
+
432
+ export const ORG_MATURITY_V2 = Object.freeze({
433
+ PROVISIONAL: "provisional",
434
+ ACTIVE: "active",
435
+ SUSPENDED: "suspended",
436
+ ARCHIVED: "archived",
437
+ });
438
+
439
+ export const MEMBER_LIFECYCLE_V2 = Object.freeze({
440
+ INVITED: "invited",
441
+ ACTIVE: "active",
442
+ SUSPENDED: "suspended",
443
+ REVOKED: "revoked",
444
+ DEPARTED: "departed",
445
+ });
446
+
447
+ const ORG_TRANSITIONS_V2 = new Map([
448
+ ["provisional", new Set(["active", "archived"])],
449
+ ["active", new Set(["suspended", "archived"])],
450
+ ["suspended", new Set(["active", "archived"])],
451
+ ["archived", new Set()],
452
+ ]);
453
+ const ORG_TERMINALS_V2 = new Set(["archived"]);
454
+
455
+ const MEMBER_TRANSITIONS_V2 = new Map([
456
+ ["invited", new Set(["active", "revoked"])],
457
+ ["active", new Set(["suspended", "departed", "revoked"])],
458
+ ["suspended", new Set(["active", "departed", "revoked"])],
459
+ ["revoked", new Set()],
460
+ ["departed", new Set()],
461
+ ]);
462
+ const MEMBER_TERMINALS_V2 = new Set(["revoked", "departed"]);
463
+
464
+ export const ORG_DEFAULT_MAX_ACTIVE_ORGS_PER_OWNER = 5;
465
+ export const ORG_DEFAULT_MAX_ACTIVE_MEMBERS_PER_ORG = 200;
466
+ export const ORG_DEFAULT_ORG_IDLE_MS = 1000 * 60 * 60 * 24 * 90; // 90 days
467
+ export const ORG_DEFAULT_INVITE_STALE_MS = 1000 * 60 * 60 * 24 * 30; // 30 days
468
+
469
+ const _orgsV2 = new Map();
470
+ const _membersV2 = new Map();
471
+ let _maxActiveOrgsPerOwnerV2 = ORG_DEFAULT_MAX_ACTIVE_ORGS_PER_OWNER;
472
+ let _maxActiveMembersPerOrgV2 = ORG_DEFAULT_MAX_ACTIVE_MEMBERS_PER_ORG;
473
+ let _orgIdleMsV2 = ORG_DEFAULT_ORG_IDLE_MS;
474
+ let _inviteStaleMsV2 = ORG_DEFAULT_INVITE_STALE_MS;
475
+
476
+ function _posIntOrgV2(n, label) {
477
+ const v = Math.floor(Number(n));
478
+ if (!Number.isFinite(v) || v <= 0)
479
+ throw new Error(`${label} must be a positive integer`);
480
+ return v;
481
+ }
482
+
483
+ export function getMaxActiveOrgsPerOwnerV2() {
484
+ return _maxActiveOrgsPerOwnerV2;
485
+ }
486
+ export function setMaxActiveOrgsPerOwnerV2(n) {
487
+ _maxActiveOrgsPerOwnerV2 = _posIntOrgV2(n, "maxActiveOrgsPerOwner");
488
+ }
489
+ export function getMaxActiveMembersPerOrgV2() {
490
+ return _maxActiveMembersPerOrgV2;
491
+ }
492
+ export function setMaxActiveMembersPerOrgV2(n) {
493
+ _maxActiveMembersPerOrgV2 = _posIntOrgV2(n, "maxActiveMembersPerOrg");
494
+ }
495
+ export function getOrgIdleMsV2() {
496
+ return _orgIdleMsV2;
497
+ }
498
+ export function setOrgIdleMsV2(n) {
499
+ _orgIdleMsV2 = _posIntOrgV2(n, "orgIdleMs");
500
+ }
501
+ export function getInviteStaleMsV2() {
502
+ return _inviteStaleMsV2;
503
+ }
504
+ export function setInviteStaleMsV2(n) {
505
+ _inviteStaleMsV2 = _posIntOrgV2(n, "inviteStaleMs");
506
+ }
507
+
508
+ export function getActiveOrgCountV2(owner) {
509
+ let n = 0;
510
+ for (const o of _orgsV2.values()) {
511
+ if (o.owner === owner && o.maturity === "active") n += 1;
512
+ }
513
+ return n;
514
+ }
515
+
516
+ export function getActiveMemberCountV2(orgId) {
517
+ let n = 0;
518
+ for (const m of _membersV2.values()) {
519
+ if (m.orgId === orgId && m.status === "active") n += 1;
520
+ }
521
+ return n;
522
+ }
523
+
524
+ function _copyOrgV2(o) {
525
+ return { ...o, metadata: { ...o.metadata } };
526
+ }
527
+ function _copyMemberV2(m) {
528
+ return { ...m, metadata: { ...m.metadata } };
529
+ }
530
+
531
+ export function registerOrgV2(
532
+ id,
533
+ { owner, name, metadata = {}, now = Date.now() } = {},
534
+ ) {
535
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
536
+ if (!owner || typeof owner !== "string")
537
+ throw new Error("owner must be a string");
538
+ if (!name || typeof name !== "string")
539
+ throw new Error("name must be a string");
540
+ if (_orgsV2.has(id)) throw new Error(`org ${id} already exists`);
541
+ const org = {
542
+ id,
543
+ owner,
544
+ name,
545
+ maturity: "provisional",
546
+ createdAt: now,
547
+ lastSeenAt: now,
548
+ activatedAt: null,
549
+ metadata: { ...metadata },
550
+ };
551
+ _orgsV2.set(id, org);
552
+ return _copyOrgV2(org);
553
+ }
554
+
555
+ export function getOrgV2(id) {
556
+ const o = _orgsV2.get(id);
557
+ return o ? _copyOrgV2(o) : null;
558
+ }
559
+
560
+ export function listOrgsV2({ owner, maturity } = {}) {
561
+ const out = [];
562
+ for (const o of _orgsV2.values()) {
563
+ if (owner && o.owner !== owner) continue;
564
+ if (maturity && o.maturity !== maturity) continue;
565
+ out.push(_copyOrgV2(o));
566
+ }
567
+ return out;
568
+ }
569
+
570
+ export function setOrgMaturityV2(id, next, { now = Date.now() } = {}) {
571
+ const o = _orgsV2.get(id);
572
+ if (!o) throw new Error(`org ${id} not found`);
573
+ if (!ORG_TRANSITIONS_V2.has(next))
574
+ throw new Error(`unknown org maturity: ${next}`);
575
+ if (ORG_TERMINALS_V2.has(o.maturity))
576
+ throw new Error(`org ${id} is in terminal state ${o.maturity}`);
577
+ const allowed = ORG_TRANSITIONS_V2.get(o.maturity);
578
+ if (!allowed.has(next))
579
+ throw new Error(`cannot transition org from ${o.maturity} to ${next}`);
580
+ if (next === "active") {
581
+ if (o.maturity === "provisional") {
582
+ const count = getActiveOrgCountV2(o.owner);
583
+ if (count >= _maxActiveOrgsPerOwnerV2)
584
+ throw new Error(
585
+ `owner ${o.owner} already at active-org cap (${_maxActiveOrgsPerOwnerV2})`,
586
+ );
587
+ }
588
+ if (!o.activatedAt) o.activatedAt = now;
589
+ }
590
+ o.maturity = next;
591
+ o.lastSeenAt = now;
592
+ return _copyOrgV2(o);
593
+ }
594
+
595
+ export function activateOrgV2(id, opts) {
596
+ return setOrgMaturityV2(id, "active", opts);
597
+ }
598
+ export function suspendOrgV2(id, opts) {
599
+ return setOrgMaturityV2(id, "suspended", opts);
600
+ }
601
+ export function archiveOrgV2(id, opts) {
602
+ return setOrgMaturityV2(id, "archived", opts);
603
+ }
604
+
605
+ export function touchOrgV2(id, { now = Date.now() } = {}) {
606
+ const o = _orgsV2.get(id);
607
+ if (!o) throw new Error(`org ${id} not found`);
608
+ o.lastSeenAt = now;
609
+ return _copyOrgV2(o);
610
+ }
611
+
612
+ export function inviteMemberV2(
613
+ id,
614
+ { orgId, userId, role = "member", metadata = {}, now = Date.now() } = {},
615
+ ) {
616
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
617
+ if (!orgId || typeof orgId !== "string")
618
+ throw new Error("orgId must be a string");
619
+ if (!userId || typeof userId !== "string")
620
+ throw new Error("userId must be a string");
621
+ if (!_orgsV2.has(orgId)) throw new Error(`org ${orgId} not found`);
622
+ if (_membersV2.has(id)) throw new Error(`member ${id} already exists`);
623
+ const member = {
624
+ id,
625
+ orgId,
626
+ userId,
627
+ role,
628
+ status: "invited",
629
+ createdAt: now,
630
+ lastSeenAt: now,
631
+ activatedAt: null,
632
+ departedAt: null,
633
+ metadata: { ...metadata },
634
+ };
635
+ _membersV2.set(id, member);
636
+ return _copyMemberV2(member);
637
+ }
638
+
639
+ export function getMemberV2(id) {
640
+ const m = _membersV2.get(id);
641
+ return m ? _copyMemberV2(m) : null;
642
+ }
643
+
644
+ export function listMembersV2({ orgId, status } = {}) {
645
+ const out = [];
646
+ for (const m of _membersV2.values()) {
647
+ if (orgId && m.orgId !== orgId) continue;
648
+ if (status && m.status !== status) continue;
649
+ out.push(_copyMemberV2(m));
650
+ }
651
+ return out;
652
+ }
653
+
654
+ export function setMemberStatusV2(id, next, { now = Date.now() } = {}) {
655
+ const m = _membersV2.get(id);
656
+ if (!m) throw new Error(`member ${id} not found`);
657
+ if (!MEMBER_TRANSITIONS_V2.has(next))
658
+ throw new Error(`unknown member status: ${next}`);
659
+ if (MEMBER_TERMINALS_V2.has(m.status))
660
+ throw new Error(`member ${id} is in terminal state ${m.status}`);
661
+ const allowed = MEMBER_TRANSITIONS_V2.get(m.status);
662
+ if (!allowed.has(next))
663
+ throw new Error(`cannot transition member from ${m.status} to ${next}`);
664
+ if (next === "active" && m.status === "invited") {
665
+ const count = getActiveMemberCountV2(m.orgId);
666
+ if (count >= _maxActiveMembersPerOrgV2)
667
+ throw new Error(
668
+ `org ${m.orgId} already at active-member cap (${_maxActiveMembersPerOrgV2})`,
669
+ );
670
+ if (!m.activatedAt) m.activatedAt = now;
671
+ }
672
+ if (MEMBER_TERMINALS_V2.has(next) && !m.departedAt) m.departedAt = now;
673
+ m.status = next;
674
+ m.lastSeenAt = now;
675
+ return _copyMemberV2(m);
676
+ }
677
+
678
+ export function activateMemberV2(id, opts) {
679
+ return setMemberStatusV2(id, "active", opts);
680
+ }
681
+ export function suspendMemberV2(id, opts) {
682
+ return setMemberStatusV2(id, "suspended", opts);
683
+ }
684
+ export function revokeMemberV2(id, opts) {
685
+ return setMemberStatusV2(id, "revoked", opts);
686
+ }
687
+ export function departMemberV2(id, opts) {
688
+ return setMemberStatusV2(id, "departed", opts);
689
+ }
690
+
691
+ export function autoArchiveIdleOrgsV2({ now = Date.now() } = {}) {
692
+ const flipped = [];
693
+ for (const o of _orgsV2.values()) {
694
+ if (o.maturity === "archived") continue;
695
+ if (o.maturity === "provisional") continue;
696
+ if (now - o.lastSeenAt > _orgIdleMsV2) {
697
+ o.maturity = "archived";
698
+ o.lastSeenAt = now;
699
+ flipped.push(_copyOrgV2(o));
700
+ }
701
+ }
702
+ return flipped;
703
+ }
704
+
705
+ export function autoRevokeStaleInvitesV2({ now = Date.now() } = {}) {
706
+ const flipped = [];
707
+ for (const m of _membersV2.values()) {
708
+ if (m.status !== "invited") continue;
709
+ if (now - m.lastSeenAt > _inviteStaleMsV2) {
710
+ m.status = "revoked";
711
+ m.lastSeenAt = now;
712
+ if (!m.departedAt) m.departedAt = now;
713
+ flipped.push(_copyMemberV2(m));
714
+ }
715
+ }
716
+ return flipped;
717
+ }
718
+
719
+ export function getOrgManagerStatsV2() {
720
+ const orgsByMaturity = {};
721
+ for (const v of Object.values(ORG_MATURITY_V2)) orgsByMaturity[v] = 0;
722
+ for (const o of _orgsV2.values()) orgsByMaturity[o.maturity] += 1;
723
+
724
+ const membersByStatus = {};
725
+ for (const v of Object.values(MEMBER_LIFECYCLE_V2)) membersByStatus[v] = 0;
726
+ for (const m of _membersV2.values()) membersByStatus[m.status] += 1;
727
+
728
+ return {
729
+ totalOrgsV2: _orgsV2.size,
730
+ totalMembersV2: _membersV2.size,
731
+ maxActiveOrgsPerOwner: _maxActiveOrgsPerOwnerV2,
732
+ maxActiveMembersPerOrg: _maxActiveMembersPerOrgV2,
733
+ orgIdleMs: _orgIdleMsV2,
734
+ inviteStaleMs: _inviteStaleMsV2,
735
+ orgsByMaturity,
736
+ membersByStatus,
737
+ };
738
+ }
739
+
740
+ export function _resetStateOrgManagerV2() {
741
+ _orgsV2.clear();
742
+ _membersV2.clear();
743
+ _maxActiveOrgsPerOwnerV2 = ORG_DEFAULT_MAX_ACTIVE_ORGS_PER_OWNER;
744
+ _maxActiveMembersPerOrgV2 = ORG_DEFAULT_MAX_ACTIVE_MEMBERS_PER_ORG;
745
+ _orgIdleMsV2 = ORG_DEFAULT_ORG_IDLE_MS;
746
+ _inviteStaleMsV2 = ORG_DEFAULT_INVITE_STALE_MS;
747
+ }