@sdux-vault/engine 0.13.0 → 0.25.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.
@@ -1,4 +1,4 @@
1
- import { registerVersion, vaultDebug, ControllerVotes, ControllerMessageTypes, OperationTypes, vaultWarn, VaultController, defineControllerKey, ControllerTypes, DevMode, DecisionOutcomeTypes, vaultError, defineBehaviorKey, DEVTOOLS_LOGGING_KEY_CONSTANT, DEVTOOLS_AGGREGATE_KEY_CONSTANT, createVaultError, EventTypes, EventBoundaryTypes, setVaultLogLevel, isTestEnv, BEHAVIOR_META, validateBehaviorKey, BehaviorTypes, VAULT_STOP, isVaultNoop, VaultLicenseError, VaultBehavior, VaultPrivateErrorService, isHttpResourceRef, isFunction, isStateInputShape, isolateValue, isVaultClearState, VAULT_CLEAR_STATE, VAULT_NOOP, VAULT_CONTINUE, isVaultContinue, isUndefined, isDefined, isNullish, ResolveTypes, isPromise, VaultUsagePromiseError, CONTROLLER_META, validateControllerKey } from '@sdux-vault/shared';
1
+ import { registerVersion, vaultDebug, ControllerVotes, ControllerMessageTypes, OperationTypes, vaultWarn, VaultController, defineControllerKey, ControllerTypes, DevMode, DecisionOutcomeTypes, vaultError, defineBehaviorKey, DEVTOOLS_LOGGING_KEY_CONSTANT, DEVTOOLS_AGGREGATE_KEY_CONSTANT, createVaultError, EventTypes, EventBoundaryTypes, setVaultLogLevel, isTestEnv, BEHAVIOR_META, BehaviorTypes, validateBehaviorKey, VAULT_STOP, isVaultNoop, VaultLicenseError, VaultBehavior, VaultPrivateErrorService, isHttpResourceRef, isFunction, isStateInputShape, isolateValue, isVaultClearState, VAULT_CLEAR_STATE, VAULT_NOOP, VAULT_CONTINUE, isVaultContinue, isUndefined, isDefined, isNullish, ResolveTypes, isPromise, VaultUsagePromiseError, CONTROLLER_META, validateControllerKey } from '@sdux-vault/shared';
2
2
  import { of, map, catchError, forkJoin, Subject, ReplaySubject, isObservable, firstValueFrom, tap } from 'rxjs';
3
3
  import { __decorate } from 'tslib';
4
4
  import { filter } from 'rxjs/operators';
@@ -11,7 +11,7 @@ import { EventBus, initDevtoolsWidget } from '@sdux-vault/devtools';
11
11
  // cmd+alt+j (see .vscode/keybindings.json)
12
12
  // --- END AI MODEL FILE PATH ---
13
13
  const SDUX_PACKAGE = '@sdux-vault/engine';
14
- const SDUX_VERSION = '0.13.0';
14
+ const SDUX_VERSION = '0.25.0';
15
15
  registerVersion(SDUX_PACKAGE, SDUX_VERSION);
16
16
 
17
17
  /**
@@ -1551,6 +1551,10 @@ const KNOWN_VAULT_KEYS = new Set([
1551
1551
  'SDUX::Controller::Policy::CoreError',
1552
1552
  'SDUX::Controller::Policy::CoreLicense',
1553
1553
  // ---------------------------------------------------------------------------
1554
+ // Core Controllers (libs/core)
1555
+ // ---------------------------------------------------------------------------
1556
+ 'SDUX::Controller::Policy::TabSync',
1557
+ // ---------------------------------------------------------------------------
1554
1558
  // Addon Controllers (libs/addons)
1555
1559
  // ---------------------------------------------------------------------------
1556
1560
  'SDUX::Controller::Policy::Delay',
@@ -2064,13 +2068,21 @@ class BehaviorInitializationClass {
2064
2068
  #initialized = false;
2065
2069
  /** FeatureCell identifier associated with this initializer. */
2066
2070
  #cellKey;
2071
+ /** Live reference to the FeatureCell's mutable last-snapshot object. */
2072
+ #lastSnapshot;
2073
+ /** Subject used by the FeatureCell to emit state snapshots. */
2074
+ #state$;
2067
2075
  /**
2068
2076
  * Creates a new behavior initializer for a specific FeatureCell.
2069
2077
  *
2070
2078
  * @param cellKey - The unique FeatureCell key.
2079
+ * @param lastSnapshot - Live reference to the FeatureCell's mutable state snapshot.
2080
+ * @param state$ - Subject used to emit state snapshots.
2071
2081
  */
