@opengeni/config 0.7.22 → 0.9.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.
package/dist/index.d.ts CHANGED
@@ -88,6 +88,12 @@ declare const SettingsSchema: z.ZodObject<{
88
88
  observabilityMetricsEnabled: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
89
89
  observabilityOtlpEndpoint: z.ZodOptional<z.ZodString>;
90
90
  observabilityOtlpHeaders: z.ZodDefault<z.ZodString>;
91
+ analyticsEnabled: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
92
+ analyticsConsentRequired: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
93
+ analyticsReoClientId: z.ZodOptional<z.ZodString>;
94
+ analyticsPosthogProjectKey: z.ZodOptional<z.ZodString>;
95
+ analyticsPosthogHost: z.ZodOptional<z.ZodString>;
96
+ analyticsGa4MeasurementId: z.ZodOptional<z.ZodString>;
91
97
  publicBaseUrl: z.ZodOptional<z.ZodString>;
92
98
  webBaseUrl: z.ZodOptional<z.ZodString>;
93
99
  agentReleasesBaseUrl: z.ZodDefault<z.ZodString>;
@@ -126,9 +132,11 @@ declare const SettingsSchema: z.ZodObject<{
126
132
  integrationsOauthClientsJson: z.ZodDefault<z.ZodString>;
127
133
  slackClientId: z.ZodOptional<z.ZodString>;
128
134
  slackClientSecret: z.ZodOptional<z.ZodString>;
135
+ slackSigningSecret: z.ZodOptional<z.ZodString>;
129
136
  googleDriveClientId: z.ZodOptional<z.ZodString>;
130
137
  googleDriveClientSecret: z.ZodOptional<z.ZodString>;
131
138
  maxNestedAgentDepth: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
139
+ socialOauthClientsJson: z.ZodDefault<z.ZodString>;
132
140
  goalMaxAutoContinuations: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
133
141
  goalNoProgressLimit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
134
142
  agentMaxModelCallsPerTurn: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
@@ -931,6 +939,13 @@ export declare const SANDBOX_REQUIRED_ENV: Record<z.infer<typeof SandboxBackend>
931
939
  /** The required OPENGENI_* env var names for a backend (for the deployment manifest). */
932
940
  export declare function requiredSandboxEnvForBackend(backend: z.infer<typeof SandboxBackend>): string[];
933
941
  export declare function getSettings(): Settings;
942
+ /**
943
+ * First-party session tools need a shared HMAC identity even in the unauthenticated
944
+ * local product mode. A fixed local-only value is no broader than that mode's
945
+ * existing access boundary, while configured and managed deployments continue to
946
+ * require an operator-provided secret.
947
+ */
948
+ export declare function resolveFirstPartyDelegationSecret(settings: Settings): string | undefined;
934
949
  /**
935
950
  * The Modal sandbox idle timeout (seconds) the provider actually passes as
936
951
  * idleTimeoutMs (sandbox-file-persistence). When the operator did not pin
@@ -1233,6 +1248,13 @@ export declare function sandboxWarmRateMicrosPerSecond(settings: Settings, backe
1233
1248
  */
1234
1249
  export declare function parseModelProvidersJson(raw: string): RegistryProvider[];
1235
1250
  export declare function parseIntegrationsOauthClientsJson(raw: string | undefined): Record<string, IntegrationOAuthClientConfig>;
1251
+ export declare const SocialOAuthClientConfigSchema: z.ZodObject<{
1252
+ clientId: z.ZodString;
1253
+ clientSecret: z.ZodOptional<z.ZodString>;
1254
+ }, z.core.$strip>;
1255
+ export type SocialOAuthClientConfig = z.infer<typeof SocialOAuthClientConfigSchema>;
1256
+ declare const SOCIAL_OAUTH_PROVIDER_IDS: readonly ["x", "reddit"];
1257
+ export declare function parseSocialOauthClientsJson(raw: string | undefined): Partial<Record<(typeof SOCIAL_OAUTH_PROVIDER_IDS)[number], SocialOAuthClientConfig>>;
1236
1258
  export declare function parseStaticUsageLimitsJson(raw: string): StaticUsageLimitsConfig;
1237
1259
  export declare function parseStaticEntitlementsJson(raw: string): EntitlementsConfig;
1238
1260
  /**
package/dist/index.js CHANGED
@@ -175,6 +175,12 @@ var SettingsSchema = z.object({
175
175
  observabilityMetricsEnabled: EnvBoolean.default(true),
176
176
  observabilityOtlpEndpoint: z.string().url().optional(),
177
177
  observabilityOtlpHeaders: z.string().default(""),
178
+ analyticsEnabled: EnvBoolean.default(false),
179
+ analyticsConsentRequired: EnvBoolean.default(true),
180
+ analyticsReoClientId: z.string().max(128).regex(/^[A-Za-z0-9_-]+$/u).optional(),
181
+ analyticsPosthogProjectKey: z.string().min(1).max(256).optional(),
182
+ analyticsPosthogHost: z.string().url().max(2048).optional(),
183
+ analyticsGa4MeasurementId: z.string().max(32).regex(/^G-[A-Z0-9]+$/u).optional(),
178
184
  publicBaseUrl: z.string().url().optional(),
179
185
  // Browser origin when the web app and API use separate origins in local
180
186
  // development. Production normally leaves this unset and uses publicBaseUrl.
@@ -217,11 +223,15 @@ var SettingsSchema = z.object({
217
223
  integrationsOauthClientsJson: z.string().default("{}"),
218
224
  slackClientId: z.string().optional(),
219
225
  slackClientSecret: z.string().optional(),
226
+ slackSigningSecret: z.string().optional(),
220
227
  googleDriveClientId: z.string().optional(),
221
228
  googleDriveClientSecret: z.string().optional(),
222
229
  // Undefined is meaningful: the migration boundary persists the product
223
230
  // default of 3 when no deployment override is supplied.
224
231
  maxNestedAgentDepth: z.coerce.number().int().nonnegative().max(MAX_NESTED_AGENT_DEPTH).optional(),
232
+ // Operator OAuth apps for first-party social connectors, keyed by provider
233
+ // id ("x", "reddit"): {"x":{"clientId":"...","clientSecret":"..."}}.
234
+ socialOauthClientsJson: z.string().default("{}"),
225
235
  // Session goal guard rails. Goals are designed for runs that legitimately
226
236
  // span days, so length is bounded by pathology detection (no-progress
227
237
  // streaks, budget exhaustion), never by count. goalMaxAutoContinuations is
@@ -273,6 +283,9 @@ var SettingsSchema = z.object({
273
283
  apiPort: z.coerce.number().int().positive().default(8e3),
274
284
  workerHttpPort: z.coerce.number().int().positive().default(8001),
275
285
  opengeniMcpUrl: z.string().url().optional(),
286
+ // Origins allowed to send browser cookies cross-origin. Other origins may
287
+ // call the public API with bearer credentials, but never receive credentialed
288
+ // CORS responses.
276
289
  corsAllowOriginRegex: z.string().default(String.raw`^https?://(localhost|127\.0\.0\.1)(:\d+)?$`),
277
290
  openaiProvider: z.enum(["openai", "azure"]).default("openai"),
278
291
  openaiApiKey: z.string().optional(),
@@ -870,7 +883,11 @@ function resolveVoiceInputProviderRegistry(settings) {
870
883
  }
871
884
  if (id === "codex-subscription") {
872
885
  if (!settings.codexSubscriptionEnabled) continue;
873
- providers.push({ id: "codex-subscription", kind: "codex-subscription", experimental: true });
886
+ providers.push({
887
+ id: "codex-subscription",
888
+ kind: "codex-subscription",
889
+ experimental: true
890
+ });
874
891
  }
875
892
  }
876
893
  return providers;
@@ -1210,6 +1227,12 @@ function getSettings() {
1210
1227
  observabilityMetricsEnabled: optional("OPENGENI_OBSERVABILITY_METRICS_ENABLED"),
1211
1228
  observabilityOtlpEndpoint: optional("OPENGENI_OTEL_EXPORTER_OTLP_ENDPOINT") ?? optional("OTEL_EXPORTER_OTLP_ENDPOINT"),
1212
1229
  observabilityOtlpHeaders: optional("OPENGENI_OTEL_EXPORTER_OTLP_HEADERS") ?? optional("OTEL_EXPORTER_OTLP_HEADERS"),
1230
+ analyticsEnabled: optional("OPENGENI_ANALYTICS_ENABLED"),
1231
+ analyticsConsentRequired: optional("OPENGENI_ANALYTICS_CONSENT_REQUIRED"),
1232
+ analyticsReoClientId: optional("OPENGENI_ANALYTICS_REO_CLIENT_ID"),
1233
+ analyticsPosthogProjectKey: optional("OPENGENI_ANALYTICS_POSTHOG_PROJECT_KEY"),
1234
+ analyticsPosthogHost: optional("OPENGENI_ANALYTICS_POSTHOG_HOST"),
1235
+ analyticsGa4MeasurementId: optional("OPENGENI_ANALYTICS_GA4_MEASUREMENT_ID"),
1213
1236
  publicBaseUrl: optional("OPENGENI_PUBLIC_BASE_URL"),
1214
1237
  webBaseUrl: optional("OPENGENI_WEB_BASE_URL"),
1215
1238
  agentReleasesBaseUrl: optional("OPENGENI_AGENT_RELEASES_BASE_URL"),
@@ -1235,9 +1258,11 @@ function getSettings() {
1235
1258
  integrationsOauthClientsJson: optional("OPENGENI_INTEGRATIONS_OAUTH_CLIENTS_JSON"),
1236
1259
  slackClientId: optional("OPENGENI_SLACK_CLIENT_ID"),
1237
1260
  slackClientSecret: optional("OPENGENI_SLACK_CLIENT_SECRET"),
1261
+ slackSigningSecret: optional("OPENGENI_SLACK_SIGNING_SECRET"),
1238
1262
  googleDriveClientId: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_ID"),
1239
1263
  googleDriveClientSecret: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_SECRET"),
1240
1264
  maxNestedAgentDepth: optional("OPENGENI_MAX_NESTED_AGENT_DEPTH"),
1265
+ socialOauthClientsJson: optional("OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON"),
1241
1266
  goalMaxAutoContinuations: optional("OPENGENI_GOAL_MAX_AUTO_CONTINUATIONS"),
1242
1267
  goalNoProgressLimit: optional("OPENGENI_GOAL_NO_PROGRESS_LIMIT"),
1243
1268
  agentMaxModelCallsPerTurn: optional("OPENGENI_AGENT_MAX_MODEL_CALLS_PER_TURN"),
@@ -1460,6 +1485,12 @@ function getSettings() {
1460
1485
  validateSettings(settings);
1461
1486
  return settings;
1462
1487
  }
1488
+ var LOCAL_FIRST_PARTY_DELEGATION_SECRET = "opengeni-local-first-party-delegation-secret-v1";
1489
+ function resolveFirstPartyDelegationSecret(settings) {
1490
+ const explicit = settings.delegationSecret?.trim();
1491
+ if (explicit) return explicit;
1492
+ return settings.productAccessMode === "local" && (settings.environment === "local" || settings.environment === "test") ? LOCAL_FIRST_PARTY_DELEGATION_SECRET : void 0;
1493
+ }
1463
1494
  function effectiveModalIdleTimeoutSeconds(settings) {
1464
1495
  return settings.modalIdleTimeoutSeconds ?? settings.modalTimeoutSeconds;
1465
1496
  }
@@ -1913,7 +1944,10 @@ function withCodexCatalogProvider(settings) {
1913
1944
  };
1914
1945
  })
1915
1946
  };
1916
- return { ...settings, modelProvidersJson: JSON.stringify([...providers, provider]) };
1947
+ return {
1948
+ ...settings,
1949
+ modelProvidersJson: JSON.stringify([...providers, provider])
1950
+ };
1917
1951
  }
1918
1952
  function policyProviderIdForModel(settings, modelId) {
1919
1953
  const canonicalModelId = canonicalizeConfiguredModelId(settings, modelId);
@@ -2048,7 +2082,9 @@ function configuredModels(settings) {
2048
2082
  capabilities,
2049
2083
  ...pricingSchedules[model.id] === void 0 ? {} : { pricing: pricingSchedules[model.id] },
2050
2084
  ...model.contextWindowTokens === void 0 ? {} : { contextWindowTokens: model.contextWindowTokens },
2051
- ...model.effectiveContextWindowTokens === void 0 ? {} : { effectiveContextWindowTokens: model.effectiveContextWindowTokens },
2085
+ ...model.effectiveContextWindowTokens === void 0 ? {} : {
2086
+ effectiveContextWindowTokens: model.effectiveContextWindowTokens
2087
+ },
2052
2088
  ...model.autoCompactTokenLimit === void 0 ? {} : { autoCompactTokenLimit: model.autoCompactTokenLimit },
2053
2089
  ...model.toolOutputTruncationTokens === void 0 ? {} : { toolOutputTruncationTokens: model.toolOutputTruncationTokens },
2054
2090
  reasoningEffort: capabilities.reasoning.runnable,
@@ -2497,7 +2533,9 @@ function parseMcpServers(raw) {
2497
2533
  return parsed;
2498
2534
  } catch (error) {
2499
2535
  const message = error instanceof Error ? error.message : String(error);
2500
- throw new Error(`OPENGENI_MCP_SERVERS must be a JSON array: ${message}`, { cause: error });
2536
+ throw new Error(`OPENGENI_MCP_SERVERS must be a JSON array: ${message}`, {
2537
+ cause: error
2538
+ });
2501
2539
  }
2502
2540
  }
2503
2541
  function parseModelPricingJson(raw) {
@@ -2629,6 +2667,46 @@ function parseIntegrationsOauthClientsJson(raw) {
2629
2667
  }
2630
2668
  return out;
2631
2669
  }
2670
+ var SocialOAuthClientConfigSchema = z.object({
2671
+ clientId: z.string().min(1),
2672
+ clientSecret: z.string().min(1).optional()
2673
+ });
2674
+ var SOCIAL_OAUTH_PROVIDER_IDS = ["x", "reddit"];
2675
+ function parseSocialOauthClientsJson(raw) {
2676
+ if (!raw?.trim() || raw.trim() === "{}") {
2677
+ return {};
2678
+ }
2679
+ let parsed;
2680
+ try {
2681
+ parsed = JSON.parse(raw);
2682
+ } catch (error) {
2683
+ const message = error instanceof Error ? error.message : String(error);
2684
+ throw new Error(`OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON must be valid JSON: ${message}`, {
2685
+ cause: error
2686
+ });
2687
+ }
2688
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2689
+ throw new Error(
2690
+ "OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON must be a JSON object keyed by social provider id"
2691
+ );
2692
+ }
2693
+ const out = {};
2694
+ for (const [key, value] of Object.entries(parsed)) {
2695
+ if (!SOCIAL_OAUTH_PROVIDER_IDS.includes(key)) {
2696
+ throw new Error(
2697
+ `OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON provider ${key} is not supported (expected: ${SOCIAL_OAUTH_PROVIDER_IDS.join(", ")})`
2698
+ );
2699
+ }
2700
+ const result = SocialOAuthClientConfigSchema.safeParse(value);
2701
+ if (!result.success) {
2702
+ throw new Error(
2703
+ `OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON client for ${key} is invalid: ${result.error.message}`
2704
+ );
2705
+ }
2706
+ out[key] = result.data;
2707
+ }
2708
+ return out;
2709
+ }
2632
2710
  function parseStaticUsageLimitsJson(raw) {
2633
2711
  if (!raw.trim() || raw.trim() === "{}") {
2634
2712
  return {};
@@ -2809,6 +2887,11 @@ function validateSettings(settings) {
2809
2887
  );
2810
2888
  }
2811
2889
  if (settings.slackClientId) {
2890
+ if (!settings.slackSigningSecret) {
2891
+ throw new Error(
2892
+ "OPENGENI_SLACK_SIGNING_SECRET is required when the OpenGeni Slack app is configured"
2893
+ );
2894
+ }
2812
2895
  if (!settings.publicBaseUrl) {
2813
2896
  throw new Error(
2814
2897
  "OPENGENI_PUBLIC_BASE_URL is required when the OpenGeni Slack app is configured"
@@ -2848,6 +2931,7 @@ function validateSettings(settings) {
2848
2931
  }
2849
2932
  }
2850
2933
  parseIntegrationsOauthClientsJson(settings.integrationsOauthClientsJson);
2934
+ parseSocialOauthClientsJson(settings.socialOauthClientsJson);
2851
2935
  if (settings.productAccessMode === "configured" && !["local", "test"].includes(settings.environment) && !settings.delegationSecret && !settings.authRequired) {
2852
2936
  throw new Error(
2853
2937
  "OPENGENI_PRODUCT_ACCESS_MODE=configured requires OPENGENI_DELEGATION_SECRET or OPENGENI_AUTH_REQUIRED=true outside local/test"
@@ -3153,6 +3237,7 @@ export {
3153
3237
  ModelProviderApi,
3154
3238
  RegistryProviderKind,
3155
3239
  SANDBOX_REQUIRED_ENV,
3240
+ SocialOAuthClientConfigSchema,
3156
3241
  applyGitAuthPointerEnvironment,
3157
3242
  assertTurnExecutionPolicyMatchesConfigV1,
3158
3243
  builtinProviderId,
@@ -3185,12 +3270,14 @@ export {
3185
3270
  parseModelPricingJson,
3186
3271
  parseModelProvidersJson,
3187
3272
  parseSandboxWarmRateJson,
3273
+ parseSocialOauthClientsJson,
3188
3274
  parseStaticEntitlementsJson,
3189
3275
  parseStaticUsageLimitsJson,
3190
3276
  policyProviderIdForModel,
3191
3277
  productLabelForModelId,
3192
3278
  requiredSandboxEnvForBackend,
3193
3279
  resolveEnrollmentSigningSecret,
3280
+ resolveFirstPartyDelegationSecret,
3194
3281
  resolveModelProvider,
3195
3282
  resolveNatsCalloutConfig,
3196
3283
  resolveNatsControlPlaneAuth,