@serve.zone/dcrouter 32.1.2 → 32.1.4

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.
package/readme.md CHANGED
@@ -342,6 +342,8 @@ Web Push is disabled by default and does not read its secret configuration while
342
342
 
343
343
  Each key ring has the form `{"currentKeyId":"key-2026-07","keys":{"key-2026-07":"<32-byte-unpadded-base64url>"}}`, supports at most eight distinct keys, and must name a configured current key. Encryption and HMAC rings must never reuse key material.
344
344
 
345
+ All four values are resolved through `@push.rocks/qenv` from the process environment, a `.nogit/env.json` beside the working directory, or a Docker secret, in that order. dcrouter ships no `qenv.yml` and declares no `required:` list, because none of these names is mandatory while the feature is off: with the flag on, `WebPushManager.start()` refuses and names the missing key material, and the `webpush-encryption-context` migration refuses when sealed documents exist without `DCROUTER_WEB_PUSH_MASTER_KEY_RING`. A `qenv.yml` left in the working directory is not enforced at start; it only logs the names it finds missing.
346
+
345
347
  Operational behavior:
346
348
 
347
349
  - Control-plane callers need gateway-client `readWebPush` or `manageWebPush` capability. App calls use the one-time binding credential returned by `syncWebPushBinding`; the active credential record stores only its HMAC verifier. To recover a lost rotation response, dcrouter may return the same issuance again during its 15-minute overlap window; that recovery secret is AES-GCM encrypted at rest and is removed when the window expires.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '32.1.2',
6
+ version: '32.1.4',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }
@@ -419,8 +419,16 @@ export class DcRouter {
419
419
  // Live DoH routes used during SmartProxy bootstrap before RouteConfigManager re-applies stored routes.
420
420
  private runtimeDnsRoutes: plugins.smartproxy.IRouteConfig[] = [];
421
421
 
422
- // Environment access
423
- private qenv = new plugins.qenv.Qenv('./', '.nogit/');
422
+ // Environment access. dcrouter ships no qenv.yml and declares no `required:` list, because it has
423
+ // no unconditionally mandatory variable: every name it reads is conditional on a feature being
424
+ // switched on or on what is already stored (the Web Push key rings, and the master key ring the
425
+ // reseal migration below only demands when sealed documents exist), and every other name is read
426
+ // straight from `process.env` with a default of its own. The reader owns the refusal in each case
427
+ // and names the missing variable and the feature it blocks, so `failOnMissing` is false here and
428
+ // at the second construction site
429
+ // (`ts/webpush/classes.webpush-manager.ts`): a qenv.yml an operator leaves in the working
430
+ // directory must never take the DNS and mail gateway down for a disabled optional feature.
431
+ private qenv = new plugins.qenv.Qenv('./', '.nogit/', false);
424
432
 
425
433
  constructor(optionsArg: IDcRouterOptions) {
426
434
  const coreTrafficConfig = optionsArg.coreTrafficConfig || optionsArg.smartProxyConfig;
@@ -99,7 +99,7 @@ export class WebPushBindingDoc extends plugins.smartdata.SmartDataDbDoc<
99
99
  WebPushBindingDoc,
100
100
  WebPushBindingDoc
101
101
  > {
102
- @plugins.smartdata.svDb()
102
+ @plugins.smartdata.unI({ indexName: 'web_push_binding_id_unique' })
103
103
  public id!: string;
104
104
 
105
105
  @plugins.smartdata.svDb()
@@ -48,7 +48,7 @@ export class WebPushSpoolDoc extends plugins.smartdata.SmartDataDbDoc<
48
48
  WebPushSpoolDoc,
49
49
  WebPushSpoolDoc
50
50
  > {
51
- @plugins.smartdata.svDb()
51
+ @plugins.smartdata.unI({ indexName: 'web_push_spool_id_unique' })
52
52
  public id!: string;
53
53
 
54
54
  @plugins.smartdata.svDb()
@@ -621,6 +621,9 @@ export class WebPushManager {
621
621
  private inactiveLifecycleCursor?: string;
622
622
 
623
623
  public constructor(optionsArg: IWebPushManagerOptions = {}) {
624
+ // Same arguments as the DcRouter-owned instance (`ts/classes.dcrouter.ts`), for the reason
625
+ // stated there: no qenv.yml declares these names as required, because they are only required
626
+ // once DCROUTER_WEB_PUSH_ENABLED is on — `start()` below is what refuses, naming all three.
624
627
  this.qenv = optionsArg.qenv ?? new plugins.qenv.Qenv('./', '.nogit/', false);
625
628
  this.transport = optionsArg.transport ?? new WebPushHttpTransport();
626
629
  this.startWorker = optionsArg.startWorker !== false;
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '32.1.2',
6
+ version: '32.1.4',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }