@fonderie/client 1.3.0 → 1.5.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.
@@ -49,6 +49,7 @@ new FonderieClient(opts: IFonderieClientOptions): FonderieClient
49
49
  .webhooks: WebhooksClient
50
50
  .customers: CustomersClient
51
51
  .media: MediaClient
52
+ .config: ConfigClient
52
53
  .setAccessToken(token: string | undefined): void
53
54
  .clearCache(): void
54
55
  .setWorkspaceId(workspaceId: string | undefined): void
@@ -239,6 +240,7 @@ interface ISetConfigInput {
239
240
  description?: string;
240
241
  active?: boolean;
241
242
  ifVersion?: number;
243
+ allowTypeChange?: boolean;
242
244
  }
243
245
 
244
246
  interface ISetSecretInput {
@@ -1601,10 +1603,14 @@ function castConfigValue(type: ConfigValueType, raw: string): CastResult
1601
1603
 
1602
1604
  function configKeyProblem(key: string): string | null
1603
1605
 
1606
+ function configValueLabel(value: unknown): string
1607
+
1604
1608
  function configValueType(value: unknown): ConfigValueType
1605
1609
 
1606
1610
  function formatConfigValue(value: unknown, type?: ConfigValueType): string
1607
1611
 
1612
+ function inferConfigValue(raw: string): IInferredConfigValue
1613
+
1608
1614
  type CastResult = {
1609
1615
  ok: true;
1610
1616
  value: unknown;
@@ -1614,4 +1620,24 @@ type CastResult = {
1614
1620
  };
1615
1621
 
1616
1622
  type ConfigValueType = 'string' | 'number' | 'boolean' | 'json';
1623
+
1624
+ interface IInferredConfigValue {
1625
+ type: ConfigValueType;
1626
+ value: unknown;
1627
+ label: string;
1628
+ ambiguous: boolean;
1629
+ }
1630
+
1631
+ new ConfigClient(http: HttpClient, tokens: TokenStore): ConfigClient
1632
+ .load(): Promise<IRemoteConfigState>
1633
+ .get<T>(key: string, fallback: T): T
1634
+ .snapshot(): IRemoteConfigState
1635
+ .subscribe(listener: Listener): () => void
1636
+
1637
+ interface IRemoteConfigState {
1638
+ values: Readonly<Record<string, unknown>>;
1639
+ loadedAt: Date | null;
1640
+ isLoading: boolean;
1641
+ error: unknown;
1642
+ }
1617
1643
  ```
package/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ __export(index_exports, {
30
30
  CONFIG_KEY_PATTERN: () => CONFIG_KEY_PATTERN,
31
31
  CONFIG_VALUE_TYPES: () => CONFIG_VALUE_TYPES,
32
32
  ConfigAdminClient: () => ConfigAdminClient,
33
+ ConfigClient: () => ConfigClient,
33
34
  CourierAdminClient: () => CourierAdminClient,
34
35
  CustomersClient: () => CustomersClient,
35
36
  FonderieApiError: () => FonderieApiError,
@@ -39,10 +40,12 @@ __export(index_exports, {
39
40
  WorkspacesClient: () => WorkspacesClient,
40
41
  castConfigValue: () => castConfigValue,
41
42
  configKeyProblem: () => configKeyProblem,
43
+ configValueLabel: () => configValueLabel,
42
44
  configValueType: () => configValueType,
43
45
  createMemoryCache: () => createMemoryCache,
44
46
  describeLocation: () => describeLocation,
45
47
  formatConfigValue: () => formatConfigValue,
48
+ inferConfigValue: () => inferConfigValue,
46
49
  isMfaRequired: () => isMfaRequired
47
50
  });
48
51
  module.exports = __toCommonJS(index_exports);
@@ -1145,6 +1148,62 @@ var MediaClient = class {
1145
1148
  }
1146
1149
  };
1147
1150
 
1151
+ // src/modules/config.ts
1152
+ var ConfigClient = class {
1153
+ constructor(http, tokens) {
1154
+ this.http = http;
1155
+ this.tokens = tokens;
1156
+ }
1157
+ http;
1158
+ tokens;
1159
+ state = { values: {}, loadedAt: null, isLoading: false, error: null };
1160
+ listeners = /* @__PURE__ */ new Set();
1161
+ inFlight = null;
1162
+ // GET /config/public — fetch the public values into the shared snapshot.
1163
+ // Concurrent calls share one request. A failure keeps the previous values
1164
+ // (a flag that was on does not flicker off because one refresh failed) and
1165
+ // is reported in `error`; before any success, reads fall back to defaults.
1166
+ load() {
1167
+ if (this.inFlight) return this.inFlight;
1168
+ this.set({ isLoading: true });
1169
+ this.inFlight = this.http.request({
1170
+ method: "GET",
1171
+ path: "/config/public",
1172
+ // Sent when signed in, so per-user values can be served later
1173
+ // without a client change; the route itself is public.
1174
+ token: this.tokens.get()
1175
+ }).then(
1176
+ (res) => this.set({ values: res.result?.values ?? {}, loadedAt: /* @__PURE__ */ new Date(), isLoading: false, error: null }),
1177
+ (error) => this.set({ isLoading: false, error })
1178
+ ).finally(() => {
1179
+ this.inFlight = null;
1180
+ });
1181
+ return this.inFlight;
1182
+ }
1183
+ // One value, with the fallback used when the key is absent — before the
1184
+ // first load, when it failed, or when the server does not expose the key.
1185
+ // Pick the SAFE fallback (feature off), not the optimistic one.
1186
+ get(key, fallback) {
1187
+ return Object.hasOwn(this.state.values, key) ? this.state.values[key] : fallback;
1188
+ }
1189
+ // The whole current state (values, loadedAt, isLoading, error).
1190
+ snapshot() {
1191
+ return this.state;
1192
+ }
1193
+ // Called with the new state after every change; returns an unsubscribe.
1194
+ subscribe(listener) {
1195
+ this.listeners.add(listener);
1196
+ return () => {
1197
+ this.listeners.delete(listener);
1198
+ };
1199
+ }
1200
+ set(patch) {
1201
+ this.state = { ...this.state, ...patch };
1202
+ for (const listener of this.listeners) listener(this.state);
1203
+ return this.state;
1204
+ }
1205
+ };
1206
+
1148
1207
  // src/modules/webhooks.ts
1149
1208
  var WebhooksClient = class {
1150
1209
  constructor(http, tokens) {
@@ -1481,6 +1540,8 @@ var FonderieClient = class {
1481
1540
  webhooks;
1482
1541
  customers;
1483
1542
  media;
1543
+ /** Public remote config: flags and settings the server exposes to frontends. */
1544
+ config;
1484
1545
  http;
1485
1546
  tokens;
1486
1547
  workspaceId;
@@ -1504,6 +1565,7 @@ var FonderieClient = class {
1504
1565
  this.webhooks = new WebhooksClient(this.http, this.tokens);
1505
1566
  this.customers = new CustomersClient(this.http, this.tokens);
1506
1567
  this.media = new MediaClient(this.http, this.tokens);
1568
+ this.config = new ConfigClient(this.http, this.tokens);
1507
1569
  if (opts.workspaceId !== void 0) this.setWorkspaceId(opts.workspaceId);
1508
1570
  }
1509
1571
  // Single-flight refresh: POST /auth/refresh with the app-supplied refresh
@@ -2170,6 +2232,35 @@ function configKeyProblem(key) {
2170
2232
  if (!key) return "Enter a key.";
2171
2233
  return CONFIG_KEY_PATTERN.test(key) ? null : 'Start with a letter; use letters, digits, ".", "_" or "-" (max 128).';
2172
2234
  }
2235
+ var PLAIN_NUMBER = /^-?(0|[1-9]\d*)(\.\d+)?$/;
2236
+ function configValueLabel(value) {
2237
+ if (typeof value === "string") return "Text";
2238
+ if (typeof value === "number") return "Number";
2239
+ if (typeof value === "boolean") return "On/off";
2240
+ if (Array.isArray(value)) return "List";
2241
+ if (value === null) return "Empty";
2242
+ return "Object";
2243
+ }
2244
+ function inferConfigValue(raw) {
2245
+ const t = raw.trim();
2246
+ if (t === "true" || t === "false") {
2247
+ return { type: "boolean", value: t === "true", label: "On/off", ambiguous: true };
2248
+ }
2249
+ if (PLAIN_NUMBER.test(t)) {
2250
+ const n = Number(t);
2251
+ if (Number.isFinite(n) && String(n) === t) return { type: "number", value: n, label: "Number", ambiguous: true };
2252
+ }
2253
+ if (t.startsWith("{") || t.startsWith("[")) {
2254
+ try {
2255
+ const parsed = JSON.parse(t);
2256
+ if (parsed !== null && typeof parsed === "object") {
2257
+ return { type: "json", value: parsed, label: Array.isArray(parsed) ? "List" : "Object", ambiguous: false };
2258
+ }
2259
+ } catch {
2260
+ }
2261
+ }
2262
+ return { type: "string", value: raw, label: "Text", ambiguous: false };
2263
+ }
2173
2264
  // Annotate the CommonJS export names for ESM import in node:
2174
2265
  0 && (module.exports = {
2175
2266
  AdminClient,
@@ -2182,6 +2273,7 @@ function configKeyProblem(key) {
2182
2273
  CONFIG_KEY_PATTERN,
2183
2274
  CONFIG_VALUE_TYPES,
2184
2275
  ConfigAdminClient,
2276
+ ConfigClient,
2185
2277
  CourierAdminClient,
2186
2278
  CustomersClient,
2187
2279
  FonderieApiError,
@@ -2191,10 +2283,12 @@ function configKeyProblem(key) {
2191
2283
  WorkspacesClient,
2192
2284
  castConfigValue,
2193
2285
  configKeyProblem,
2286
+ configValueLabel,
2194
2287
  configValueType,
2195
2288
  createMemoryCache,
2196
2289
  describeLocation,
2197
2290
  formatConfigValue,
2291
+ inferConfigValue,
2198
2292
  isMfaRequired
2199
2293
  });
2200
2294
  //# sourceMappingURL=index.cjs.map