@resolveio/server-lib 22.2.22 → 22.2.24

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.
@@ -1,5 +1,5 @@
1
1
  export interface OpenAIUsageRecordInput {
2
- id_client: string;
2
+ id_client?: string;
3
3
  model: string;
4
4
  input_tokens: number;
5
5
  output_tokens: number;
@@ -96,13 +96,14 @@ var estimateCost = function (model, inputTokens, outputTokens) {
96
96
  };
97
97
  function recordOpenAIUsage(input) {
98
98
  return __awaiter(this, void 0, void 0, function () {
99
- var inputTokens, outputTokens, totalTokens, model, costEstimate;
99
+ var idClient, inputTokens, outputTokens, totalTokens, model, costEstimate;
100
100
  return __generator(this, function (_a) {
101
101
  switch (_a.label) {
102
102
  case 0:
103
- if (!input || !input.id_client) {
103
+ if (!input) {
104
104
  return [2 /*return*/];
105
105
  }
106
+ idClient = String(input.id_client || '').trim();
106
107
  inputTokens = toNumber(input.input_tokens);
107
108
  outputTokens = toNumber(input.output_tokens);
108
109
  totalTokens = toNumber(input.total_tokens);
@@ -114,7 +115,7 @@ function recordOpenAIUsage(input) {
114
115
  ? input.cost_estimate
115
116
  : estimateCost(model, inputTokens, outputTokens);
116
117
  return [4 /*yield*/, openai_usage_ledger_collection_1.OpenAIUsageLedger.insertOne({
117
- id_client: input.id_client,
118
+ id_client: idClient,
118
119
  timestamp: input.timestamp || new Date(),
119
120
  model: model,
120
121
  input_tokens: inputTokens,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/managers/openai-usage-ledger.manager.ts"],"names":[],"mappings":"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","file":"openai-usage-ledger.manager.js","sourcesContent":["import { round } from '../util/common';\nimport { ResolveIOServer } from '../resolveio-server-app';\nimport { OpenAIUsageLedger } from '../collections/openai-usage-ledger.collection';\n\nexport interface OpenAIUsageRecordInput {\n\tid_client: string;\n\tmodel: string;\n\tinput_tokens: number;\n\toutput_tokens: number;\n\ttotal_tokens: number;\n\tbillable?: boolean;\n\tcategory?: string;\n\tid_request?: string;\n\tid_conversation?: string;\n\ttimestamp?: Date;\n\tcost_estimate?: number;\n}\n\ntype PricingConfig = {\n\tinputPer1k: number;\n\toutputPer1k: number;\n};\n\nconst toNumber = (value: any): number => {\n\tconst parsed = Number(value);\n\treturn Number.isFinite(parsed) ? parsed : 0;\n};\n\nconst normalizeModelKey = (value: string): string => {\n\treturn String(value || '').trim().toLowerCase();\n};\n\nconst parsePricingJson = (raw: string): Record<string, PricingConfig> => {\n\tif (!raw) {\n\t\treturn {};\n\t}\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (!parsed || typeof parsed !== 'object') {\n\t\t\treturn {};\n\t\t}\n\t\tconst out: Record<string, PricingConfig> = {};\n\t\tObject.keys(parsed).forEach((key) => {\n\t\t\tconst entry = parsed[key] || {};\n\t\t\tconst inputPer1k = toNumber(entry.inputPer1k ?? entry.input ?? entry.prompt ?? 0);\n\t\t\tconst outputPer1k = toNumber(entry.outputPer1k ?? entry.output ?? entry.completion ?? 0);\n\t\t\tif (inputPer1k || outputPer1k) {\n\t\t\t\tout[normalizeModelKey(key)] = { inputPer1k, outputPer1k };\n\t\t\t}\n\t\t});\n\t\treturn out;\n\t}\n\tcatch {\n\t\treturn {};\n\t}\n};\n\nconst resolvePricingConfig = (): { perModel: Record<string, PricingConfig>; defaultPricing: PricingConfig } => {\n\tconst config = ResolveIOServer.getServerConfig() || {};\n\tconst rawJson = String(config['OPENAI_MODEL_PRICING'] ?? process.env.OPENAI_MODEL_PRICING ?? '').trim();\n\tconst defaultInput = toNumber(config['OPENAI_COST_PER_1K_INPUT_TOKENS'] ?? process.env.OPENAI_COST_PER_1K_INPUT_TOKENS ?? 0);\n\tconst defaultOutput = toNumber(config['OPENAI_COST_PER_1K_OUTPUT_TOKENS'] ?? process.env.OPENAI_COST_PER_1K_OUTPUT_TOKENS ?? 0);\n\treturn {\n\t\tperModel: parsePricingJson(rawJson),\n\t\tdefaultPricing: { inputPer1k: defaultInput, outputPer1k: defaultOutput }\n\t};\n};\n\nconst estimateCost = (model: string, inputTokens: number, outputTokens: number): number => {\n\tconst { perModel, defaultPricing } = resolvePricingConfig();\n\tconst normalizedModel = normalizeModelKey(model);\n\tconst pricing = perModel[normalizedModel] || defaultPricing;\n\tif (!pricing.inputPer1k && !pricing.outputPer1k) {\n\t\treturn 0;\n\t}\n\tconst inputCost = (toNumber(inputTokens) / 1000) * pricing.inputPer1k;\n\tconst outputCost = (toNumber(outputTokens) / 1000) * pricing.outputPer1k;\n\treturn round(inputCost + outputCost, 6);\n};\n\nexport async function recordOpenAIUsage(input: OpenAIUsageRecordInput): Promise<void> {\n\tif (!input || !input.id_client) {\n\t\treturn;\n\t}\n\tconst inputTokens = toNumber(input.input_tokens);\n\tconst outputTokens = toNumber(input.output_tokens);\n\tconst totalTokens = toNumber(input.total_tokens);\n\tif (!totalTokens && (!inputTokens && !outputTokens)) {\n\t\treturn;\n\t}\n\tconst model = String(input.model || '').trim() || 'unknown';\n\tconst costEstimate = Number.isFinite(input.cost_estimate)\n\t\t? input.cost_estimate\n\t\t: estimateCost(model, inputTokens, outputTokens);\n\n\tawait OpenAIUsageLedger.insertOne({\n\t\tid_client: input.id_client,\n\t\ttimestamp: input.timestamp || new Date(),\n\t\tmodel,\n\t\tinput_tokens: inputTokens,\n\t\toutput_tokens: outputTokens,\n\t\ttotal_tokens: totalTokens || (inputTokens + outputTokens),\n\t\tcost_estimate: costEstimate,\n\t\tbillable: input.billable !== false,\n\t\tcategory: input.category || '',\n\t\tid_request: input.id_request || '',\n\t\tid_conversation: input.id_conversation || ''\n\t});\n}\n"]}
1
+ {"version":3,"sources":["../../src/managers/openai-usage-ledger.manager.ts"],"names":[],"mappings":"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","file":"openai-usage-ledger.manager.js","sourcesContent":["import { round } from '../util/common';\nimport { ResolveIOServer } from '../resolveio-server-app';\nimport { OpenAIUsageLedger } from '../collections/openai-usage-ledger.collection';\n\nexport interface OpenAIUsageRecordInput {\n\tid_client?: string;\n\tmodel: string;\n\tinput_tokens: number;\n\toutput_tokens: number;\n\ttotal_tokens: number;\n\tbillable?: boolean;\n\tcategory?: string;\n\tid_request?: string;\n\tid_conversation?: string;\n\ttimestamp?: Date;\n\tcost_estimate?: number;\n}\n\ntype PricingConfig = {\n\tinputPer1k: number;\n\toutputPer1k: number;\n};\n\nconst toNumber = (value: any): number => {\n\tconst parsed = Number(value);\n\treturn Number.isFinite(parsed) ? parsed : 0;\n};\n\nconst normalizeModelKey = (value: string): string => {\n\treturn String(value || '').trim().toLowerCase();\n};\n\nconst parsePricingJson = (raw: string): Record<string, PricingConfig> => {\n\tif (!raw) {\n\t\treturn {};\n\t}\n\ttry {\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (!parsed || typeof parsed !== 'object') {\n\t\t\treturn {};\n\t\t}\n\t\tconst out: Record<string, PricingConfig> = {};\n\t\tObject.keys(parsed).forEach((key) => {\n\t\t\tconst entry = parsed[key] || {};\n\t\t\tconst inputPer1k = toNumber(entry.inputPer1k ?? entry.input ?? entry.prompt ?? 0);\n\t\t\tconst outputPer1k = toNumber(entry.outputPer1k ?? entry.output ?? entry.completion ?? 0);\n\t\t\tif (inputPer1k || outputPer1k) {\n\t\t\t\tout[normalizeModelKey(key)] = { inputPer1k, outputPer1k };\n\t\t\t}\n\t\t});\n\t\treturn out;\n\t}\n\tcatch {\n\t\treturn {};\n\t}\n};\n\nconst resolvePricingConfig = (): { perModel: Record<string, PricingConfig>; defaultPricing: PricingConfig } => {\n\tconst config = ResolveIOServer.getServerConfig() || {};\n\tconst rawJson = String(config['OPENAI_MODEL_PRICING'] ?? process.env.OPENAI_MODEL_PRICING ?? '').trim();\n\tconst defaultInput = toNumber(config['OPENAI_COST_PER_1K_INPUT_TOKENS'] ?? process.env.OPENAI_COST_PER_1K_INPUT_TOKENS ?? 0);\n\tconst defaultOutput = toNumber(config['OPENAI_COST_PER_1K_OUTPUT_TOKENS'] ?? process.env.OPENAI_COST_PER_1K_OUTPUT_TOKENS ?? 0);\n\treturn {\n\t\tperModel: parsePricingJson(rawJson),\n\t\tdefaultPricing: { inputPer1k: defaultInput, outputPer1k: defaultOutput }\n\t};\n};\n\nconst estimateCost = (model: string, inputTokens: number, outputTokens: number): number => {\n\tconst { perModel, defaultPricing } = resolvePricingConfig();\n\tconst normalizedModel = normalizeModelKey(model);\n\tconst pricing = perModel[normalizedModel] || defaultPricing;\n\tif (!pricing.inputPer1k && !pricing.outputPer1k) {\n\t\treturn 0;\n\t}\n\tconst inputCost = (toNumber(inputTokens) / 1000) * pricing.inputPer1k;\n\tconst outputCost = (toNumber(outputTokens) / 1000) * pricing.outputPer1k;\n\treturn round(inputCost + outputCost, 6);\n};\n\nexport async function recordOpenAIUsage(input: OpenAIUsageRecordInput): Promise<void> {\n\tif (!input) {\n\t\treturn;\n\t}\n\tconst idClient = String(input.id_client || '').trim();\n\tconst inputTokens = toNumber(input.input_tokens);\n\tconst outputTokens = toNumber(input.output_tokens);\n\tconst totalTokens = toNumber(input.total_tokens);\n\tif (!totalTokens && (!inputTokens && !outputTokens)) {\n\t\treturn;\n\t}\n\tconst model = String(input.model || '').trim() || 'unknown';\n\tconst costEstimate = Number.isFinite(input.cost_estimate)\n\t\t? input.cost_estimate\n\t\t: estimateCost(model, inputTokens, outputTokens);\n\n\tawait OpenAIUsageLedger.insertOne({\n\t\tid_client: idClient,\n\t\ttimestamp: input.timestamp || new Date(),\n\t\tmodel,\n\t\tinput_tokens: inputTokens,\n\t\toutput_tokens: outputTokens,\n\t\ttotal_tokens: totalTokens || (inputTokens + outputTokens),\n\t\tcost_estimate: costEstimate,\n\t\tbillable: input.billable !== false,\n\t\tcategory: input.category || '',\n\t\tid_request: input.id_request || '',\n\t\tid_conversation: input.id_conversation || ''\n\t});\n}\n"]}
@@ -52,6 +52,7 @@ export declare class SubscriptionManager {
52
52
  private _fullResyncPromise;
53
53
  private readonly RESUME_TOKEN_COLLECTION;
54
54
  private readonly RESUME_TOKEN_SAVE_INTERVAL_MS;
55
+ private readonly RESUME_TOKEN_AUTO_HEAL_RETRY_THRESHOLD;
55
56
  private latencyBuffer;
56
57
  private _latencyFlushInProgress;
57
58
  private _latencyFlushPending;
@@ -164,6 +164,7 @@ var SubscriptionManager = /** @class */ (function () {
164
164
  this._fullResyncPromise = null;
165
165
  this.RESUME_TOKEN_COLLECTION = 'subscription-manager-resume-tokens';
166
166
  this.RESUME_TOKEN_SAVE_INTERVAL_MS = 5000;
167
+ this.RESUME_TOKEN_AUTO_HEAL_RETRY_THRESHOLD = 2;
167
168
  // Buffer to store throttled latency updates with timestamps
168
169
  this.latencyBuffer = new Map();
169
170
  this._latencyFlushInProgress = false;
@@ -1984,7 +1985,7 @@ var SubscriptionManager = /** @class */ (function () {
1984
1985
  // Watch (tail) Mongo's operation log on the entire database (all insert/modify/delete will trigger this function)
1985
1986
  SubscriptionManager.prototype.tailOpLog = function (resumeToken) {
1986
1987
  return __awaiter(this, void 0, void 0, function () {
1987
- var watchDatabases, pipeline, lastResumeToken_1, startedWithResumeToken, error_8, innerError_1, error_9;
1988
+ var watchDatabases, pipeline, lastResumeToken_1, startedWithResumeToken_1, sawChangeEvent_1, resumeTokenInvalidated_1, streamStartedAtMs_1, error_8, innerError_1, error_9;
1988
1989
  var _this = this;
1989
1990
  return __generator(this, function (_a) {
1990
1991
  switch (_a.label) {
@@ -2035,14 +2036,17 @@ var SubscriptionManager = /** @class */ (function () {
2035
2036
  },
2036
2037
  },
2037
2038
  ];
2038
- startedWithResumeToken = false;
2039
+ startedWithResumeToken_1 = false;
2040
+ sawChangeEvent_1 = false;
2041
+ resumeTokenInvalidated_1 = false;
2042
+ streamStartedAtMs_1 = Date.now();
2039
2043
  if (!resumeToken) return [3 /*break*/, 20];
2040
2044
  lastResumeToken_1 = resumeToken;
2041
2045
  _a.label = 4;
2042
2046
  case 4:
2043
2047
  _a.trys.push([4, 5, , 19]);
2044
2048
  this._oplog$ = resolveio_server_app_1.ResolveIOServer.getMongoConnection().watch(pipeline, { resumeAfter: resumeToken, fullDocument: 'updateLookup' });
2045
- startedWithResumeToken = true;
2049
+ startedWithResumeToken_1 = true;
2046
2050
  return [3 /*break*/, 19];
2047
2051
  case 5:
2048
2052
  error_8 = _a.sent();
@@ -2079,7 +2083,7 @@ var SubscriptionManager = /** @class */ (function () {
2079
2083
  case 14:
2080
2084
  _a.trys.push([14, 15, , 18]);
2081
2085
  this._oplog$ = resolveio_server_app_1.ResolveIOServer.getMongoConnection().watch(pipeline, { fullDocument: 'updateLookup' });
2082
- startedWithResumeToken = false;
2086
+ startedWithResumeToken_1 = false;
2083
2087
  return [3 /*break*/, 18];
2084
2088
  case 15:
2085
2089
  innerError_1 = _a.sent();
@@ -2112,12 +2116,14 @@ var SubscriptionManager = /** @class */ (function () {
2112
2116
  return [2 /*return*/];
2113
2117
  case 25: throw error_9;
2114
2118
  case 26:
2115
- console.log(new Date(), 'oplog started', startedWithResumeToken ? '(resumeAfter)' : '');
2119
+ console.log(new Date(), 'oplog started', startedWithResumeToken_1 ? '(resumeAfter)' : '');
2116
2120
  this._oplog$.on('change', function (doc) { return __awaiter(_this, void 0, void 0, function () {
2117
2121
  var collection, fullDocument, docId, flag, dependencyFlag;
2118
2122
  return __generator(this, function (_a) {
2119
2123
  switch (_a.label) {
2120
2124
  case 0:
2125
+ sawChangeEvent_1 = true;
2126
+ this._oplogRetryCount = 0;
2121
2127
  if (!doc.ns) return [3 /*break*/, 14];
2122
2128
  if (this._enableDebug) {
2123
2129
  console.log(new Date(), 'Oplog Hit', doc.ns);
@@ -2221,6 +2227,7 @@ var SubscriptionManager = /** @class */ (function () {
2221
2227
  return [2 /*return*/];
2222
2228
  case 5:
2223
2229
  if (!this.isResumeTokenInvalid(error)) return [3 /*break*/, 7];
2230
+ resumeTokenInvalidated_1 = true;
2224
2231
  return [4 /*yield*/, this.clearResumeToken()];
2225
2232
  case 6:
2226
2233
  _a.sent();
@@ -2247,15 +2254,34 @@ var SubscriptionManager = /** @class */ (function () {
2247
2254
  });
2248
2255
  }); });
2249
2256
  this._oplog$.on('close', function () { return __awaiter(_this, void 0, void 0, function () {
2257
+ var retryThresholdReached, shouldAutoHealResumeToken;
2250
2258
  return __generator(this, function (_a) {
2251
2259
  switch (_a.label) {
2252
2260
  case 0:
2253
2261
  console.log(new Date(), 'oplog close');
2254
- this.queueResumeTokenSave(lastResumeToken_1, { force: true });
2262
+ retryThresholdReached = this._oplogRetryCount >= this.RESUME_TOKEN_AUTO_HEAL_RETRY_THRESHOLD;
2263
+ shouldAutoHealResumeToken = startedWithResumeToken_1
2264
+ && !!lastResumeToken_1
2265
+ && !sawChangeEvent_1
2266
+ && (resumeTokenInvalidated_1 || retryThresholdReached);
2267
+ if (!shouldAutoHealResumeToken) return [3 /*break*/, 2];
2268
+ return [4 /*yield*/, this.clearResumeToken()];
2269
+ case 1:
2270
+ _a.sent();
2271
+ lastResumeToken_1 = null;
2272
+ if (!resumeTokenInvalidated_1) {
2273
+ this.queueFullResync('oplog-resume-token-auto-heal');
2274
+ }
2275
+ console.log(new Date(), 'Sub Manager', 'Auto-healed stale oplog resume token', { retryCount: this._oplogRetryCount, streamLifetimeMs: Date.now() - streamStartedAtMs_1 });
2276
+ _a.label = 2;
2277
+ case 2:
2278
+ if (lastResumeToken_1) {
2279
+ this.queueResumeTokenSave(lastResumeToken_1, { force: true });
2280
+ }
2255
2281
  this._oplog$.removeAllListeners();
2256
2282
  this._oplog$ = null;
2257
2283
  return [4 /*yield*/, this.tailOpLog(lastResumeToken_1)];
2258
- case 1:
2284
+ case 3:
2259
2285
  _a.sent();
2260
2286
  return [2 /*return*/];
2261
2287
  }