manifest 5.38.1 → 5.38.4

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.
@@ -20,8 +20,11 @@ function verifyKey(input, storedHash) {
20
20
  const actual = (0, crypto_1.scryptSync)(input, salt, KEY_LENGTH);
21
21
  return expected.length === KEY_LENGTH && (0, crypto_1.timingSafeEqual)(actual, expected);
22
22
  }
23
- const legacyHash = (0, crypto_1.scryptSync)(input, LEGACY_SALT, KEY_LENGTH).toString('hex');
24
- return legacyHash === storedHash;
23
+ if (!/^[0-9a-fA-F]{64}$/.test(storedHash))
24
+ return false;
25
+ const legacyHashBuf = (0, crypto_1.scryptSync)(input, LEGACY_SALT, KEY_LENGTH);
26
+ const storedBuf = Buffer.from(storedHash, 'hex');
27
+ return (0, crypto_1.timingSafeEqual)(legacyHashBuf, storedBuf);
25
28
  }
26
29
  function keyPrefix(key) {
27
30
  return key.substring(0, 12);
@@ -54,7 +54,7 @@ function isCloudMetadataIp(ip) {
54
54
  return CLOUD_METADATA_RANGES.some((range) => (addr & range.mask) === range.addr);
55
55
  }
56
56
  async function validatePublicUrl(url) {
57
- if (process.env['NODE_ENV'] === 'test')
57
+ if (process.env['NODE_ENV'] === 'test' && process.env['SKIP_SSRF_VALIDATION'] !== 'false')
58
58
  return;
59
59
  let parsed;
60
60
  try {
@@ -61,6 +61,7 @@ let DatabaseSeederService = DatabaseSeederService_1 = class DatabaseSeederServic
61
61
  await this.seedTenantAndAgent();
62
62
  await this.seedAgentMessages();
63
63
  this.logger.log('Seeded demo data (dev/test only, SEED_DATA=true)');
64
+ this.logger.warn('SECURITY: Default seed credentials are active (admin@manifest.build). Do NOT use in production.');
64
65
  }
65
66
  }
66
67
  async runBetterAuthMigrations() {
@@ -43,6 +43,10 @@ const SHORT_DATE_SUFFIX_RE = /-\d{4}$/;
43
43
  const LATEST_SUFFIX = '-latest';
44
44
  const GOOGLE_VARIANT_RE = /-(?:preview(?:-\d{2,4}){1,3}|exp-\d{4}|latest)$/;
45
45
  const REASONING_SUFFIX_RE = /-(reasoning|non-reasoning)$/;
46
+ const LEGACY_NAME_ALIASES = new Map([
47
+ ['open-mistral-nemo', 'mistral-nemo'],
48
+ ['mistral-tiny', 'open-mistral-7b'],
49
+ ]);
46
50
  let ModelsDevSyncService = ModelsDevSyncService_1 = class ModelsDevSyncService {
47
51
  logger = new common_1.Logger(ModelsDevSyncService_1.name);
48
52
  cache = new Map();
@@ -90,6 +94,18 @@ let ModelsDevSyncService = ModelsDevSyncService_1 = class ModelsDevSyncService {
90
94
  const exact = providerModels.get(modelId);
91
95
  if (exact)
92
96
  return exact;
97
+ const aliasBase = modelId
98
+ .replace(DATE_SUFFIX_RE, '')
99
+ .replace(SHORT_DATE_SUFFIX_RE, '')
100
+ .replace(/-latest$/, '');
101
+ const aliasTarget = LEGACY_NAME_ALIASES.get(aliasBase) ??
102
+ LEGACY_NAME_ALIASES.get(modelId) ??
103
+ LEGACY_NAME_ALIASES.get(modelId.replace(/-latest$/, ''));
104
+ if (aliasTarget) {
105
+ const found = providerModels.get(aliasTarget);
106
+ if (found)
107
+ return found;
108
+ }
93
109
  const noVersion = modelId.replace(VERSION_SUFFIX_RE, '');
94
110
  if (noVersion !== modelId) {
95
111
  const found = providerModels.get(noVersion);
@@ -135,6 +151,17 @@ let ModelsDevSyncService = ModelsDevSyncService_1 = class ModelsDevSyncService {
135
151
  return withLatest;
136
152
  }
137
153
  }
154
+ if (modelId.endsWith(LATEST_SUFFIX)) {
155
+ const base = modelId.slice(0, -LATEST_SUFFIX.length);
156
+ const prefix = `${base}-`;
157
+ for (const [key, entry] of providerModels) {
158
+ if (key.startsWith(prefix) && key !== modelId)
159
+ return entry;
160
+ }
161
+ const baseMatch = providerModels.get(base);
162
+ if (baseMatch)
163
+ return baseMatch;
164
+ }
138
165
  return null;
139
166
  }
140
167
  getModelsForProvider(providerId) {
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lookupKnownPrice = lookupKnownPrice;
4
+ const PER_MILLION = 1_000_000;
5
+ const KNOWN_PRICES = [
6
+ { prefix: 'moonshot-v1-', price: { input: 1.66 / PER_MILLION, output: 1.66 / PER_MILLION } },
7
+ { prefix: 'gemma-3-1b-it', price: { input: 0, output: 0 } },
8
+ { prefix: 'gemini-pro-latest', price: { input: 1.25 / PER_MILLION, output: 10.0 / PER_MILLION } },
9
+ ];
10
+ function lookupKnownPrice(modelId) {
11
+ for (const entry of KNOWN_PRICES) {
12
+ if (modelId.startsWith(entry.prefix) || modelId === entry.prefix) {
13
+ return entry.price;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ //# sourceMappingURL=known-model-prices.js.map
@@ -30,6 +30,7 @@ const qwen_region_1 = require("../routing/qwen-region");
30
30
  const copilot_token_service_1 = require("../routing/proxy/copilot-token.service");
31
31
  const anthropic_subscription_probe_1 = require("./anthropic-subscription-probe");
32
32
  const model_fallback_1 = require("./model-fallback");
33
+ const known_model_prices_1 = require("./known-model-prices");
33
34
  const customProviderKey = (id) => `custom:${id}`;
34
35
  const customModelKey = (id, modelName) => `custom:${id}/${modelName}`;
35
36
  function isQwenProvider(providerId) {
@@ -209,7 +210,10 @@ let ModelDiscoveryService = ModelDiscoveryService_1 = class ModelDiscoveryServic
209
210
  return all.find((m) => m.id === modelName);
210
211
  }
211
212
  enrichModel(model, providerId) {
212
- if (model.inputPricePerToken !== null && model.inputPricePerToken >= 0) {
213
+ if (model.inputPricePerToken !== null &&
214
+ model.inputPricePerToken >= 0 &&
215
+ model.outputPricePerToken !== null &&
216
+ model.outputPricePerToken >= 0) {
213
217
  return this.computeScore(this.applyCapabilities(model, providerId));
214
218
  }
215
219
  if (this.modelsDevSync) {
@@ -251,6 +255,14 @@ let ModelDiscoveryService = ModelDiscoveryService_1 = class ModelDiscoveryServic
251
255
  });
252
256
  }
253
257
  }
258
+ const known = (0, known_model_prices_1.lookupKnownPrice)(model.id);
259
+ if (known) {
260
+ return this.computeScore({
261
+ ...model,
262
+ inputPricePerToken: known.input,
263
+ outputPricePerToken: known.output,
264
+ });
265
+ }
254
266
  return this.computeScore(model);
255
267
  }
256
268
  applyCapabilities(model, providerId) {
@@ -32,10 +32,23 @@ function findOpenRouterPrefix(providerId) {
32
32
  }
33
33
  return null;
34
34
  }
35
+ const OPENROUTER_NAME_ALIASES = new Map([
36
+ ['voxtral-small', 'voxtral-small-24b'],
37
+ ['open-mistral-nemo', 'mistral-nemo'],
38
+ ['mistral-tiny', 'open-mistral-7b'],
39
+ ]);
35
40
  function lookupWithVariants(pricingSync, prefix, modelId) {
36
41
  const exact = pricingSync.lookupPricing(`${prefix}/${modelId}`);
37
42
  if (exact)
38
43
  return exact;
44
+ for (const [from, to] of OPENROUTER_NAME_ALIASES) {
45
+ if (modelId.includes(from)) {
46
+ const aliased = modelId.replace(from, to);
47
+ const aliasResult = pricingSync.lookupPricing(`${prefix}/${aliased}`);
48
+ if (aliasResult)
49
+ return aliasResult;
50
+ }
51
+ }
39
52
  const dotVariant = modelId.replace(/-(\d+)-(\d)/g, '-$1.$2');
40
53
  if (dotVariant !== modelId) {
41
54
  const dotResult = pricingSync.lookupPricing(`${prefix}/${dotVariant}`);
@@ -69,6 +82,17 @@ function lookupWithVariants(pricingSync, prefix, modelId) {
69
82
  if (result)
70
83
  return result;
71
84
  }
85
+ if (modelId.endsWith('-latest')) {
86
+ const base = modelId.slice(0, -'-latest'.length);
87
+ const scanPrefix = `${prefix}/${base}-`;
88
+ for (const [key] of pricingSync.getAll()) {
89
+ if (key.startsWith(scanPrefix)) {
90
+ const found = pricingSync.lookupPricing(key);
91
+ if (found)
92
+ return found;
93
+ }
94
+ }
95
+ }
72
96
  return null;
73
97
  }
74
98
  function buildModelsDevFallback(modelsDevSync, providerId) {
@@ -63,10 +63,10 @@ function parseOpenAIDeduped(body, provider) {
63
63
  }
64
64
  exports.UNIVERSAL_NON_CHAT_RE = /(?:embed|tts|whisper|dall-e|imagen|cogview|wanx|sambert|paraformer|text-embedding|speech-to|voice-|audio-turbo)/i;
65
65
  exports.PROVIDER_NON_CHAT = {
66
- openai: /(?:moderation|davinci|babbage|^text-|realtime|-transcribe|^sora|^gpt-3\.5-turbo-instruct|audio|^chatgpt-image)/i,
66
+ openai: /(?:moderation|davinci|babbage|^text-|realtime|-transcribe|^sora|^gpt-3\.5-turbo-instruct|audio|^chatgpt-image|search-api)/i,
67
67
  'openai-subscription': /(?:moderation|davinci|babbage|^text-|realtime|-transcribe|^sora|audio|^chatgpt-image)/i,
68
- gemini: /(?:^aqs-|nano-banana|^deep-research|computer-use|^lyria|^gemini-2\.0-flash-lite$|flash-lite-preview)/i,
69
- mistral: /(?:^mistral-ocr|moderation|voxtral-.*-(?:transcribe|realtime)|^labs-)/i,
68
+ gemini: /(?:^aqs-|nano-banana|^deep-research|computer-use|^lyria|^gemini-2\.0-flash-lite$|flash-lite-preview|robotics)/i,
69
+ mistral: /(?:^mistral-ocr|moderation|voxtral-.*-(?:transcribe|realtime)|^labs-|^mistral-vibe-cli)/i,
70
70
  xai: /(?:imagine|multi-agent)/i,
71
71
  };
72
72
  exports.PROVIDER_BLOCKLIST = {
@@ -174,8 +174,8 @@ function parseOpenRouter(body, provider) {
174
174
  displayName: entry.name || entry.id,
175
175
  provider,
176
176
  contextWindow: entry.context_length ?? 128000,
177
- inputPricePerToken: prompt !== null && Number.isFinite(prompt) ? prompt : null,
178
- outputPricePerToken: completion !== null && Number.isFinite(completion) ? completion : null,
177
+ inputPricePerToken: prompt !== null && Number.isFinite(prompt) && prompt >= 0 ? prompt : null,
178
+ outputPricePerToken: completion !== null && Number.isFinite(completion) && completion >= 0 ? completion : null,
179
179
  capabilityReasoning: false,
180
180
  capabilityCode: false,
181
181
  qualityScore: 3,
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SetNotificationEmailDto = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const class_transformer_1 = require("class-transformer");
15
+ class SetNotificationEmailDto {
16
+ email;
17
+ }
18
+ exports.SetNotificationEmailDto = SetNotificationEmailDto;
19
+ __decorate([
20
+ (0, class_validator_1.IsEmail)(),
21
+ (0, class_transformer_1.Transform)(({ value }) => (typeof value === 'string' ? value.trim().toLowerCase() : value)),
22
+ __metadata("design:type", String)
23
+ ], SetNotificationEmailDto.prototype, "email", void 0);
24
+ //# sourceMappingURL=set-notification-email.dto.js.map
@@ -23,6 +23,7 @@ const notification_cron_service_1 = require("./services/notification-cron.servic
23
23
  const limit_check_service_1 = require("./services/limit-check.service");
24
24
  const notification_rule_dto_1 = require("./dto/notification-rule.dto");
25
25
  const set_email_provider_dto_1 = require("./dto/set-email-provider.dto");
26
+ const set_notification_email_dto_1 = require("./dto/set-notification-email.dto");
26
27
  let NotificationsController = NotificationsController_1 = class NotificationsController {
27
28
  rulesService;
28
29
  notificationLog;
@@ -145,7 +146,7 @@ __decorate([
145
146
  __param(0, (0, current_user_decorator_1.CurrentUser)()),
146
147
  __param(1, (0, common_1.Body)()),
147
148
  __metadata("design:type", Function),
148
- __metadata("design:paramtypes", [Object, Object]),
149
+ __metadata("design:paramtypes", [Object, set_notification_email_dto_1.SetNotificationEmailDto]),
149
150
  __metadata("design:returntype", Promise)
150
151
  ], NotificationsController.prototype, "setNotificationEmail", null);
151
152
  __decorate([
@@ -15,91 +15,91 @@ const common_1 = require("@nestjs/common");
15
15
  const public_decorator_1 = require("../common/decorators/public.decorator");
16
16
  const cache_constants_1 = require("../common/constants/cache.constants");
17
17
  const public_stats_service_1 = require("./public-stats.service");
18
- let cachedStats = null;
19
- let statsTimestamp = 0;
20
- let statsInflight = null;
21
- let cachedCatalog = null;
22
- let catalogTimestamp = 0;
23
- let catalogInflight = null;
18
+ let cachedUsage = null;
19
+ let usageTimestamp = 0;
20
+ let usageInflight = null;
21
+ let cachedFree = null;
22
+ let freeTimestamp = 0;
23
+ let freeInflight = null;
24
24
  let PublicStatsController = PublicStatsController_1 = class PublicStatsController {
25
25
  service;
26
26
  logger = new common_1.Logger(PublicStatsController_1.name);
27
27
  constructor(service) {
28
28
  this.service = service;
29
29
  }
30
- async getStats() {
31
- if (cachedStats && Date.now() - statsTimestamp < cache_constants_1.PUBLIC_STATS_CACHE_TTL_MS) {
32
- return cachedStats;
30
+ async getUsage() {
31
+ if (cachedUsage && Date.now() - usageTimestamp < cache_constants_1.PUBLIC_STATS_CACHE_TTL_MS) {
32
+ return cachedUsage;
33
33
  }
34
- if (!statsInflight) {
35
- statsInflight = this.refreshStats().finally(() => {
36
- statsInflight = null;
34
+ if (!usageInflight) {
35
+ usageInflight = this.refreshUsage().finally(() => {
36
+ usageInflight = null;
37
37
  });
38
38
  }
39
- return statsInflight;
39
+ return usageInflight;
40
40
  }
41
- async getModelCatalog() {
42
- if (cachedCatalog && Date.now() - catalogTimestamp < cache_constants_1.PUBLIC_STATS_CACHE_TTL_MS) {
43
- return cachedCatalog;
41
+ async getFreeModels() {
42
+ if (cachedFree && Date.now() - freeTimestamp < cache_constants_1.PUBLIC_STATS_CACHE_TTL_MS) {
43
+ return cachedFree;
44
44
  }
45
- if (!catalogInflight) {
46
- catalogInflight = this.refreshCatalog().finally(() => {
47
- catalogInflight = null;
45
+ if (!freeInflight) {
46
+ freeInflight = this.refreshFreeModels().finally(() => {
47
+ freeInflight = null;
48
48
  });
49
49
  }
50
- return catalogInflight;
50
+ return freeInflight;
51
51
  }
52
- async refreshStats() {
52
+ async refreshUsage() {
53
53
  try {
54
54
  const stats = await this.service.getUsageStats();
55
- cachedStats = {
55
+ cachedUsage = {
56
56
  total_messages: stats.total_messages,
57
57
  top_models: stats.top_models,
58
58
  cached_at: new Date().toISOString(),
59
59
  };
60
- statsTimestamp = Date.now();
60
+ usageTimestamp = Date.now();
61
61
  }
62
62
  catch (err) {
63
63
  const msg = err instanceof Error ? err.message : String(err);
64
64
  this.logger.error(`Failed to fetch usage stats: ${msg}`);
65
65
  }
66
- return (cachedStats ?? { total_messages: 0, top_models: [], cached_at: new Date().toISOString() });
66
+ return (cachedUsage ?? { total_messages: 0, top_models: [], cached_at: new Date().toISOString() });
67
67
  }
68
- async refreshCatalog() {
68
+ async refreshFreeModels() {
69
69
  try {
70
70
  const stats = await this.service.getUsageStats();
71
71
  const models = this.service.getFreeModels(stats.token_map);
72
- cachedCatalog = {
72
+ cachedFree = {
73
73
  models,
74
74
  total_models: models.length,
75
75
  cached_at: new Date().toISOString(),
76
76
  };
77
- catalogTimestamp = Date.now();
77
+ freeTimestamp = Date.now();
78
78
  }
79
79
  catch (err) {
80
80
  const msg = err instanceof Error ? err.message : String(err);
81
- this.logger.error(`Failed to fetch model catalog: ${msg}`);
81
+ this.logger.error(`Failed to fetch free models: ${msg}`);
82
82
  }
83
- return cachedCatalog ?? { models: [], total_models: 0, cached_at: new Date().toISOString() };
83
+ return cachedFree ?? { models: [], total_models: 0, cached_at: new Date().toISOString() };
84
84
  }
85
85
  };
86
86
  exports.PublicStatsController = PublicStatsController;
87
87
  __decorate([
88
88
  (0, public_decorator_1.Public)(),
89
- (0, common_1.Get)('public-stats'),
89
+ (0, common_1.Get)('usage'),
90
90
  __metadata("design:type", Function),
91
91
  __metadata("design:paramtypes", []),
92
92
  __metadata("design:returntype", Promise)
93
- ], PublicStatsController.prototype, "getStats", null);
93
+ ], PublicStatsController.prototype, "getUsage", null);
94
94
  __decorate([
95
95
  (0, public_decorator_1.Public)(),
96
- (0, common_1.Get)('public-stats/models'),
96
+ (0, common_1.Get)('free-models'),
97
97
  __metadata("design:type", Function),
98
98
  __metadata("design:paramtypes", []),
99
99
  __metadata("design:returntype", Promise)
100
- ], PublicStatsController.prototype, "getModelCatalog", null);
100
+ ], PublicStatsController.prototype, "getFreeModels", null);
101
101
  exports.PublicStatsController = PublicStatsController = PublicStatsController_1 = __decorate([
102
- (0, common_1.Controller)('api/v1'),
102
+ (0, common_1.Controller)('api/v1/public'),
103
103
  __metadata("design:paramtypes", [public_stats_service_1.PublicStatsService])
104
104
  ], PublicStatsController);
105
105
  //# sourceMappingURL=public-stats.controller.js.map
@@ -19,6 +19,11 @@ const typeorm_2 = require("typeorm");
19
19
  const agent_message_entity_1 = require("../entities/agent-message.entity");
20
20
  const model_pricing_cache_service_1 = require("../model-prices/model-pricing-cache.service");
21
21
  const sql_dialect_1 = require("../common/utils/sql-dialect");
22
+ const MAX_RESULTS = 10;
23
+ const EXCLUDED_PROVIDERS = new Set(['Unknown']);
24
+ function isCustomModel(model) {
25
+ return model.startsWith('custom:');
26
+ }
22
27
  let PublicStatsService = class PublicStatsService {
23
28
  messageRepo;
24
29
  pricingCache;
@@ -37,7 +42,6 @@ let PublicStatsService = class PublicStatsService {
37
42
  .where('at.model IS NOT NULL')
38
43
  .groupBy('at.model')
39
44
  .orderBy('usage_count', 'DESC')
40
- .limit(20)
41
45
  .getRawMany(),
42
46
  this.messageRepo
43
47
  .createQueryBuilder('at')
@@ -52,12 +56,18 @@ let PublicStatsService = class PublicStatsService {
52
56
  for (const r of tokenRows) {
53
57
  tokenMap.set(r.model, Number(r.tokens ?? 0));
54
58
  }
55
- const topModels = topRows.map((r, i) => {
59
+ const eligible = [];
60
+ for (const r of topRows) {
56
61
  const modelName = r.model;
62
+ if (isCustomModel(modelName))
63
+ continue;
57
64
  const pricing = this.pricingCache.getByModel(modelName);
58
- return {
65
+ const provider = pricing?.provider || 'Unknown';
66
+ if (EXCLUDED_PROVIDERS.has(provider))
67
+ continue;
68
+ eligible.push({
59
69
  model: modelName,
60
- provider: pricing?.provider || 'Unknown',
70
+ provider,
61
71
  tokens_7d: tokenMap.get(modelName) ?? 0,
62
72
  input_price_per_million: pricing?.input_price_per_token != null
63
73
  ? Number(pricing.input_price_per_token) * 1_000_000
@@ -65,9 +75,12 @@ let PublicStatsService = class PublicStatsService {
65
75
  output_price_per_million: pricing?.output_price_per_token != null
66
76
  ? Number(pricing.output_price_per_token) * 1_000_000
67
77
  : null,
68
- usage_rank: i + 1,
69
- };
70
- });
78
+ usage_rank: 0,
79
+ });
80
+ }
81
+ eligible.sort((a, b) => b.tokens_7d - a.tokens_7d);
82
+ const topModels = eligible.slice(0, MAX_RESULTS);
83
+ topModels.forEach((m, i) => (m.usage_rank = i + 1));
71
84
  return {
72
85
  total_messages: Number(countRow?.total ?? 0),
73
86
  top_models: topModels,
@@ -77,12 +90,23 @@ let PublicStatsService = class PublicStatsService {
77
90
  getFreeModels(tokenMap) {
78
91
  return this.pricingCache
79
92
  .getAll()
80
- .filter((e) => (e.input_price_per_token ?? 0) === 0 && (e.output_price_per_token ?? 0) === 0)
93
+ .filter((e) => {
94
+ if ((e.input_price_per_token ?? 0) !== 0 || (e.output_price_per_token ?? 0) !== 0)
95
+ return false;
96
+ if (isCustomModel(e.model_name))
97
+ return false;
98
+ const provider = e.provider || 'Unknown';
99
+ if (EXCLUDED_PROVIDERS.has(provider))
100
+ return false;
101
+ return (tokenMap.get(e.model_name) ?? 0) > 0;
102
+ })
81
103
  .map((e) => ({
82
104
  model_name: e.model_name,
83
105
  provider: e.provider || 'Unknown',
84
106
  tokens_7d: tokenMap.get(e.model_name) ?? 0,
85
- }));
107
+ }))
108
+ .sort((a, b) => b.tokens_7d - a.tokens_7d)
109
+ .slice(0, MAX_RESULTS);
86
110
  }
87
111
  };
88
112
  exports.PublicStatsService = PublicStatsService;
@@ -15,6 +15,7 @@ var OpenaiOauthController_1;
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.OpenaiOauthController = void 0;
17
17
  const common_1 = require("@nestjs/common");
18
+ const crypto_1 = require("crypto");
18
19
  const public_decorator_1 = require("../../common/decorators/public.decorator");
19
20
  const current_user_decorator_1 = require("../../auth/current-user.decorator");
20
21
  const openai_oauth_service_1 = require("./openai-oauth.service");
@@ -85,9 +86,10 @@ let OpenaiOauthController = OpenaiOauthController_1 = class OpenaiOauthControlle
85
86
  }
86
87
  done(ok, res) {
87
88
  const success = ok === '1';
89
+ const nonce = (0, crypto_1.randomBytes)(16).toString('base64');
88
90
  res.setHeader('Content-Type', 'text/html');
89
- res.setHeader('Content-Security-Policy', "default-src 'none'; script-src 'unsafe-inline'");
90
- res.send((0, openai_oauth_service_1.oauthDoneHtml)(success));
91
+ res.setHeader('Content-Security-Policy', `default-src 'none'; script-src 'nonce-${nonce}'`);
92
+ res.send((0, openai_oauth_service_1.oauthDoneHtml)(success, nonce));
91
93
  }
92
94
  };
93
95
  exports.OpenaiOauthController = OpenaiOauthController;
@@ -22,18 +22,19 @@ function parseOAuthTokenBlob(rawValue) {
22
22
  return null;
23
23
  }
24
24
  }
25
- function oauthDoneHtml(success) {
25
+ function oauthDoneHtml(success, nonce) {
26
26
  const message = success ? 'manifest-oauth-success' : 'manifest-oauth-error';
27
27
  const text = success
28
28
  ? 'Login successful!'
29
29
  : 'Login failed. Please close this window and try again.';
30
+ const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
30
31
  return `<!DOCTYPE html>
31
32
  <html>
32
33
  <head><title>Manifest — OpenAI Login</title></head>
33
34
  <body style="font-family:system-ui;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;margin:0;background:#111;color:#eee;">
34
35
  <p>${text}</p>
35
36
  <p id="hint" style="font-size:13px;color:#888;display:none;">You can close this window.</p>
36
- <script>
37
+ <script${nonceAttr}>
37
38
  try{var bc=new BroadcastChannel('manifest-oauth');bc.postMessage({type:'${message}'});bc.close();}catch(e){}
38
39
  if(window.opener){window.opener.postMessage({type:'${message}'},window.location.origin);}
39
40
  setTimeout(function(){window.close();document.getElementById('hint').style.display='block';},1500);
@@ -14,6 +14,13 @@ const KNOWN_ERROR_MESSAGES = {
14
14
  503: 'Upstream provider temporarily unavailable',
15
15
  504: 'Upstream provider gateway timeout',
16
16
  };
17
+ function sanitizeSensitivePatterns(msg) {
18
+ return msg
19
+ .replace(/sk-ant-[a-zA-Z0-9_-]{20,}/g, 'sk-ant-***')
20
+ .replace(/sk-[a-zA-Z0-9_-]{20,}/g, 'sk-***')
21
+ .replace(/key=[^&\s"]+/g, 'key=***')
22
+ .replace(/Bearer\s+[^\s"]+/gi, 'Bearer ***');
23
+ }
17
24
  function sanitizeProviderError(status, rawBody, nodeEnv) {
18
25
  const generic = KNOWN_ERROR_MESSAGES[status] ?? `Upstream provider returned HTTP ${status}`;
19
26
  if ((nodeEnv ?? 'production') === 'production')
@@ -23,7 +30,7 @@ function sanitizeProviderError(status, rawBody, nodeEnv) {
23
30
  const error = parsed.error;
24
31
  const message = error?.message ?? parsed.message;
25
32
  if (typeof message === 'string' && message.length > 0) {
26
- return message.slice(0, 500);
33
+ return sanitizeSensitivePatterns(message).slice(0, 500);
27
34
  }
28
35
  }
29
36
  catch {
@@ -31,8 +31,10 @@ function filterSubModels(models) {
31
31
  }
32
32
  const result = [];
33
33
  for (const providerModels of byProvider.values()) {
34
- const zeroCost = providerModels.filter((m) => (m.inputPricePerToken == null || m.inputPricePerToken === 0) &&
35
- (m.outputPricePerToken == null || m.outputPricePerToken === 0));
34
+ const zeroCost = providerModels.filter((m) => m.inputPricePerToken != null &&
35
+ m.outputPricePerToken != null &&
36
+ m.inputPricePerToken === 0 &&
37
+ m.outputPricePerToken === 0);
36
38
  result.push(...(zeroCost.length > 0 ? zeroCost : providerModels));
37
39
  }
38
40
  return result;
@@ -82,11 +84,14 @@ let TierAutoAssignService = TierAutoAssignService_1 = class TierAutoAssignServic
82
84
  pickBest(models, tier) {
83
85
  if (models.length === 0)
84
86
  return null;
85
- const totalPrice = (m) => (m.inputPricePerToken != null ? Number(m.inputPricePerToken) : 0) +
86
- (m.outputPricePerToken != null ? Number(m.outputPricePerToken) : 0);
87
+ const totalPrice = (m) => {
88
+ if (m.inputPricePerToken == null || m.outputPricePerToken == null)
89
+ return Infinity;
90
+ return Number(m.inputPricePerToken) + Number(m.outputPricePerToken);
91
+ };
87
92
  const quality = (m) => m.qualityScore ?? 3;
88
93
  const byPrice = [...models].sort((a, b) => totalPrice(a) - totalPrice(b));
89
- let picked;
94
+ let picked = byPrice[0];
90
95
  switch (tier) {
91
96
  case 'simple': {
92
97
  picked = byPrice[0];
@@ -119,18 +119,10 @@ function scoreRequest(input, configOverride, momentum) {
119
119
  const hasTools = tools && tools.length > 0;
120
120
  const hasMomentum = momentum?.recentTiers && momentum.recentTiers.length > 0;
121
121
  if (lastUserText.length > 0 && lastUserText.length < 50 && !hasTools) {
122
- if (!hasMomentum) {
123
- return {
124
- tier: 'simple',
125
- score: -0.3,
126
- confidence: 0.9,
127
- reason: 'short_message',
128
- dimensions: emptyDimensions(config),
129
- momentum: null,
130
- };
131
- }
132
122
  const lastMatches = trie.scan(lastUserText);
133
- if (lastMatches.some((m) => m.dimension === 'simpleIndicators')) {
123
+ const hasSimpleIndicator = lastMatches.some((m) => m.dimension === 'simpleIndicators');
124
+ const hasComplexSignal = lastMatches.some((m) => m.dimension !== 'simpleIndicators' && m.dimension !== 'relay');
125
+ if (!hasComplexSignal && (!hasMomentum || hasSimpleIndicator)) {
134
126
  return {
135
127
  tier: 'simple',
136
128
  score: -0.3,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "manifest",
3
3
  "name": "Manifest Self-Hosted LLM Router",
4
- "version": "5.38.1",
4
+ "version": "5.38.4",
5
5
  "description": "Run the Manifest LLM router locally with SQLite. Zero-config dashboard included.",
6
6
  "author": "MNFST Inc.",
7
7
  "homepage": "https://manifest.build",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "manifest",
3
3
  "name": "Manifest Self-Hosted LLM Router",
4
- "version": "5.38.1",
4
+ "version": "5.38.4",
5
5
  "description": "Run the Manifest LLM router locally with SQLite. Zero-config dashboard included.",
6
6
  "author": "MNFST Inc.",
7
7
  "homepage": "https://manifest.build",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "manifest",
3
- "version": "5.38.1",
3
+ "version": "5.38.4",
4
4
  "description": "Self-hosted Manifest LLM router with embedded server, SQLite database, and dashboard",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",