@rpcbase/server 0.482.0 → 0.483.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,7 +1,7 @@
1
1
  import { models } from "@rpcbase/db";
2
2
  import { buildAbilityFromSession, getAccessibleByQuery } from "@rpcbase/db/acl";
3
3
  import { createNotification, sendNotificationsDigestForUser } from "./notifications.js";
4
- import { o as object, b as boolean, n as number, a as array, s as string, r as record, u as unknown, _ as _enum } from "./schemas-D5T9tDtI.js";
4
+ import { o as object, b as boolean, n as number, a as array, s as string, r as record, _ as _enum, u as unknown } from "./schemas-7qqi9OQy.js";
5
5
  const getSessionUser = (ctx) => {
6
6
  const rawSessionUser = ctx.req.session?.user;
7
7
  const userId = typeof rawSessionUser?.id === "string" ? rawSessionUser.id.trim() : "";
@@ -1,6 +1,6 @@
1
1
  import { models, ZRBRtsChangeOp } from "@rpcbase/db";
2
2
  import { buildAbilityFromSession } from "@rpcbase/db/acl";
3
- import { o as object, a as array, s as string, n as number, b as boolean, _ as _enum } from "./schemas-D5T9tDtI.js";
3
+ import { o as object, a as array, s as string, n as number, b as boolean, _ as _enum } from "./schemas-7qqi9OQy.js";
4
4
  const Route = "/api/rb/rts/changes";
5
5
  const requestSchema = object({
6
6
  sinceSeq: number().int().min(0).default(0),
@@ -4,7 +4,7 @@ import { JSDOM } from "jsdom";
4
4
  import createDOMPurify from "dompurify";
5
5
  import { g as getTenantId, a as getModelCtx, b as buildUploadsAbility, c as getUploadSessionAccessQuery, e as ensureUploadIndexes, d as getBucketName, f as getUserId, h as getChunkSizeBytes, i as getSessionTtlMs, j as computeSha256Hex, t as toBufferPayload, n as normalizeSha256Hex, k as getMaxClientUploadBytesPerSecond, l as getRawBodyLimitBytes } from "./shared-BJomDDWK.js";
6
6
  import { randomBytes } from "node:crypto";
7
- import { o as object, n as number, b as boolean, s as string, a as array, _ as _enum } from "./schemas-D5T9tDtI.js";
7
+ import { o as object, n as number, b as boolean, s as string, a as array, _ as _enum } from "./schemas-7qqi9OQy.js";
8
8
  const MAX_SVG_BYTES = 128 * 1024;
9
9
  const window = new JSDOM("").window;
10
10
  const DOMPurify = createDOMPurify(window);
package/dist/index.js CHANGED
@@ -2096,7 +2096,7 @@ class ErrorTracking {
2096
2096
  this._rateLimiter.stop();
2097
2097
  }
2098
2098
  }
2099
- const version = "5.18.0";
2099
+ const version = "5.19.0";
2100
2100
  const FeatureFlagError = {
2101
2101
  ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
2102
2102
  FLAG_MISSING: "flag_missing",
@@ -2374,6 +2374,7 @@ class FeatureFlagsPoller {
2374
2374
  }
2375
2375
  async loadFeatureFlags(forceReload = false) {
2376
2376
  if (this.loadedSuccessfullyOnce && !forceReload) return;
2377
+ if (!forceReload && this.nextFetchAllowedAt && Date.now() < this.nextFetchAllowedAt) return void this.logMsgIfDebug(() => console.debug("[FEATURE FLAGS] Skipping fetch, in backoff period"));
2377
2378
  if (!this.loadingPromise) this.loadingPromise = this._loadFeatureFlags().catch((err) => this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] Failed to load feature flags: ${err}`))).finally(() => {
2378
2379
  this.loadingPromise = void 0;
2379
2380
  });
@@ -2386,6 +2387,16 @@ class FeatureFlagsPoller {
2386
2387
  if (!this.shouldBeginExponentialBackoff) return this.pollingInterval;
2387
2388
  return Math.min(SIXTY_SECONDS, this.pollingInterval * 2 ** this.backOffCount);
2388
2389
  }
2390
+ beginBackoff() {
2391
+ this.shouldBeginExponentialBackoff = true;
2392
+ this.backOffCount += 1;
2393
+ this.nextFetchAllowedAt = Date.now() + this.getPollingInterval();
2394
+ }
2395
+ clearBackoff() {
2396
+ this.shouldBeginExponentialBackoff = false;
2397
+ this.backOffCount = 0;
2398
+ this.nextFetchAllowedAt = void 0;
2399
+ }
2389
2400
  async _loadFeatureFlags() {
2390
2401
  if (this.poller) {
2391
2402
  clearTimeout(this.poller);
@@ -2411,12 +2422,10 @@ class FeatureFlagsPoller {
2411
2422
  this.logMsgIfDebug(() => console.debug("[FEATURE FLAGS] Flags not modified (304), using cached data"));
2412
2423
  this.flagsEtag = res.headers?.get("ETag") ?? this.flagsEtag;
2413
2424
  this.loadedSuccessfullyOnce = true;
2414
- this.shouldBeginExponentialBackoff = false;
2415
- this.backOffCount = 0;
2425
+ this.clearBackoff();
2416
2426
  return;
2417
2427
  case 401:
2418
- this.shouldBeginExponentialBackoff = true;
2419
- this.backOffCount += 1;
2428
+ this.beginBackoff();
2420
2429
  throw new ClientError(`Your project key or personal API key is invalid. Setting next polling interval to ${this.getPollingInterval()}ms. More information: https://posthog.com/docs/api#rate-limiting`);
2421
2430
  case 402:
2422
2431
  console.warn("[FEATURE FLAGS] Feature flags quota limit exceeded - unsetting all local flags. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts");
@@ -2426,12 +2435,10 @@ class FeatureFlagsPoller {
2426
2435
  this.cohorts = {};
2427
2436
  return;
2428
2437
  case 403:
2429
- this.shouldBeginExponentialBackoff = true;
2430
- this.backOffCount += 1;
2438
+ this.beginBackoff();
2431
2439
  throw new ClientError(`Your personal API key does not have permission to fetch feature flag definitions for local evaluation. Setting next polling interval to ${this.getPollingInterval()}ms. Are you sure you're using the correct personal and Project API key pair? More information: https://posthog.com/docs/api/overview`);
2432
2440
  case 429:
2433
- this.shouldBeginExponentialBackoff = true;
2434
- this.backOffCount += 1;
2441
+ this.beginBackoff();
2435
2442
  throw new ClientError(`You are being rate limited. Setting next polling interval to ${this.getPollingInterval()}ms. More information: https://posthog.com/docs/api#rate-limiting`);
2436
2443
  case 200: {
2437
2444
  const responseJson = await res.json() ?? {};
@@ -2443,8 +2450,7 @@ class FeatureFlagsPoller {
2443
2450
  cohorts: responseJson.cohorts || {}
2444
2451
  };
2445
2452
  this.updateFlagState(flagData);
2446
- this.shouldBeginExponentialBackoff = false;
2447
- this.backOffCount = 0;
2453
+ this.clearBackoff();
2448
2454
  if (this.cacheProvider && shouldFetch) try {
2449
2455
  await this.cacheProvider.onFlagDefinitionsReceived(flagData);
2450
2456
  } catch (err) {
@@ -2812,6 +2818,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
2812
2818
  });
2813
2819
  }
2814
2820
  async getFeatureFlag(key, distinctId, options) {
2821
+ if (void 0 !== this._flagOverrides && key in this._flagOverrides) return this._flagOverrides[key];
2815
2822
  const { groups, disableGeoip } = options || {};
2816
2823
  let { onlyEvaluateLocally, sendFeatureFlagEvents, personProperties, groupProperties } = options || {};
2817
2824
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
@@ -2872,6 +2879,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
2872
2879
  return response;
2873
2880
  }
2874
2881
  async getFeatureFlagPayload(key, distinctId, matchValue, options) {
2882
+ if (void 0 !== this._payloadOverrides && key in this._payloadOverrides) return this._payloadOverrides[key];
2875
2883
  const { groups, disableGeoip } = options || {};
2876
2884
  let { onlyEvaluateLocally, personProperties, groupProperties } = options || {};
2877
2885
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
@@ -2945,6 +2953,14 @@ class PostHogBackendClient extends PostHogCoreStateless {
2945
2953
  ...remoteEvaluationResult.payloads || {}
2946
2954
  };
2947
2955
  }
2956
+ if (void 0 !== this._flagOverrides) featureFlags = {
2957
+ ...featureFlags,
2958
+ ...this._flagOverrides
2959
+ };
2960
+ if (void 0 !== this._payloadOverrides) featureFlagPayloads = {
2961
+ ...featureFlagPayloads,
2962
+ ...this._payloadOverrides
2963
+ };
2948
2964
  return {
2949
2965
  featureFlags,
2950
2966
  featureFlagPayloads
@@ -2958,6 +2974,53 @@ class PostHogBackendClient extends PostHogCoreStateless {
2958
2974
  async reloadFeatureFlags() {
2959
2975
  await this.featureFlagsPoller?.loadFeatureFlags(true);
2960
2976
  }
2977
+ overrideFeatureFlags(overrides) {
2978
+ const flagArrayToRecord = (flags) => Object.fromEntries(flags.map((f) => [
2979
+ f,
2980
+ true
2981
+ ]));
2982
+ if (false === overrides) {
2983
+ this._flagOverrides = void 0;
2984
+ this._payloadOverrides = void 0;
2985
+ return;
2986
+ }
2987
+ if (Array.isArray(overrides)) {
2988
+ this._flagOverrides = flagArrayToRecord(overrides);
2989
+ return;
2990
+ }
2991
+ if (this._isFeatureFlagOverrideOptions(overrides)) {
2992
+ if ("flags" in overrides) {
2993
+ if (false === overrides.flags) this._flagOverrides = void 0;
2994
+ else if (Array.isArray(overrides.flags)) this._flagOverrides = flagArrayToRecord(overrides.flags);
2995
+ else if (void 0 !== overrides.flags) this._flagOverrides = {
2996
+ ...overrides.flags
2997
+ };
2998
+ }
2999
+ if ("payloads" in overrides) {
3000
+ if (false === overrides.payloads) this._payloadOverrides = void 0;
3001
+ else if (void 0 !== overrides.payloads) this._payloadOverrides = {
3002
+ ...overrides.payloads
3003
+ };
3004
+ }
3005
+ return;
3006
+ }
3007
+ this._flagOverrides = {
3008
+ ...overrides
3009
+ };
3010
+ }
3011
+ _isFeatureFlagOverrideOptions(overrides) {
3012
+ if ("object" != typeof overrides || null === overrides || Array.isArray(overrides)) return false;
3013
+ const obj = overrides;
3014
+ if ("flags" in obj) {
3015
+ const flagsValue = obj["flags"];
3016
+ if (false === flagsValue || Array.isArray(flagsValue) || "object" == typeof flagsValue && null !== flagsValue) return true;
3017
+ }
3018
+ if ("payloads" in obj) {
3019
+ const payloadsValue = obj["payloads"];
3020
+ if (false === payloadsValue || "object" == typeof payloadsValue && null !== payloadsValue) return true;
3021
+ }
3022
+ return false;
3023
+ }
2961
3024
  withContext(data, fn, options) {
2962
3025
  if (!this.context) return fn();
2963
3026
  return this.context.run(data, fn, options);
@@ -1,7 +1,7 @@
1
1
  import { models } from "@rpcbase/db";
2
2
  import { s as sendEmail } from "./email-DEw8keax.js";
3
3
  const routes = Object.entries({
4
- .../* @__PURE__ */ Object.assign({ "./api/notifications/handler.ts": () => import("./handler-BvRk-c8E.js") })
4
+ .../* @__PURE__ */ Object.assign({ "./api/notifications/handler.ts": () => import("./handler-BwK8qxLn.js") })
5
5
  }).reduce((acc, [path, mod]) => {
6
6
  acc[path.replace("./api/", "@rpcbase/server/notifications/api/")] = mod;
7
7
  return acc;
package/dist/rts/index.js CHANGED
@@ -3,7 +3,7 @@ import { models } from "@rpcbase/db";
3
3
  import { buildAbilityFromSession, getTenantRolesFromSessionUser, buildAbility, getAccessibleByQuery } from "@rpcbase/db/acl";
4
4
  import { WebSocketServer } from "ws";
5
5
  const routes = Object.entries({
6
- .../* @__PURE__ */ Object.assign({ "./api/changes/handler.ts": () => import("../handler-lOVgWqyF.js") })
6
+ .../* @__PURE__ */ Object.assign({ "./api/changes/handler.ts": () => import("../handler-CedzJJg0.js") })
7
7
  }).reduce((acc, [path, mod]) => {
8
8
  acc[path.replace("./api/", "@rpcbase/server/rts/api/")] = mod;
9
9
  return acc;