@palbase/web 1.10.0 → 2.0.1

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.
@@ -7,7 +7,7 @@ import {
7
7
  __configure,
8
8
  endpointRefFromApiKey,
9
9
  getRuntime
10
- } from "../chunk-4ZJHHXD3.js";
10
+ } from "../chunk-AIPUO4QX.js";
11
11
  import "../chunk-PZ5AY32C.js";
12
12
 
13
13
  // src/next/client.ts
@@ -566,12 +566,6 @@ async function palbeRequest(rt, method, path, spec = {}) {
566
566
  if (MUTATING.has(method) && !callerHasKey) {
567
567
  headers["Idempotency-Key"] = crypto.randomUUID();
568
568
  }
569
- if (rt.appIdentifier !== "") {
570
- const callerHasBundle = Object.keys(headers).some(
571
- (k) => k.toLowerCase() === "x-palbase-bundle"
572
- );
573
- if (!callerHasBundle) headers["X-Palbase-Bundle"] = rt.appIdentifier;
574
- }
575
569
  const attempt = async () => {
576
570
  try {
577
571
  return await rt.http.request(method, path, {
@@ -1465,23 +1459,6 @@ var PalbeAnalytics = class {
1465
1459
  }
1466
1460
  };
1467
1461
 
1468
- // src/app-config.ts
1469
- function loadAppConfig(raw) {
1470
- if (typeof raw !== "object" || raw === null) {
1471
- throw new Error("app_config_invalid: expected a JSON object");
1472
- }
1473
- const r = raw;
1474
- const str = (k) => typeof r[k] === "string" ? r[k] : "";
1475
- return { appId: str("app_id"), identifier: str("identifier"), envPreset: str("env_preset") };
1476
- }
1477
- function assertOriginMatches(cfg, runtimeOrigin) {
1478
- if (cfg.identifier === "") return;
1479
- if (runtimeOrigin === "") return;
1480
- if (runtimeOrigin !== cfg.identifier) {
1481
- throw new Error(`app_config_mismatch: expected origin ${cfg.identifier}, got ${runtimeOrigin}`);
1482
- }
1483
- }
1484
-
1485
1462
  // src/auth-facade.ts
1486
1463
  function mapWireUser(raw) {
1487
1464
  return {
@@ -2030,6 +2007,19 @@ var PalbeCalls = class {
2030
2007
 
2031
2008
  // ../modules/flags/dist/index.js
2032
2009
  var FLAG_NAME_RE = /^[a-zA-Z0-9_-]+$/;
2010
+ function flagEnabled(value) {
2011
+ if (typeof value === "boolean") return value;
2012
+ return value != null && value !== 0 && value !== "";
2013
+ }
2014
+ function flagVariant(value) {
2015
+ return typeof value === "string" ? { name: value } : null;
2016
+ }
2017
+ function mapResponse(res, fn) {
2018
+ if (res.error || res.data == null) {
2019
+ return { ...res, data: null };
2020
+ }
2021
+ return { ...res, data: fn(res.data) };
2022
+ }
2033
2023
  var FlagsClient = class {
2034
2024
  httpClient;
2035
2025
  getCurrentUserId;
@@ -2049,10 +2039,11 @@ var FlagsClient = class {
2049
2039
  `Invalid flag name: "${flagName}". Flag names must match ${FLAG_NAME_RE.source}`
2050
2040
  );
2051
2041
  }
2052
- const params = this.buildContextParams(context);
2053
- const query = params.toString();
2054
- const path = `/v1/flags/${flagName}/enabled${query ? `?${query}` : ""}`;
2055
- return this.httpClient.request("GET", path);
2042
+ const res = await this.httpClient.request(
2043
+ "GET",
2044
+ this.mergedPath(context)
2045
+ );
2046
+ return mapResponse(res, (snap) => flagEnabled(snap.values?.[flagName]));
2056
2047
  }
2057
2048
  async getVariant(flagName, context) {
2058
2049
  if (!FLAG_NAME_RE.test(flagName)) {
@@ -2060,16 +2051,29 @@ var FlagsClient = class {
2060
2051
  `Invalid flag name: "${flagName}". Flag names must match ${FLAG_NAME_RE.source}`
2061
2052
  );
2062
2053
  }
2063
- const params = this.buildContextParams(context);
2064
- const query = params.toString();
2065
- const path = `/v1/flags/${flagName}/variant${query ? `?${query}` : ""}`;
2066
- return this.httpClient.request("GET", path);
2054
+ const res = await this.httpClient.request(
2055
+ "GET",
2056
+ this.mergedPath(context)
2057
+ );
2058
+ if (res.error || res.data == null) {
2059
+ return { ...res, data: null };
2060
+ }
2061
+ return { ...res, data: flagVariant(res.data.values?.[flagName]) };
2067
2062
  }
2068
2063
  async getAll(context) {
2069
- const params = this.buildContextParams(context);
2070
- const query = params.toString();
2071
- const path = `/v1/flags${query ? `?${query}` : ""}`;
2072
- return this.httpClient.request("GET", path);
2064
+ const res = await this.httpClient.request(
2065
+ "GET",
2066
+ this.mergedPath(context)
2067
+ );
2068
+ return mapResponse(res, (snap) => {
2069
+ const values = snap.values ?? {};
2070
+ return Object.keys(values).map((name) => {
2071
+ const value = values[name];
2072
+ const flag = { name, enabled: flagEnabled(value) };
2073
+ if (typeof value === "string") flag.variant = { name: value };
2074
+ return flag;
2075
+ });
2076
+ });
2073
2077
  }
2074
2078
  /**
2075
2079
  * Cold-start read: the full merged flag set for the current auth identity.
@@ -2168,15 +2172,16 @@ var FlagsClient = class {
2168
2172
  }
2169
2173
  };
2170
2174
  }
2171
- buildContextParams(context) {
2172
- const params = new URLSearchParams();
2173
- if (context?.userId) {
2174
- params.set("userId", context.userId);
2175
- }
2176
- if (context?.properties) {
2177
- params.set("properties", JSON.stringify(context.properties));
2178
- }
2179
- return params;
2175
+ /**
2176
+ * Resolve the merged-read path for a context. With `context.userId` present the
2177
+ * read targets that specific user's merged view (`/v1/user-flags/users/{id}`, a
2178
+ * privileged cross-user read); otherwise the current auth user's view
2179
+ * (`/v1/user-flags`). `context.properties` has no server-side targeting support
2180
+ * in the user-flags module and is ignored.
2181
+ */
2182
+ mergedPath(context) {
2183
+ const uid = context?.userId;
2184
+ return uid ? `/v1/user-flags/users/${encodeURIComponent(uid)}` : "/v1/user-flags";
2180
2185
  }
2181
2186
  };
2182
2187
  var DEFAULT_POLL_MS = 3e4;
@@ -2638,7 +2643,7 @@ var PalbeFlags = class {
2638
2643
  *
2639
2644
  * DEVIATION from iOS sync-cache parity: the platform does not propagate
2640
2645
  * variant metadata into the user-flags snapshot/delta cache, so this is an
2641
- * ASYNC transport read (`GET /v1/flags/{key}/variant`), not a cache lookup.
2646
+ * ASYNC transport read (derived from `GET /v1/user-flags`), not a cache lookup.
2642
2647
  */
2643
2648
  async getVariant(key) {
2644
2649
  let res;
@@ -8278,6 +8283,14 @@ function observeWebVitals(record) {
8278
8283
  };
8279
8284
  }
8280
8285
 
8286
+ // src/runtime-metadata.ts
8287
+ var APP_METADATA_HEADER = "X-Palbase-Bundle";
8288
+ function applyBrowserOriginHeader(headers) {
8289
+ if (Object.keys(headers).some((key) => key.toLowerCase() === "x-palbase-bundle")) return;
8290
+ const origin = typeof window !== "undefined" && typeof window.location !== "undefined" ? window.location.origin : "";
8291
+ if (origin !== "") headers[APP_METADATA_HEADER] = origin;
8292
+ }
8293
+
8281
8294
  // src/realtime/anon-token.ts
8282
8295
  var REFRESH_SKEW_MS = 6e4;
8283
8296
  var AnonTokenProvider = class {
@@ -8320,11 +8333,16 @@ var AnonTokenProvider = class {
8320
8333
  */
8321
8334
  async mint() {
8322
8335
  const base = this.rt.config.url.replace(/\/+$/, "");
8336
+ const headers = {
8337
+ apikey: this.rt.config.apiKey,
8338
+ ...this.rt.config.headers
8339
+ };
8340
+ applyBrowserOriginHeader(headers);
8323
8341
  let response;
8324
8342
  try {
8325
8343
  response = await fetch(`${base}/auth/anonymous`, {
8326
8344
  method: "POST",
8327
- headers: { apikey: this.rt.config.apiKey }
8345
+ headers
8328
8346
  });
8329
8347
  } catch (e) {
8330
8348
  throw new BackendError("network", {
@@ -8965,17 +8983,15 @@ function defaultSessionStorage(key) {
8965
8983
  }
8966
8984
 
8967
8985
  // src/version.ts
8968
- var VERSION = "1.10.0";
8986
+ var VERSION = "2.0.1";
8969
8987
 
8970
8988
  // src/runtime.ts
8971
8989
  function buildRuntime(config) {
8972
- const appIdentifier = config.identifier ?? "";
8973
- const runtimeOrigin = typeof window !== "undefined" && typeof window.location !== "undefined" ? window.location.origin : "";
8974
- assertOriginMatches(loadAppConfig({ identifier: appIdentifier }), runtimeOrigin);
8975
8990
  const http = new HttpClient(config.apiKey, {
8976
8991
  url: config.url,
8977
8992
  headers: { "X-Client-Info": `palbe-web/${VERSION}`, ...config.headers }
8978
8993
  });
8994
+ http.addInterceptor(({ headers }) => applyBrowserOriginHeader(headers));
8979
8995
  const tokenManager = new TokenManager();
8980
8996
  http.tokenManager = tokenManager;
8981
8997
  const authClient = new AuthClient(http, tokenManager);
@@ -9024,7 +9040,6 @@ function buildRuntime(config) {
9024
9040
  let perf;
9025
9041
  const rt = {
9026
9042
  config,
9027
- appIdentifier,
9028
9043
  http,
9029
9044
  tokenManager,
9030
9045
  authClient,
@@ -9183,7 +9198,9 @@ async function buildHeaders(rt, extra) {
9183
9198
  if (token) headers.Authorization = `Bearer ${token}`;
9184
9199
  const callerHasKey = Object.keys(extra ?? {}).some((k) => k.toLowerCase() === "idempotency-key");
9185
9200
  if (!callerHasKey) headers["Idempotency-Key"] = crypto.randomUUID();
9186
- return { ...headers, ...extra };
9201
+ const merged = { ...headers, ...extra };
9202
+ applyBrowserOriginHeader(merged);
9203
+ return merged;
9187
9204
  }
9188
9205
  function buildForm(options) {
9189
9206
  const form = new FormData();