@opengeni/config 0.8.1 → 0.9.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/config",
3
- "version": "0.8.1",
3
+ "version": "0.9.3",
4
4
  "description": "OpenGeni runtime configuration: settings resolution, deployment knobs, and config validation shared across the server packages.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@opengeni/codex": "^0.2.9",
37
- "@opengeni/contracts": "^0.27.0",
37
+ "@opengeni/contracts": "^0.30.0",
38
38
  "zod": "^4.2.1"
39
39
  },
40
40
  "engines": {
package/src/index.ts CHANGED
@@ -218,6 +218,20 @@ const SettingsSchema = z.object({
218
218
  observabilityMetricsEnabled: EnvBoolean.default(true),
219
219
  observabilityOtlpEndpoint: z.string().url().optional(),
220
220
  observabilityOtlpHeaders: z.string().default(""),
221
+ analyticsEnabled: EnvBoolean.default(false),
222
+ analyticsConsentRequired: EnvBoolean.default(true),
223
+ analyticsReoClientId: z
224
+ .string()
225
+ .max(128)
226
+ .regex(/^[A-Za-z0-9_-]+$/u)
227
+ .optional(),
228
+ analyticsPosthogProjectKey: z.string().min(1).max(256).optional(),
229
+ analyticsPosthogHost: z.string().url().max(2_048).optional(),
230
+ analyticsGa4MeasurementId: z
231
+ .string()
232
+ .max(32)
233
+ .regex(/^G-[A-Z0-9]+$/u)
234
+ .optional(),
221
235
  publicBaseUrl: z.string().url().optional(),
222
236
  // Browser origin when the web app and API use separate origins in local
223
237
  // development. Production normally leaves this unset and uses publicBaseUrl.
@@ -275,6 +289,9 @@ const SettingsSchema = z.object({
275
289
  // Undefined is meaningful: the migration boundary persists the product
276
290
  // default of 3 when no deployment override is supplied.
277
291
  maxNestedAgentDepth: z.coerce.number().int().nonnegative().max(MAX_NESTED_AGENT_DEPTH).optional(),
292
+ // Operator OAuth apps for first-party social connectors, keyed by provider
293
+ // id ("x", "reddit"): {"x":{"clientId":"...","clientSecret":"..."}}.
294
+ socialOauthClientsJson: z.string().default("{}"),
278
295
  // Session goal guard rails. Goals are designed for runs that legitimately
279
296
  // span days, so length is bounded by pathology detection (no-progress
280
297
  // streaks, budget exhaustion), never by count. goalMaxAutoContinuations is
@@ -1571,6 +1588,12 @@ export function getSettings(): Settings {
1571
1588
  optional("OPENGENI_OTEL_EXPORTER_OTLP_ENDPOINT") ?? optional("OTEL_EXPORTER_OTLP_ENDPOINT"),
1572
1589
  observabilityOtlpHeaders:
1573
1590
  optional("OPENGENI_OTEL_EXPORTER_OTLP_HEADERS") ?? optional("OTEL_EXPORTER_OTLP_HEADERS"),
1591
+ analyticsEnabled: optional("OPENGENI_ANALYTICS_ENABLED"),
1592
+ analyticsConsentRequired: optional("OPENGENI_ANALYTICS_CONSENT_REQUIRED"),
1593
+ analyticsReoClientId: optional("OPENGENI_ANALYTICS_REO_CLIENT_ID"),
1594
+ analyticsPosthogProjectKey: optional("OPENGENI_ANALYTICS_POSTHOG_PROJECT_KEY"),
1595
+ analyticsPosthogHost: optional("OPENGENI_ANALYTICS_POSTHOG_HOST"),
1596
+ analyticsGa4MeasurementId: optional("OPENGENI_ANALYTICS_GA4_MEASUREMENT_ID"),
1574
1597
  publicBaseUrl: optional("OPENGENI_PUBLIC_BASE_URL"),
1575
1598
  webBaseUrl: optional("OPENGENI_WEB_BASE_URL"),
1576
1599
  agentReleasesBaseUrl: optional("OPENGENI_AGENT_RELEASES_BASE_URL"),
@@ -1600,6 +1623,7 @@ export function getSettings(): Settings {
1600
1623
  googleDriveClientId: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_ID"),
1601
1624
  googleDriveClientSecret: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_SECRET"),
1602
1625
  maxNestedAgentDepth: optional("OPENGENI_MAX_NESTED_AGENT_DEPTH"),
1626
+ socialOauthClientsJson: optional("OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON"),
1603
1627
  goalMaxAutoContinuations: optional("OPENGENI_GOAL_MAX_AUTO_CONTINUATIONS"),
1604
1628
  goalNoProgressLimit: optional("OPENGENI_GOAL_NO_PROGRESS_LIMIT"),
1605
1629
  agentMaxModelCallsPerTurn: optional("OPENGENI_AGENT_MAX_MODEL_CALLS_PER_TURN"),
@@ -3627,6 +3651,53 @@ export function parseIntegrationsOauthClientsJson(
3627
3651
  return out;
3628
3652
  }
3629
3653
 
3654
+ export const SocialOAuthClientConfigSchema = z.object({
3655
+ clientId: z.string().min(1),
3656
+ clientSecret: z.string().min(1).optional(),
3657
+ });
3658
+ export type SocialOAuthClientConfig = z.infer<typeof SocialOAuthClientConfigSchema>;
3659
+
3660
+ const SOCIAL_OAUTH_PROVIDER_IDS = ["x", "reddit"] as const;
3661
+
3662
+ export function parseSocialOauthClientsJson(
3663
+ raw: string | undefined,
3664
+ ): Partial<Record<(typeof SOCIAL_OAUTH_PROVIDER_IDS)[number], SocialOAuthClientConfig>> {
3665
+ if (!raw?.trim() || raw.trim() === "{}") {
3666
+ return {};
3667
+ }
3668
+ let parsed: unknown;
3669
+ try {
3670
+ parsed = JSON.parse(raw);
3671
+ } catch (error) {
3672
+ const message = error instanceof Error ? error.message : String(error);
3673
+ throw new Error(`OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON must be valid JSON: ${message}`, {
3674
+ cause: error,
3675
+ });
3676
+ }
3677
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3678
+ throw new Error(
3679
+ "OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON must be a JSON object keyed by social provider id",
3680
+ );
3681
+ }
3682
+ const out: Partial<Record<(typeof SOCIAL_OAUTH_PROVIDER_IDS)[number], SocialOAuthClientConfig>> =
3683
+ {};
3684
+ for (const [key, value] of Object.entries(parsed)) {
3685
+ if (!SOCIAL_OAUTH_PROVIDER_IDS.includes(key as (typeof SOCIAL_OAUTH_PROVIDER_IDS)[number])) {
3686
+ throw new Error(
3687
+ `OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON provider ${key} is not supported (expected: ${SOCIAL_OAUTH_PROVIDER_IDS.join(", ")})`,
3688
+ );
3689
+ }
3690
+ const result = SocialOAuthClientConfigSchema.safeParse(value);
3691
+ if (!result.success) {
3692
+ throw new Error(
3693
+ `OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON client for ${key} is invalid: ${result.error.message}`,
3694
+ );
3695
+ }
3696
+ out[key as (typeof SOCIAL_OAUTH_PROVIDER_IDS)[number]] = result.data;
3697
+ }
3698
+ return out;
3699
+ }
3700
+
3630
3701
  export function parseStaticUsageLimitsJson(raw: string): StaticUsageLimitsConfig {
3631
3702
  if (!raw.trim() || raw.trim() === "{}") {
3632
3703
  return {};
@@ -3912,6 +3983,7 @@ function validateSettings(settings: Settings): void {
3912
3983
  }
3913
3984
  }
3914
3985
  parseIntegrationsOauthClientsJson(settings.integrationsOauthClientsJson);
3986
+ parseSocialOauthClientsJson(settings.socialOauthClientsJson);
3915
3987
  if (
3916
3988
  settings.productAccessMode === "configured" &&
3917
3989
  !["local", "test"].includes(settings.environment) &&