feeef 0.8.11 → 0.9.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.
- package/README.md +4 -0
- package/build/index.js +459 -0
- package/build/index.js.map +1 -1
- package/build/src/ai/ai_calculator.d.ts +204 -0
- package/build/src/core/entities/order.d.ts +20 -0
- package/build/src/core/entities/product.d.ts +2 -0
- package/build/src/core/entities/product_landing_page.d.ts +2 -0
- package/build/src/core/entities/shipping_price.d.ts +2 -2
- package/build/src/delivery/delivery_carrier_client.d.ts +20 -0
- package/build/src/delivery/parcel.d.ts +78 -0
- package/build/src/feeef/repositories/orders.d.ts +3 -0
- package/build/src/feeef/repositories/product_landing_pages.d.ts +7 -0
- package/build/src/feeef/repositories/products.d.ts +7 -0
- package/build/src/feeef/repositories/stores.d.ts +7 -0
- package/build/src/feeef/services/cart.d.ts +4 -4
- package/build/src/feeef/services/integrations.d.ts +2 -1
- package/build/src/index.d.ts +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
`feeefjs` is a TypeScript library for managing feeef e-commerce platforms for self-hosted stores. It provides a wrapper for feeef rest api such like send order..., also have frontend srvices like the `CartService` class for managing cart items, shipping methods, and calculating totals. The library also includes a `NotifiableService` base class for handling listeners that react to changes in the service state.
|
|
4
4
|
|
|
5
|
+
## Delivery parcel types
|
|
6
|
+
|
|
7
|
+
Canonical shipment shapes mirror the API domain in `feeefapps/backend/services/delivery/domain/parcel.ts`. In this package they live under `src/delivery/parcel.ts` and are exported from the main entry (`ParcelCreate`, `ParcelUpdate`, `DeliveryCarrierClient`, …). Keep them in sync when the backend parcel model changes; published npm `feeef` should re-export the same definitions after each release.
|
|
8
|
+
|
|
5
9
|
## Developer OAuth (third-party apps)
|
|
6
10
|
|
|
7
11
|
Use `OAuthRepository.buildAuthorizeUrl` (point `baseUrl` at the **accounts** host, e.g. `https://accounts.feeef.org`) and `FeeeF` client `oauth.exchangeAuthorizationCode` / `revokeToken` / `introspectToken` against the **API** base (`.../v1`). Full flow, scopes, and troubleshooting: Feeef backend **`docs/OAUTH2_DEVELOPER.md`** (in the Adonis API repo).
|
package/build/index.js
CHANGED
|
@@ -167,6 +167,7 @@ var OrderRepository = class extends ModelRepository {
|
|
|
167
167
|
if (options.shippingState) params.shippingState = options.shippingState;
|
|
168
168
|
if (options.shippingCity) params.shippingCity = options.shippingCity;
|
|
169
169
|
if (options.deliveryService) params.deliveryService = options.deliveryService;
|
|
170
|
+
if (options.references !== void 0) params.references = options.references;
|
|
170
171
|
}
|
|
171
172
|
return super.list({ params });
|
|
172
173
|
}
|
|
@@ -321,6 +322,15 @@ var ProductRepository = class extends ModelRepository {
|
|
|
321
322
|
const res = await this.client.get(`/stores/${storeId}/${this.resource}/${productId}/report`);
|
|
322
323
|
return res.data;
|
|
323
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Lite orders report for a product in a store.
|
|
327
|
+
*/
|
|
328
|
+
async liteOrdersReport(storeId, productId) {
|
|
329
|
+
const res = await this.client.get(
|
|
330
|
+
`/stores/${storeId}/${this.resource}/${productId}/analytics/lor`
|
|
331
|
+
);
|
|
332
|
+
return res.data;
|
|
333
|
+
}
|
|
324
334
|
};
|
|
325
335
|
|
|
326
336
|
// src/feeef/repositories/store_invites_repository.ts
|
|
@@ -329,6 +339,8 @@ var StoreInvitesRepository = class {
|
|
|
329
339
|
this.client = client;
|
|
330
340
|
this.resource = resource;
|
|
331
341
|
}
|
|
342
|
+
client;
|
|
343
|
+
resource;
|
|
332
344
|
/**
|
|
333
345
|
* Lists invites for a store.
|
|
334
346
|
* @param storeId - The store ID.
|
|
@@ -434,6 +446,13 @@ var StoreRepository = class extends ModelRepository {
|
|
|
434
446
|
}
|
|
435
447
|
return chartData;
|
|
436
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Lite orders report for the store (8 UTC days + total).
|
|
451
|
+
*/
|
|
452
|
+
async liteOrdersReport(storeId) {
|
|
453
|
+
const res = await this.client.get(`/${this.resource}/${storeId}/analytics/lor`);
|
|
454
|
+
return res.data;
|
|
455
|
+
}
|
|
437
456
|
/**
|
|
438
457
|
* Adds a member to the store.
|
|
439
458
|
* @param storeId - The store ID.
|
|
@@ -1160,6 +1179,7 @@ var PromoRepository = class {
|
|
|
1160
1179
|
constructor(client) {
|
|
1161
1180
|
this.client = client;
|
|
1162
1181
|
}
|
|
1182
|
+
client;
|
|
1163
1183
|
/**
|
|
1164
1184
|
* Lists promos with optional pagination and validNow filter.
|
|
1165
1185
|
*/
|
|
@@ -1815,6 +1835,15 @@ var ProductLandingPagesRepository = class extends ModelRepository {
|
|
|
1815
1835
|
const params = { ...options?.params };
|
|
1816
1836
|
return super.list({ params });
|
|
1817
1837
|
}
|
|
1838
|
+
/**
|
|
1839
|
+
* Lite orders report for a product landing page in a store.
|
|
1840
|
+
*/
|
|
1841
|
+
async liteOrdersReport(storeId, landingPageId) {
|
|
1842
|
+
const res = await this.client.get(
|
|
1843
|
+
`/stores/${storeId}/product_landing_pages/${landingPageId}/analytics/lor`
|
|
1844
|
+
);
|
|
1845
|
+
return res.data;
|
|
1846
|
+
}
|
|
1818
1847
|
};
|
|
1819
1848
|
|
|
1820
1849
|
// src/core/entities/attachment.ts
|
|
@@ -2252,10 +2281,14 @@ var ShippingPriceStatus = /* @__PURE__ */ ((ShippingPriceStatus2) => {
|
|
|
2252
2281
|
return ShippingPriceStatus2;
|
|
2253
2282
|
})(ShippingPriceStatus || {});
|
|
2254
2283
|
function getShippingPrice(prices, countryCode, stateCode, type) {
|
|
2284
|
+
console.log("0 [getShippingPrice]", { prices, countryCode, stateCode, type });
|
|
2255
2285
|
const countryRates = prices[countryCode];
|
|
2286
|
+
console.log("1 [getShippingPrice] countryRates", countryRates);
|
|
2256
2287
|
if (!countryRates) return null;
|
|
2257
2288
|
const stateRates = countryRates[stateCode];
|
|
2289
|
+
console.log("2 [getShippingPrice] stateRates", stateRates);
|
|
2258
2290
|
if (!stateRates) return null;
|
|
2291
|
+
console.log("3 [getShippingPrice] stateRates[type]", stateRates[type]);
|
|
2259
2292
|
return stateRates[type] ?? null;
|
|
2260
2293
|
}
|
|
2261
2294
|
function isShippingAvailable(prices, countryCode, stateCode) {
|
|
@@ -4085,6 +4118,14 @@ var ProductType = /* @__PURE__ */ ((ProductType2) => {
|
|
|
4085
4118
|
ProductType2["service"] = "service";
|
|
4086
4119
|
return ProductType2;
|
|
4087
4120
|
})(ProductType || {});
|
|
4121
|
+
function formatProductOrderReference(productId) {
|
|
4122
|
+
return `product:${productId}`;
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
// src/core/entities/product_landing_page.ts
|
|
4126
|
+
function formatProductLandingPageOrderReference(landingPageId) {
|
|
4127
|
+
return `product_landing_page:${landingPageId}`;
|
|
4128
|
+
}
|
|
4088
4129
|
|
|
4089
4130
|
// src/core/entities/feedback.ts
|
|
4090
4131
|
var FeedbackStatus = /* @__PURE__ */ ((FeedbackStatus2) => {
|
|
@@ -4144,6 +4185,8 @@ var FeeefTransmitHttpClient = class {
|
|
|
4144
4185
|
this.options = options;
|
|
4145
4186
|
this.getAuthorizationHeader = getAuthorizationHeader;
|
|
4146
4187
|
}
|
|
4188
|
+
options;
|
|
4189
|
+
getAuthorizationHeader;
|
|
4147
4190
|
send(request) {
|
|
4148
4191
|
return fetch(request);
|
|
4149
4192
|
}
|
|
@@ -4192,6 +4235,414 @@ function createFeeefTransmitFromAxios(client, options) {
|
|
|
4192
4235
|
});
|
|
4193
4236
|
}
|
|
4194
4237
|
|
|
4238
|
+
// src/ai/ai_calculator.ts
|
|
4239
|
+
var FALLBACK_AI_EXCHANGE_RATE = 260;
|
|
4240
|
+
var DEFAULT_TTS = {
|
|
4241
|
+
whenScriptEmptyTokens: 200,
|
|
4242
|
+
whenAttachmentsOnlyTokens: 400,
|
|
4243
|
+
promptBaseTokens: 400,
|
|
4244
|
+
promptPerAttachmentTokens: 300,
|
|
4245
|
+
outputMinimumTokens: 300,
|
|
4246
|
+
outputToTextTokenRatio: 2.5,
|
|
4247
|
+
maxTotalTokens: 32e3
|
|
4248
|
+
};
|
|
4249
|
+
var DEFAULT_RESOLVED = {
|
|
4250
|
+
retailMarkup: { multiplier: 2.5 },
|
|
4251
|
+
referenceAttachmentSurcharge: {
|
|
4252
|
+
perFileUsd: 0.1,
|
|
4253
|
+
highResolutionExtraPerFileUsd: 0.05,
|
|
4254
|
+
lowResolutionDiscountPerFileUsd: 0.05
|
|
4255
|
+
},
|
|
4256
|
+
imageGeneration: { fallbackProviderCostPerImageUsd: 0.131 },
|
|
4257
|
+
textGeneration: {
|
|
4258
|
+
freeTierMaxPromptTokens: 1e3,
|
|
4259
|
+
estimatedPromptTokensDefault: 2e3,
|
|
4260
|
+
estimatedOutputTokensDefault: 1e3
|
|
4261
|
+
},
|
|
4262
|
+
voiceGeneration: {
|
|
4263
|
+
minimumChargeUsd: 50 / FALLBACK_AI_EXCHANGE_RATE,
|
|
4264
|
+
scriptEnhancementAddonUsd: 25 / FALLBACK_AI_EXCHANGE_RATE,
|
|
4265
|
+
ttsTokenEstimate: { ...DEFAULT_TTS }
|
|
4266
|
+
},
|
|
4267
|
+
landingPageImage: {
|
|
4268
|
+
fixedChargeUsd: 100 / FALLBACK_AI_EXCHANGE_RATE
|
|
4269
|
+
}
|
|
4270
|
+
};
|
|
4271
|
+
function mergeTts(base, partial) {
|
|
4272
|
+
if (!partial) return { ...base };
|
|
4273
|
+
return {
|
|
4274
|
+
whenScriptEmptyTokens: partial.whenScriptEmptyTokens ?? base.whenScriptEmptyTokens,
|
|
4275
|
+
whenAttachmentsOnlyTokens: partial.whenAttachmentsOnlyTokens ?? base.whenAttachmentsOnlyTokens,
|
|
4276
|
+
promptBaseTokens: partial.promptBaseTokens ?? base.promptBaseTokens,
|
|
4277
|
+
promptPerAttachmentTokens: partial.promptPerAttachmentTokens ?? base.promptPerAttachmentTokens,
|
|
4278
|
+
outputMinimumTokens: partial.outputMinimumTokens ?? base.outputMinimumTokens,
|
|
4279
|
+
outputToTextTokenRatio: partial.outputToTextTokenRatio ?? base.outputToTextTokenRatio,
|
|
4280
|
+
maxTotalTokens: partial.maxTotalTokens ?? base.maxTotalTokens
|
|
4281
|
+
};
|
|
4282
|
+
}
|
|
4283
|
+
function mergeAiModelsBilling(partial) {
|
|
4284
|
+
const d = DEFAULT_RESOLVED;
|
|
4285
|
+
if (!partial) return structuredClone(d);
|
|
4286
|
+
const v = partial.voiceGeneration;
|
|
4287
|
+
const tts = mergeTts(d.voiceGeneration.ttsTokenEstimate, v?.ttsTokenEstimate);
|
|
4288
|
+
return {
|
|
4289
|
+
retailMarkup: {
|
|
4290
|
+
multiplier: partial.retailMarkup?.multiplier ?? d.retailMarkup.multiplier
|
|
4291
|
+
},
|
|
4292
|
+
referenceAttachmentSurcharge: {
|
|
4293
|
+
perFileUsd: partial.referenceAttachmentSurcharge?.perFileUsd ?? d.referenceAttachmentSurcharge.perFileUsd,
|
|
4294
|
+
highResolutionExtraPerFileUsd: partial.referenceAttachmentSurcharge?.highResolutionExtraPerFileUsd ?? d.referenceAttachmentSurcharge.highResolutionExtraPerFileUsd,
|
|
4295
|
+
lowResolutionDiscountPerFileUsd: partial.referenceAttachmentSurcharge?.lowResolutionDiscountPerFileUsd ?? d.referenceAttachmentSurcharge.lowResolutionDiscountPerFileUsd
|
|
4296
|
+
},
|
|
4297
|
+
imageGeneration: {
|
|
4298
|
+
fallbackProviderCostPerImageUsd: partial.imageGeneration?.fallbackProviderCostPerImageUsd ?? d.imageGeneration.fallbackProviderCostPerImageUsd
|
|
4299
|
+
},
|
|
4300
|
+
textGeneration: {
|
|
4301
|
+
freeTierMaxPromptTokens: partial.textGeneration?.freeTierMaxPromptTokens ?? d.textGeneration.freeTierMaxPromptTokens,
|
|
4302
|
+
estimatedPromptTokensDefault: partial.textGeneration?.estimatedPromptTokensDefault ?? d.textGeneration.estimatedPromptTokensDefault,
|
|
4303
|
+
estimatedOutputTokensDefault: partial.textGeneration?.estimatedOutputTokensDefault ?? d.textGeneration.estimatedOutputTokensDefault
|
|
4304
|
+
},
|
|
4305
|
+
voiceGeneration: {
|
|
4306
|
+
minimumChargeUsd: v?.minimumChargeUsd ?? d.voiceGeneration.minimumChargeUsd,
|
|
4307
|
+
scriptEnhancementAddonUsd: v?.scriptEnhancementAddonUsd ?? d.voiceGeneration.scriptEnhancementAddonUsd,
|
|
4308
|
+
ttsTokenEstimate: tts
|
|
4309
|
+
},
|
|
4310
|
+
landingPageImage: {
|
|
4311
|
+
fixedChargeUsd: partial.landingPageImage?.fixedChargeUsd ?? d.landingPageImage.fixedChargeUsd
|
|
4312
|
+
}
|
|
4313
|
+
};
|
|
4314
|
+
}
|
|
4315
|
+
function roundMoney(amount, precision = 3) {
|
|
4316
|
+
const factor = 10 ** precision;
|
|
4317
|
+
return Math.round((amount + Number.EPSILON) * factor) / factor;
|
|
4318
|
+
}
|
|
4319
|
+
function getLegacyAiBillingFlat(exchangeRate, resolved = mergeAiModelsBilling(null)) {
|
|
4320
|
+
const t = resolved.voiceGeneration.ttsTokenEstimate;
|
|
4321
|
+
return {
|
|
4322
|
+
MULTIPLIER: resolved.retailMarkup.multiplier,
|
|
4323
|
+
FREE_TEXT_TOKENS_THRESHOLD: resolved.textGeneration.freeTierMaxPromptTokens,
|
|
4324
|
+
DEFAULT_EXCHANGE_RATE: FALLBACK_AI_EXCHANGE_RATE,
|
|
4325
|
+
DEFAULT_GOOGLE_IMAGE_COST_USD: resolved.imageGeneration.fallbackProviderCostPerImageUsd,
|
|
4326
|
+
DEFAULT_ATTACHMENT_COST_USD: resolved.referenceAttachmentSurcharge.perFileUsd,
|
|
4327
|
+
ATTACHMENT_HIGH_RES_EXTRA_USD: resolved.referenceAttachmentSurcharge.highResolutionExtraPerFileUsd,
|
|
4328
|
+
ATTACHMENT_LOW_RES_DISCOUNT_USD: resolved.referenceAttachmentSurcharge.lowResolutionDiscountPerFileUsd,
|
|
4329
|
+
VOICEOVER_FIXED_COST_DZD: roundMoney(
|
|
4330
|
+
resolved.voiceGeneration.minimumChargeUsd * exchangeRate,
|
|
4331
|
+
3
|
|
4332
|
+
),
|
|
4333
|
+
VOICEOVER_ENHANCE_ADDON_DZD: roundMoney(
|
|
4334
|
+
resolved.voiceGeneration.scriptEnhancementAddonUsd * exchangeRate,
|
|
4335
|
+
3
|
|
4336
|
+
),
|
|
4337
|
+
IMAGE_LANDING_PAGE_FIXED_COST_DZD: roundMoney(
|
|
4338
|
+
resolved.landingPageImage.fixedChargeUsd * exchangeRate,
|
|
4339
|
+
3
|
|
4340
|
+
),
|
|
4341
|
+
DEFAULT_TEXT_PROMPT_TOKENS: resolved.textGeneration.estimatedPromptTokensDefault,
|
|
4342
|
+
DEFAULT_TEXT_OUTPUT_TOKENS: resolved.textGeneration.estimatedOutputTokensDefault,
|
|
4343
|
+
VOICE_TTS_EMPTY_SCRIPT_TEXT_TOKENS: t.whenScriptEmptyTokens,
|
|
4344
|
+
VOICE_TTS_ATTACHMENT_ONLY_TEXT_TOKENS: t.whenAttachmentsOnlyTokens,
|
|
4345
|
+
VOICE_TTS_PROMPT_BASE: t.promptBaseTokens,
|
|
4346
|
+
VOICE_TTS_PROMPT_PER_ATTACHMENT: t.promptPerAttachmentTokens,
|
|
4347
|
+
VOICE_TTS_OUTPUT_MIN: t.outputMinimumTokens,
|
|
4348
|
+
VOICE_TTS_OUTPUT_TEXT_FACTOR: t.outputToTextTokenRatio,
|
|
4349
|
+
VOICE_TTS_TOKEN_CAP: t.maxTotalTokens
|
|
4350
|
+
};
|
|
4351
|
+
}
|
|
4352
|
+
var AI_BILLING = getLegacyAiBillingFlat(FALLBACK_AI_EXCHANGE_RATE);
|
|
4353
|
+
function findModel(models, modelId, fallbackId) {
|
|
4354
|
+
return models.find((m) => m.id === modelId) || models.find((m) => m.id === fallbackId) || models[0];
|
|
4355
|
+
}
|
|
4356
|
+
function modelHasVoiceCapability(model) {
|
|
4357
|
+
const caps = model?.capabilities;
|
|
4358
|
+
if (!Array.isArray(caps)) return false;
|
|
4359
|
+
return caps.some((c) => c === "voice" || c === "audio");
|
|
4360
|
+
}
|
|
4361
|
+
function findVoiceModel(models, modelId, fallbackId) {
|
|
4362
|
+
return models.find((m) => m.id === modelId) || models.find((m) => m.id === fallbackId) || models.find((m) => modelHasVoiceCapability(m));
|
|
4363
|
+
}
|
|
4364
|
+
function pickTtsProviderOutputUsd(model) {
|
|
4365
|
+
if (!model?.pricing?.length) return null;
|
|
4366
|
+
const voiceLike = modelHasVoiceCapability(model);
|
|
4367
|
+
for (const unit of ["audio", "voice"]) {
|
|
4368
|
+
const row = model.pricing.find((p) => p.unit === unit);
|
|
4369
|
+
if (row?.output == null) continue;
|
|
4370
|
+
const usd = row.output;
|
|
4371
|
+
if (usd > 0) return usd;
|
|
4372
|
+
}
|
|
4373
|
+
if (voiceLike) {
|
|
4374
|
+
const row = model.pricing.find((p) => p.unit === "image");
|
|
4375
|
+
if (row?.output == null) return null;
|
|
4376
|
+
const usd = row.output;
|
|
4377
|
+
if (usd > 0) return usd;
|
|
4378
|
+
}
|
|
4379
|
+
return null;
|
|
4380
|
+
}
|
|
4381
|
+
function ttsTokenEstimatesFromResolved(b, scriptCharLength, attachmentCount) {
|
|
4382
|
+
const t = b.voiceGeneration.ttsTokenEstimate;
|
|
4383
|
+
let textTok = Math.round(scriptCharLength / 4);
|
|
4384
|
+
if (textTok <= 0) {
|
|
4385
|
+
textTok = attachmentCount > 0 ? t.whenAttachmentsOnlyTokens : t.whenScriptEmptyTokens;
|
|
4386
|
+
}
|
|
4387
|
+
const rawPrompt = t.promptBaseTokens + textTok + attachmentCount * t.promptPerAttachmentTokens;
|
|
4388
|
+
const promptTokens = Math.min(t.maxTotalTokens, Math.max(0, rawPrompt));
|
|
4389
|
+
const rawOutput = Math.max(t.outputMinimumTokens, Math.round(textTok * t.outputToTextTokenRatio));
|
|
4390
|
+
const outputTokens = Math.min(t.maxTotalTokens, rawOutput);
|
|
4391
|
+
return { promptTokens, outputTokens };
|
|
4392
|
+
}
|
|
4393
|
+
function defaultVoiceTtsTokenEstimates(scriptCharLength, attachmentCount) {
|
|
4394
|
+
return ttsTokenEstimatesFromResolved(
|
|
4395
|
+
mergeAiModelsBilling(null),
|
|
4396
|
+
scriptCharLength,
|
|
4397
|
+
attachmentCount
|
|
4398
|
+
);
|
|
4399
|
+
}
|
|
4400
|
+
function pickVoiceTokenPricing(model, totalTokens) {
|
|
4401
|
+
const tokenPricings = (model?.pricing ?? []).filter((p) => p.unit === "tokens");
|
|
4402
|
+
if (!tokenPricings.length) return null;
|
|
4403
|
+
const isLargeContext = totalTokens > 2e5;
|
|
4404
|
+
const preferred = tokenPricings.find(
|
|
4405
|
+
(p) => isLargeContext ? String(p.contextThreshold ?? "").includes(">") : String(p.contextThreshold ?? "").includes("<=")
|
|
4406
|
+
) || tokenPricings[0];
|
|
4407
|
+
const input = preferred.input ?? 0;
|
|
4408
|
+
const output = preferred.output ?? 0;
|
|
4409
|
+
if (input <= 0 && output <= 0) return null;
|
|
4410
|
+
return { input, output };
|
|
4411
|
+
}
|
|
4412
|
+
var AiCalculator = class {
|
|
4413
|
+
config;
|
|
4414
|
+
constructor(config = {}) {
|
|
4415
|
+
const exchangeRate = config.exchangeRate ?? FALLBACK_AI_EXCHANGE_RATE;
|
|
4416
|
+
const billing = mergeAiModelsBilling(config.billing ?? null);
|
|
4417
|
+
const fallbackDzd = billing.imageGeneration.fallbackProviderCostPerImageUsd * exchangeRate;
|
|
4418
|
+
this.config = {
|
|
4419
|
+
exchangeRate,
|
|
4420
|
+
defaultImageCost: config.defaultImageCost ?? fallbackDzd,
|
|
4421
|
+
referenceImageCost: config.referenceImageCost ?? 5,
|
|
4422
|
+
resolutionCosts: config.resolutionCosts ?? {
|
|
4423
|
+
MEDIA_RESOLUTION_LOW: 0,
|
|
4424
|
+
MEDIA_RESOLUTION_MEDIUM: 5,
|
|
4425
|
+
MEDIA_RESOLUTION_HIGH: 10
|
|
4426
|
+
},
|
|
4427
|
+
models: config.models ?? [],
|
|
4428
|
+
billing
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4431
|
+
/** TTS base DZD: localCost → flat USD row → tokens (per 1M) × estimates × rate × multiplier → floor. */
|
|
4432
|
+
_voiceoverBaseUserCostDzd(modelId, promptTokens, outputTokens) {
|
|
4433
|
+
const { exchangeRate, billing, models } = this.config;
|
|
4434
|
+
const b = billing;
|
|
4435
|
+
const floorDzd = roundMoney(b.voiceGeneration.minimumChargeUsd * exchangeRate);
|
|
4436
|
+
const model = findVoiceModel(models, modelId, "gemini-2.5-pro-preview-tts");
|
|
4437
|
+
if (model?.localCost !== void 0 && model.localCost !== null) {
|
|
4438
|
+
return { baseDzd: roundMoney(model.localCost), usedLocalCost: true };
|
|
4439
|
+
}
|
|
4440
|
+
const providerUsd = pickTtsProviderOutputUsd(model);
|
|
4441
|
+
if (providerUsd != null) {
|
|
4442
|
+
const providerDzd = providerUsd * exchangeRate;
|
|
4443
|
+
return {
|
|
4444
|
+
baseDzd: roundMoney(providerDzd * b.retailMarkup.multiplier),
|
|
4445
|
+
usedLocalCost: false
|
|
4446
|
+
};
|
|
4447
|
+
}
|
|
4448
|
+
const tokenPricing = pickVoiceTokenPricing(model, promptTokens + outputTokens);
|
|
4449
|
+
if (tokenPricing) {
|
|
4450
|
+
const providerCostUsd = promptTokens / 1e6 * tokenPricing.input + outputTokens / 1e6 * tokenPricing.output;
|
|
4451
|
+
const providerDzd = providerCostUsd * exchangeRate;
|
|
4452
|
+
return {
|
|
4453
|
+
baseDzd: roundMoney(providerDzd * b.retailMarkup.multiplier),
|
|
4454
|
+
usedLocalCost: false
|
|
4455
|
+
};
|
|
4456
|
+
}
|
|
4457
|
+
return { baseDzd: floorDzd, usedLocalCost: false };
|
|
4458
|
+
}
|
|
4459
|
+
_attachmentExtraUserDzd(attachmentCount, attachmentResolution) {
|
|
4460
|
+
if (attachmentCount <= 0) return 0;
|
|
4461
|
+
const { exchangeRate, billing } = this.config;
|
|
4462
|
+
const ref = billing.referenceAttachmentSurcharge;
|
|
4463
|
+
const m = billing.retailMarkup.multiplier;
|
|
4464
|
+
let attachCostUsd = attachmentCount * ref.perFileUsd;
|
|
4465
|
+
if (attachmentResolution === "high") {
|
|
4466
|
+
attachCostUsd += attachmentCount * ref.highResolutionExtraPerFileUsd;
|
|
4467
|
+
} else if (attachmentResolution === "low") {
|
|
4468
|
+
attachCostUsd -= attachmentCount * ref.lowResolutionDiscountPerFileUsd;
|
|
4469
|
+
}
|
|
4470
|
+
return roundMoney(attachCostUsd * exchangeRate * m);
|
|
4471
|
+
}
|
|
4472
|
+
/**
|
|
4473
|
+
* Estimate the cost of an image generation action.
|
|
4474
|
+
* Covers: image gen, logo gen, editOrGenerateSimpleImage.
|
|
4475
|
+
*/
|
|
4476
|
+
estimateImageGeneration(options = {}) {
|
|
4477
|
+
const {
|
|
4478
|
+
modelId = "gemini-3.1-flash-image-preview",
|
|
4479
|
+
attachmentCount = 0,
|
|
4480
|
+
attachmentResolution = "medium",
|
|
4481
|
+
resolution,
|
|
4482
|
+
imageSize,
|
|
4483
|
+
iterations = 1,
|
|
4484
|
+
referenceImageCount = 0
|
|
4485
|
+
} = options;
|
|
4486
|
+
const model = findModel(this.config.models, modelId, "gemini-3.1-flash-image-preview");
|
|
4487
|
+
const { exchangeRate, defaultImageCost, billing } = this.config;
|
|
4488
|
+
const mult = billing.retailMarkup.multiplier;
|
|
4489
|
+
const localCost = model?.localCost;
|
|
4490
|
+
const imagePricing = model?.pricing?.find((p) => p.unit === "image");
|
|
4491
|
+
const providerCostUsd = imagePricing?.output ? imagePricing.output : defaultImageCost / exchangeRate;
|
|
4492
|
+
const providerCostDzd = imagePricing?.output ? providerCostUsd * exchangeRate : defaultImageCost;
|
|
4493
|
+
const computedUserCostDzd = providerCostDzd * mult;
|
|
4494
|
+
const usedLocalCost = localCost !== void 0 && localCost !== null;
|
|
4495
|
+
const basePerIteration = usedLocalCost ? localCost : roundMoney(computedUserCostDzd);
|
|
4496
|
+
const baseCostDzd = roundMoney(basePerIteration * iterations);
|
|
4497
|
+
const refExtraDzd = roundMoney(referenceImageCount * this.config.referenceImageCost);
|
|
4498
|
+
const attachExtraDzd = this._attachmentExtraUserDzd(attachmentCount, attachmentResolution);
|
|
4499
|
+
const supportsImageSize = modelId === "gemini-3.1-flash-image-preview";
|
|
4500
|
+
let outputResKey = "MEDIA_RESOLUTION_HIGH";
|
|
4501
|
+
if (supportsImageSize && imageSize) {
|
|
4502
|
+
outputResKey = imageSize === "4K" ? "MEDIA_RESOLUTION_HIGH" : imageSize === "2K" ? "MEDIA_RESOLUTION_MEDIUM" : "MEDIA_RESOLUTION_LOW";
|
|
4503
|
+
} else if (resolution) {
|
|
4504
|
+
outputResKey = resolution;
|
|
4505
|
+
}
|
|
4506
|
+
const outputResExtraDzd = supportsImageSize ? roundMoney(this.config.resolutionCosts[outputResKey] ?? 0) : 0;
|
|
4507
|
+
let referenceResolutionExtraDzd = 0;
|
|
4508
|
+
if (referenceImageCount > 0 && resolution) {
|
|
4509
|
+
const low = this.config.resolutionCosts.MEDIA_RESOLUTION_LOW ?? 0;
|
|
4510
|
+
const tier = this.config.resolutionCosts[resolution] ?? 0;
|
|
4511
|
+
referenceResolutionExtraDzd = roundMoney(Math.max(0, tier - low));
|
|
4512
|
+
}
|
|
4513
|
+
const resExtraDzd = roundMoney(outputResExtraDzd + referenceResolutionExtraDzd);
|
|
4514
|
+
const userCostDzd = roundMoney(baseCostDzd + refExtraDzd + attachExtraDzd + resExtraDzd);
|
|
4515
|
+
return {
|
|
4516
|
+
providerCostUsd: providerCostUsd * iterations,
|
|
4517
|
+
providerCostDzd: providerCostDzd * iterations,
|
|
4518
|
+
userCostDzd,
|
|
4519
|
+
exchangeRate,
|
|
4520
|
+
multiplier: mult,
|
|
4521
|
+
usedLocalCost,
|
|
4522
|
+
breakdown: {
|
|
4523
|
+
baseCostDzd,
|
|
4524
|
+
referenceImageExtraDzd: refExtraDzd,
|
|
4525
|
+
attachmentExtraDzd: attachExtraDzd,
|
|
4526
|
+
outputResolutionExtraDzd: outputResExtraDzd,
|
|
4527
|
+
referenceResolutionExtraDzd,
|
|
4528
|
+
resolutionExtraDzd: resExtraDzd,
|
|
4529
|
+
iterations,
|
|
4530
|
+
referenceImageCount,
|
|
4531
|
+
attachmentCount
|
|
4532
|
+
}
|
|
4533
|
+
};
|
|
4534
|
+
}
|
|
4535
|
+
/**
|
|
4536
|
+
* Estimate the cost of a text generation action.
|
|
4537
|
+
* Covers: updateProductUsingAi, generateSimpleCode, generateCustomComponentCode.
|
|
4538
|
+
* Uses estimated tokens (exact cost billed post-generation).
|
|
4539
|
+
*/
|
|
4540
|
+
estimateTextGeneration(options = {}) {
|
|
4541
|
+
const tg = this.config.billing.textGeneration;
|
|
4542
|
+
const mult = this.config.billing.retailMarkup.multiplier;
|
|
4543
|
+
const {
|
|
4544
|
+
modelId = "gemini-3-flash-preview",
|
|
4545
|
+
estimatedPromptTokens = tg.estimatedPromptTokensDefault,
|
|
4546
|
+
estimatedOutputTokens = tg.estimatedOutputTokensDefault
|
|
4547
|
+
} = options;
|
|
4548
|
+
const totalTokens = estimatedPromptTokens + estimatedOutputTokens;
|
|
4549
|
+
const { exchangeRate } = this.config;
|
|
4550
|
+
const model = findModel(this.config.models, modelId, "gemini-3-flash-preview");
|
|
4551
|
+
const tokenPricing = model?.pricing?.find((p) => p.unit === "tokens");
|
|
4552
|
+
if (!tokenPricing || totalTokens < tg.freeTierMaxPromptTokens) {
|
|
4553
|
+
return {
|
|
4554
|
+
providerCostUsd: 0,
|
|
4555
|
+
providerCostDzd: 0,
|
|
4556
|
+
userCostDzd: 0,
|
|
4557
|
+
exchangeRate,
|
|
4558
|
+
multiplier: mult,
|
|
4559
|
+
usedLocalCost: false,
|
|
4560
|
+
breakdown: {
|
|
4561
|
+
estimatedPromptTokens,
|
|
4562
|
+
estimatedOutputTokens,
|
|
4563
|
+
isFree: true
|
|
4564
|
+
}
|
|
4565
|
+
};
|
|
4566
|
+
}
|
|
4567
|
+
const inputPrice = tokenPricing.input ?? 0;
|
|
4568
|
+
const outputPrice = tokenPricing.output ?? 0;
|
|
4569
|
+
const providerCostUsd = estimatedPromptTokens / 1e6 * inputPrice + estimatedOutputTokens / 1e6 * outputPrice;
|
|
4570
|
+
const providerCostDzd = providerCostUsd * exchangeRate;
|
|
4571
|
+
const userCostDzd = roundMoney(providerCostDzd * mult);
|
|
4572
|
+
return {
|
|
4573
|
+
providerCostUsd,
|
|
4574
|
+
providerCostDzd,
|
|
4575
|
+
userCostDzd,
|
|
4576
|
+
exchangeRate,
|
|
4577
|
+
multiplier: mult,
|
|
4578
|
+
usedLocalCost: false,
|
|
4579
|
+
breakdown: {
|
|
4580
|
+
estimatedPromptTokens,
|
|
4581
|
+
estimatedOutputTokens,
|
|
4582
|
+
isFree: false
|
|
4583
|
+
}
|
|
4584
|
+
};
|
|
4585
|
+
}
|
|
4586
|
+
/**
|
|
4587
|
+
* Voiceover: base + attachment surcharge + optional script-enhancement add-on.
|
|
4588
|
+
*/
|
|
4589
|
+
estimateVoiceover(options = {}) {
|
|
4590
|
+
const modelId = options.modelId ?? "gemini-2.5-pro-preview-tts";
|
|
4591
|
+
const attachmentCount = options.attachmentCount ?? 0;
|
|
4592
|
+
const attachmentResolution = options.attachmentResolution ?? "medium";
|
|
4593
|
+
const enhanceScript = options.enhanceScript !== false;
|
|
4594
|
+
const charLen = options.scriptCharLength ?? 0;
|
|
4595
|
+
const b = this.config.billing;
|
|
4596
|
+
const cap = b.voiceGeneration.ttsTokenEstimate.maxTotalTokens;
|
|
4597
|
+
const tokenEst = (
|
|
4598
|
+
// eslint-disable-next-line eqeqeq
|
|
4599
|
+
options.estimatedPromptTokens != null && options.estimatedOutputTokens != null ? {
|
|
4600
|
+
promptTokens: Math.max(0, Math.min(cap, options.estimatedPromptTokens)),
|
|
4601
|
+
outputTokens: Math.max(0, Math.min(cap, options.estimatedOutputTokens))
|
|
4602
|
+
} : ttsTokenEstimatesFromResolved(b, charLen, attachmentCount)
|
|
4603
|
+
);
|
|
4604
|
+
const { exchangeRate } = this.config;
|
|
4605
|
+
const { baseDzd, usedLocalCost } = this._voiceoverBaseUserCostDzd(
|
|
4606
|
+
modelId,
|
|
4607
|
+
tokenEst.promptTokens,
|
|
4608
|
+
tokenEst.outputTokens
|
|
4609
|
+
);
|
|
4610
|
+
const attachExtra = this._attachmentExtraUserDzd(attachmentCount, attachmentResolution);
|
|
4611
|
+
const enhanceExtra = enhanceScript ? roundMoney(b.voiceGeneration.scriptEnhancementAddonUsd * exchangeRate) : 0;
|
|
4612
|
+
const userCostDzd = roundMoney(baseDzd + attachExtra + enhanceExtra);
|
|
4613
|
+
return {
|
|
4614
|
+
providerCostUsd: userCostDzd / exchangeRate,
|
|
4615
|
+
providerCostDzd: userCostDzd,
|
|
4616
|
+
userCostDzd,
|
|
4617
|
+
exchangeRate,
|
|
4618
|
+
multiplier: 1,
|
|
4619
|
+
usedLocalCost,
|
|
4620
|
+
breakdown: {
|
|
4621
|
+
fixedCostDzd: baseDzd,
|
|
4622
|
+
attachmentExtraDzd: attachExtra,
|
|
4623
|
+
enhanceAddonDzd: enhanceExtra,
|
|
4624
|
+
attachmentCount,
|
|
4625
|
+
estimatedPromptTokens: tokenEst.promptTokens,
|
|
4626
|
+
estimatedOutputTokens: tokenEst.outputTokens
|
|
4627
|
+
}
|
|
4628
|
+
};
|
|
4629
|
+
}
|
|
4630
|
+
/** Get the fixed cost for image landing page generation. */
|
|
4631
|
+
estimateImageLandingPage() {
|
|
4632
|
+
const { exchangeRate, billing } = this.config;
|
|
4633
|
+
const costDzd = roundMoney(billing.landingPageImage.fixedChargeUsd * exchangeRate);
|
|
4634
|
+
return {
|
|
4635
|
+
providerCostUsd: costDzd / exchangeRate,
|
|
4636
|
+
providerCostDzd: costDzd,
|
|
4637
|
+
userCostDzd: costDzd,
|
|
4638
|
+
exchangeRate,
|
|
4639
|
+
multiplier: 1,
|
|
4640
|
+
usedLocalCost: false,
|
|
4641
|
+
breakdown: { fixedCostDzd: costDzd }
|
|
4642
|
+
};
|
|
4643
|
+
}
|
|
4644
|
+
};
|
|
4645
|
+
|
|
4195
4646
|
// src/utils.ts
|
|
4196
4647
|
var convertDartColorToCssNumber = (dartColor) => {
|
|
4197
4648
|
const alpha = dartColor >> 24 & 255;
|
|
@@ -4276,8 +4727,10 @@ function validatePhoneNumber(phone) {
|
|
|
4276
4727
|
return null;
|
|
4277
4728
|
}
|
|
4278
4729
|
export {
|
|
4730
|
+
AI_BILLING,
|
|
4279
4731
|
ATTACHMENT_TYPES,
|
|
4280
4732
|
ActionsService,
|
|
4733
|
+
AiCalculator,
|
|
4281
4734
|
AppRepository,
|
|
4282
4735
|
CartService,
|
|
4283
4736
|
CategoryRepository,
|
|
@@ -4290,6 +4743,7 @@ export {
|
|
|
4290
4743
|
EcomanagerDeliveryIntegrationApi,
|
|
4291
4744
|
EcotrackDeliveryIntegrationApi,
|
|
4292
4745
|
EmbaddedContactType,
|
|
4746
|
+
FALLBACK_AI_EXCHANGE_RATE,
|
|
4293
4747
|
FeedbackPriority,
|
|
4294
4748
|
FeedbackRepository,
|
|
4295
4749
|
FeedbackStatus,
|
|
@@ -4346,6 +4800,9 @@ export {
|
|
|
4346
4800
|
createImageGenerationFormData,
|
|
4347
4801
|
cssColorToHslString,
|
|
4348
4802
|
dartColorToCssColor,
|
|
4803
|
+
defaultVoiceTtsTokenEstimates,
|
|
4804
|
+
formatProductLandingPageOrderReference,
|
|
4805
|
+
formatProductOrderReference,
|
|
4349
4806
|
generatePublicIntegrationsData,
|
|
4350
4807
|
generatePublicIntegrationsDataGoogleAnalytics,
|
|
4351
4808
|
generatePublicIntegrationsDataGoogleSheets,
|
|
@@ -4366,9 +4823,11 @@ export {
|
|
|
4366
4823
|
generatePublicStoreIntegrationWebhooks,
|
|
4367
4824
|
generatePublicStoreIntegrations,
|
|
4368
4825
|
getAvailableShippingTypes,
|
|
4826
|
+
getLegacyAiBillingFlat,
|
|
4369
4827
|
getShippingPrice,
|
|
4370
4828
|
isAttachmentType,
|
|
4371
4829
|
isShippingAvailable,
|
|
4830
|
+
mergeAiModelsBilling,
|
|
4372
4831
|
normalizeAttachmentPayload,
|
|
4373
4832
|
normalizeAttachmentPayloads,
|
|
4374
4833
|
normalizeImageGeneration,
|