2072
- constructor(cellKey) {
2082
+ constructor(cellKey, lastSnapshot, state$) {
2073
2083
  this.#cellKey = cellKey;
2084
+ this.#lastSnapshot = lastSnapshot;
2085
+ this.#state$ = state$;
2074
2086
  }
2075
2087
  /**
2076
2088
  * Instantiates and validates all behaviors declared for a FeatureCell.
@@ -2141,11 +2153,19 @@ class BehaviorInitializationClass {
2141
2153
  }
2142
2154
  let instance;
2143
2155
  try {
2144
- instance = new BehaviorClass(behaviorKey, {
2156
+ let behaviorContract = {
2145
2157
  featureCellKey: this.#cellKey,
2146
2158
  behaviorConfig,
2147
2159
  licensePayload
2148
- });
2160
+ };
2161
+ if (meta.type === BehaviorTypes.TabSyncState) {
2162
+ behaviorContract = {
2163
+ ...behaviorContract,
2164
+ lastSnapshot: this.#lastSnapshot,
2165
+ state$: this.#state$
2166
+ };
2167
+ }
2168
+ instance = new BehaviorClass(behaviorKey, behaviorContract);
2149
2169
  }
2150
2170
  catch (error) {
2151
2171
  isCritical = meta.critical;
@@ -2327,27 +2347,21 @@ const PublicKeys = {
2327
2347
  */
2328
2348
  pro: `
2329
2349
  -----BEGIN PUBLIC KEY-----
2350
+ MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuXto+eRaFm9pObys/IEI ASwV1wgGvNGJsiyw/9hXsEd9mA76aQI1X9lpkZRKmBFovHdK2unPHFOPQM0k9vJo ieFMNXO9kmHn7UYZV98bDCcDTNURFHQ4SWlcAE/HEiNqcUb9LwotFbON7/mcthM8 QQQ4Lycdv+lm1uozQl8rl+i7FjfQzLaxJMuAkm9jFZK+ta6eoSy/lmXfhDem8RIo dE19aZWfY+LTXP9nn977XFah0z0S0D3NSvMv96gZsXTN2hTbFBl5dgDMAOW9R5OI wT6I+kGwrVqARXq2pTDHnZjqfO3a+rT4Lrb5/L58RjQ0EfA5puZ16EXGEUpOabqI KVT4Z/wv818P8eyat+LtTcy2G0zx/h0Fcz0QANzx3P9K7ezxeqdg4SsjkcNXRWZq PaJUhZHygN/Xuef9zfWwjuKobCBSdyyeXxF5XS0A0Y6NBmdhikyHc/YOY2iYupIt xiUvlHaq97B5wej3XcTmp4kmJUQyeQ8oD5Mj8Dmf69oa7vhI/ANNKWo9s8e7u7UX Dx74Eu3d8JBpACQ+Vvek6ZEGw+D0yCyLF6u/CaCw+cb2cBYAlM7jWZ5kpgsbQcWw YP2nbGV3OofcEspoEU704M4RW4v+nSRYrJbMEIJJ5Wuxk2/RuUgk/9uwgCHAvzXZ cmGomIf9dXZGoNhwT5uW1OECAwEAAQ==
2330
2351
  -----END PUBLIC KEY-----
2331
2352
  `,
2332
2353
  /**
2333
2354
  * the enterprise public key
2334
2355
  */
2335
2356
  enterprise: `
2336
- -----BEGIN PUBLIC KEY-----
2357
+ -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6k4XHyV4WE6Bd/fizN4Q c3C37LtskNTJ1c3FVxcziygAFd+fotRfbLHctwtJJhuO6+Pv+c1SPjrPeJsWRw4M IN7QHcBQHPbQDW/Erd1XjA0OVNbxs3xLVjtgMuVcd2sKYPp4nJqIyz5WLMde7v1g 1k8knI+ISrym0h4GcjkNSaHK5QKKpK7n3dzOXrjo1P6h1uOVsGAHC/ErVMQNHrAu dKgY+SDVn87oPIrd2pJb5SotI6H8HzODM/CDsF58hk/eK4zApnrtDViVb1j3oNCk hdDOnN98VIgwcHzHYZOhPFM0TFwudpi57Yu/PJJztI7WbsjpxTyX3JPvwVeWJR+Z tt6NEQ5ZaoBghGgHGiuRbhKR5qoznwsMkfb2jUbpbgRTinmtEjFmpIYSnROCixjq W1neupzBDrNi+JfoVsTwiP8SbzxHXWksN0gLMfL235l1LDMS/IrI3RmhcRkhB/Pu vPuc+jhPkwpbXaM9vDkkPWK1dmRYHWo3atYCWoSdK2705woo19oT8Dxm9OXKT+nh HsdOI+k9asBCqe4kQHi3OJ4Raesa6bFWWxKFLeUNKSAt7clJKo7GhrovnHIIAbty gk7ULdwLIlpjwB5mVUBBCts5z9KznHo+pumNoeEA8FGqq374a+jEPOHWjsshA678 RDYeqeRbh2VNcy/OwlqH/MUCAwEAAQ==
2337
2358
  -----END PUBLIC KEY-----
2338
2359
  `,
2339
2360
  /**
2340
2361
  * the development public key
2341
2362
  */
2342
2363
  development: `
2343
- -----BEGIN PUBLIC KEY-----
2344
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6RDckQGY38NrlPq70YfI
2345
- hIpBFmc9baNLS2HIeyKIU2m+Vvnt3AYcQJlQnzmO4ZLDOUkIP+VxAjaSCaUBeTOx
2346
- KDYXAK8ds0xEur0cRV4Kn26jhLveLZVpfVzhkOjJ6I9ggLeh5JRt7kj3NPgKwnSm
2347
- t5DxLh4JPyLfZdBDtW8tU2tCgCfEs2cArrVo/fg7Dei8FJ8w83PDhsKmX5UazSfj
2348
- MC57gkTZ/cZmKBvVoIhnqaWVXcRRL+wZPArIsO801DRiMAhROyQYyC3EKpGLyUc1
2349
- 1VSKqdmQLIUE1pt151EnmStB+VOsMzCLZH4TyU7cd1Afs2Siqu947W2w4Qpm5+Y/
2350
- FwIDAQAB
2364
+ -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsAFRjQalSEZkCDPrdBEf IMQpY7ujGf4pqjuFk86rkZENr7kJ00RjVJxuhcafgygdmxVAhKS+d1WtsSAw6c9m AawI+sSyhAClB+wrwfuCrxt/ZlLbNMiMH5SD1YvoRaHstkLpMGbWnbsLDI+cCpaL hGKk+5LoJLikhf9ipBkGX8VSAT0xTMk06iaYtEV85H9cMWtfx7seyBw2Mps/8S6f Rtp3tLlbNJIyh9+5XjtkTqYNRWJtFW1rv75K9GN9dPVXrEXUGojqeV13G+z2R3Sr QvmhESkyC1DviZBxaYnEhpWoijJQFJUQ1DGRi29ugktYzf36Otw9gyz9jGb5MLNE W+meR2LdnbTBy83QNtaS5lCzNJVo2ohwbD+djblNVegH/Dr0rK4IHEYSgjdxjErY 6xqykJpKJ025CTU4kyI3aaaYB+l2CQMAKVAh2y2rgGyJSJnMDTR44aBIZ8rtTu2r wazjBJ/RiMr0OOkfBqEQPKZ6qzSWtBDebvD0iUyRAP8SXSdDo1DcaJNamLLmjIxr 3KCcwgJt2oLcdZZHKG3WbjqmIdp7tq03O4gajKJHd5GmyLWtHXKqBwaijAx9aNqr qDPWj/Qg/8C9qpSBs7EUod3slV6UhO4yEnb7FdD/O0o8mRMU0rtJ0KQTarpEh2bY MKVsYxByiFeAjUJUWLSqIX8CAwEAAQ==
2351
2365
  -----END PUBLIC KEY-----
2352
2366
  `
2353
2367
  };
@@ -2367,6 +2381,12 @@ FwIDAQAB
2367
2381
  *
2368
2382
  * Verification failures return `false` rather than throwing.
2369
2383
  */
2384
+ let hasLoggedLicenseDetails = false;
2385
+ function resetLicenseDetailsLog() {
2386
+ if (!DevMode.active)
2387
+ return;
2388
+ hasLoggedLicenseDetails = false;
2389
+ }
2370
2390
  const VerifyLicenseToken = {
2371
2391
  /**
2372
2392
  * Verifies the supplied signed license token using the public key associated
@@ -2392,6 +2412,11 @@ const VerifyLicenseToken = {
2392
2412
  if (!licenseType) {
2393
2413
  return false;
2394
2414
  }
2415
+ if (!DevMode.active && licenseType === 'development') {
2416
+ // eslint-disable-next-line
2417
+ console.error('[sdux-vault] Development license token rejected in production environment.');
2418
+ return false;
2419
+ }
2395
2420
  const keyPem = PublicKeys[licenseType];
2396
2421
  if (!keyPem)
2397
2422
  return false;
@@ -2400,9 +2425,45 @@ const VerifyLicenseToken = {
2400
2425
  name: 'RSASSA-PKCS1-v1_5',
2401
2426
  hash: 'SHA-256'
2402
2427
  }, key, signature, new TextEncoder().encode(encodedPayload));
2428
+ if (!hasLoggedLicenseDetails) {
2429
+ hasLoggedLicenseDetails = true;
2430
+ if (verified) {
2431
+ // eslint-disable-next-line
2432
+ console.info(`[sdux-vault] License verified — organization: "${payload.organization}", tier: "${payload.licenseType}"`);
2433
+ }
2434
+ else {
2435
+ // eslint-disable-next-line
2436
+ console.warn(`[sdux-vault] License signature invalid — organization: "${payload.organization}", tier: "${payload.licenseType}"`);
2437
+ }
2438
+ // eslint-disable-next-line
2439
+ console.info('[sdux-vault] License organization:', payload.organization);
2440
+ // eslint-disable-next-line
2441
+ console.info('[sdux-vault] License domain:', payload.domain);
2442
+ // eslint-disable-next-line
2443
+ console.info('[sdux-vault] License type:', payload.licenseType);
2444
+ // eslint-disable-next-line
2445
+ console.info('[sdux-vault] License issuedAt:', formatLicenseDate(payload.issuedAt));
2446
+ // eslint-disable-next-line
2447
+ console.info('[sdux-vault] License expires:', formatLicenseDate(payload.expires));
2448
+ }
2449
+ if (verified && payload.licenseType === 'enterprise' && typeof payload.expires === 'number') {
2450
+ const msUntilExpiry = payload.expires - Date.now();
2451
+ if (msUntilExpiry < 0) {
2452
+ // eslint-disable-next-line
2453
+ console.error(`[sdux-vault] Enterprise license expired — organization: "${payload.organization}", expired: ${formatLicenseDate(payload.expires)}`);
2454
+ return false;
2455
+ }
2456
+ const fifteenDaysMs = 15 * 24 * 60 * 60 * 1000;
2457
+ if (msUntilExpiry <= fifteenDaysMs) {
2458
+ // eslint-disable-next-line
2459
+ console.warn(`[sdux-vault] Enterprise license expiring soon — organization: "${payload.organization}", expires: ${formatLicenseDate(payload.expires)}`);
2460
+ }
2461
+ }
2403
2462
  return verified;
2404
2463
  }
2405
- catch {
2464
+ catch (error) {
2465
+ // eslint-disable-next-line
2466
+ console.error('[sdux-vault] License token verification failed:', error);
2406
2467
  return false;
2407
2468
  }
2408
2469
  }
@@ -2445,6 +2506,35 @@ function str2ab(str) {
2445
2506
  arr[i] = str.charCodeAt(i);
2446
2507
  return buf;
2447
2508
  }
2509
+ /**
2510
+ * Formats a license date value for display. Numeric timestamps are
2511
+ * formatted as locale-aware date strings; string values such as
2512
+ * `'forever'` are returned as-is.
2513
+ *
2514
+ * @param value - A Unix-epoch millisecond timestamp or a string literal.
2515
+ * @returns A human-readable date string.
2516
+ */
2517
+ function formatLicenseDate(value) {
2518
+ if (typeof value === 'string')
2519
+ return value;
2520
+ return new Intl.DateTimeFormat('en-US', {
2521
+ month: '2-digit',
2522
+ day: '2-digit',
2523
+ year: 'numeric'
2524
+ }).format(new Date(value));
2525
+ }
2526
+
2527
+ async function verifyLicensePayload(licensePayload) {
2528
+ try {
2529
+ if (!licensePayload) {
2530
+ return false;
2531
+ }
2532
+ return await VerifyLicenseToken.verify(licensePayload);
2533
+ }
2534
+ catch {
2535
+ return false;
2536
+ }
2537
+ }
2448
2538
 
2449
2539
  class LicensingAbstract {
2450
2540
  static needsLicense;
@@ -2456,7 +2546,7 @@ class LicensingAbstract {
2456
2546
  constructor(ctx) {
2457
2547
  const ctor = this.constructor;
2458
2548
  if (typeof ctor.key !== 'string' || !ctor.key.trim()) {
2459
- throw new VaultLicenseError(`LicensingClass requires a static "key". Did you forget @VaultBehavior?`);
2549
+ throw new VaultLicenseError(`LicensingClass requires a static "key". Did you forget @VaultBehavior or @VaultController?`);
2460
2550
  }
2461
2551
  this.#licenseService = LicensingService();
2462
2552
  this.#key = ctor.key;
@@ -2489,21 +2579,7 @@ let withCoreLicenseBehavior = class withCoreLicenseBehavior extends LicensingAbs
2489
2579
  super(behaviorCtx);
2490
2580
  this.behaviorCtx = behaviorCtx;
2491
2581
  this.key = key;
2492
- this.#performLicenseValidation();
2493
- }
2494
- async #performLicenseValidation() {
2495
- try {
2496
- const payload = this.behaviorCtx.licensePayload;
2497
- if (!payload?.token) {
2498
- this.validateLicense(false);
2499
- return;
2500
- }
2501
- const isValid = await VerifyLicenseToken.verify(payload.token);
2502
- this.validateLicense(isValid);
2503
- }
2504
- catch {
2505
- this.validateLicense(false);
2506
- }
2582
+ verifyLicensePayload(this.behaviorCtx.licensePayload).then((valid) => this.validateLicense(valid));
2507
2583
  }
2508
2584
  destroy() {
2509
2585
  vaultWarn(`${this.key} - destroy noop`);
@@ -2731,7 +2807,7 @@ class Orchestrator {
2731
2807
  if (hasTabSync) {
2732
2808
  allBehaviors = allBehaviors.filter((behavior) => behavior.type !== BehaviorTypes.CoreState);
2733
2809
  }
2734
- const behaviorInit = new BehaviorInitializationClass(this.cellKey);
2810
+ const behaviorInit = new BehaviorInitializationClass(this.cellKey, config.lastSnapshot, config.state$);
2735
2811
  this.#registerBehaviorsWithVault(allBehaviors);
2736
2812
  this.#behaviors = behaviorInit.initializeBehaviors(allBehaviors, config.behaviorConfigs);
2737
2813
  this.#registerErrorBehavior();
@@ -3751,6 +3827,8 @@ class Conductor extends Orchestrator {
3751
3827
  this.vaultMonitor.conductorLicenseDenied(this.cellKey, event.traceId);
3752
3828
  this.#conductorLicenseStatus = ConductorLicenseStatusTypes.Denied;
3753
3829
  const error = new Error(`${this.cellKey} Conductor Decision Engine: The FeatureCell received a "License Denied". Pipeline is disabled.`);
3830
+ // eslint-disable-next-line
3831
+ console.error(`[vault] ${error.message}`);
3754
3832
  vaultDebug(error.message);
3755
3833
  this.privateErrorService.setError(createVaultError(error, this.cellKey));
3756
3834
  this.#attemptQueue.length = 0;
@@ -4113,8 +4191,10 @@ class FeatureCellBuilder {
4113
4191
  filterCallbacks: ctx.filterFunctions,
4114
4192
  initialState: ctx.hydrate || this.featureCellConfiguration.initialState,
4115
4193
  interceptors: ctx.interceptors,
4194
+ lastSnapshot: this.ctx.lastSnapshot,
4116
4195
  operators: ctx.operators,
4117
- reducerCallbacks: ctx.reducerFunctions
4196
+ reducerCallbacks: ctx.reducerFunctions,
4197
+ state$: this.state$
4118
4198
  });
4119
4199
  this.#conductor.initialize(this.ctx);
4120
4200
  if (DevMode.active) {
@@ -4417,5 +4497,5 @@ function resetFeatureCellToken() {
4417
4497
  * Generated bundle index. Do not edit.
4418
4498
  */
4419
4499
 
4420
- export { Conductor, FeatureCellClass, LicensingAbstract, VAULT_LICENSE_ID, VaultCore, VerifyLicenseToken, createFeatureCellToken, getFeatureCellToken, getLicensePayload, getVaultRegistryForTests, hasVaultLicense, isAuthorizedKey, isBypassLicensing, isPipelineTerminal, registerFeatureCell, registerVaultSettled, resetFeatureCellRegistry, resetVaultForTests, vaultAllSettled, vaultSettled };
4500
+ export { Conductor, FeatureCellClass, LicensingAbstract, VAULT_LICENSE_ID, VaultCore, VerifyLicenseToken, createFeatureCellToken, getFeatureCellToken, getLicensePayload, getVaultRegistryForTests, hasVaultLicense, isAuthorizedKey, isBypassLicensing, isPipelineTerminal, registerFeatureCell, registerVaultSettled, resetFeatureCellRegistry, resetVaultForTests, vaultAllSettled, vaultSettled, verifyLicensePayload };
4421
4501
  //# sourceMappingURL=sdux-vault-engine.mjs.map