feeef 0.8.11 → 0.8.13
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 +450 -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 +14 -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/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/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
|
|
@@ -434,6 +444,13 @@ var StoreRepository = class extends ModelRepository {
|
|
|
434
444
|
}
|
|
435
445
|
return chartData;
|
|
436
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* Lite orders report for the store (8 UTC days + total).
|
|
449
|
+
*/
|
|
450
|
+
async liteOrdersReport(storeId) {
|
|
451
|
+
const res = await this.client.get(`/${this.resource}/${storeId}/analytics/lor`);
|
|
452
|
+
return res.data;
|
|
453
|
+
}
|
|
437
454
|
/**
|
|
438
455
|
* Adds a member to the store.
|
|
439
456
|
* @param storeId - The store ID.
|
|
@@ -1815,6 +1832,15 @@ var ProductLandingPagesRepository = class extends ModelRepository {
|
|
|
1815
1832
|
const params = { ...options?.params };
|
|
1816
1833
|
return super.list({ params });
|
|
1817
1834
|
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Lite orders report for a product landing page in a store.
|
|
1837
|
+
*/
|
|
1838
|
+
async liteOrdersReport(storeId, landingPageId) {
|
|
1839
|
+
const res = await this.client.get(
|
|
1840
|
+
`/stores/${storeId}/product_landing_pages/${landingPageId}/analytics/lor`
|
|
1841
|
+
);
|
|
1842
|
+
return res.data;
|
|
1843
|
+
}
|
|
1818
1844
|
};
|
|
1819
1845
|
|
|
1820
1846
|
// src/core/entities/attachment.ts
|
|
@@ -4085,6 +4111,14 @@ var ProductType = /* @__PURE__ */ ((ProductType2) => {
|
|
|
4085
4111
|
ProductType2["service"] = "service";
|
|
4086
4112
|
return ProductType2;
|
|
4087
4113
|
})(ProductType || {});
|
|
4114
|
+
function formatProductOrderReference(productId) {
|
|
4115
|
+
return `product:${productId}`;
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
// src/core/entities/product_landing_page.ts
|
|
4119
|
+
function formatProductLandingPageOrderReference(landingPageId) {
|
|
4120
|
+
return `product_landing_page:${landingPageId}`;
|
|
4121
|
+
}
|
|
4088
4122
|
|
|
4089
4123
|
// src/core/entities/feedback.ts
|
|
4090
4124
|
var FeedbackStatus = /* @__PURE__ */ ((FeedbackStatus2) => {
|
|
@@ -4192,6 +4226,414 @@ function createFeeefTransmitFromAxios(client, options) {
|
|
|
4192
4226
|
});
|
|
4193
4227
|
}
|
|
4194
4228
|
|
|
4229
|
+
// src/ai/ai_calculator.ts
|
|
4230
|
+
var FALLBACK_AI_EXCHANGE_RATE = 260;
|
|
4231
|
+
var DEFAULT_TTS = {
|
|
4232
|
+
whenScriptEmptyTokens: 200,
|
|
4233
|
+
whenAttachmentsOnlyTokens: 400,
|
|
4234
|
+
promptBaseTokens: 400,
|
|
4235
|
+
promptPerAttachmentTokens: 300,
|
|
4236
|
+
outputMinimumTokens: 300,
|
|
4237
|
+
outputToTextTokenRatio: 2.5,
|
|
4238
|
+
maxTotalTokens: 32e3
|
|
4239
|
+
};
|
|
4240
|
+
var DEFAULT_RESOLVED = {
|
|
4241
|
+
retailMarkup: { multiplier: 2.5 },
|
|
4242
|
+
referenceAttachmentSurcharge: {
|
|
4243
|
+
perFileUsd: 0.1,
|
|
4244
|
+
highResolutionExtraPerFileUsd: 0.05,
|
|
4245
|
+
lowResolutionDiscountPerFileUsd: 0.05
|
|
4246
|
+
},
|
|
4247
|
+
imageGeneration: { fallbackProviderCostPerImageUsd: 0.131 },
|
|
4248
|
+
textGeneration: {
|
|
4249
|
+
freeTierMaxPromptTokens: 1e3,
|
|
4250
|
+
estimatedPromptTokensDefault: 2e3,
|
|
4251
|
+
estimatedOutputTokensDefault: 1e3
|
|
4252
|
+
},
|
|
4253
|
+
voiceGeneration: {
|
|
4254
|
+
minimumChargeUsd: 50 / FALLBACK_AI_EXCHANGE_RATE,
|
|
4255
|
+
scriptEnhancementAddonUsd: 25 / FALLBACK_AI_EXCHANGE_RATE,
|
|
4256
|
+
ttsTokenEstimate: { ...DEFAULT_TTS }
|
|
4257
|
+
},
|
|
4258
|
+
landingPageImage: {
|
|
4259
|
+
fixedChargeUsd: 100 / FALLBACK_AI_EXCHANGE_RATE
|
|
4260
|
+
}
|
|
4261
|
+
};
|
|
4262
|
+
function mergeTts(base, partial) {
|
|
4263
|
+
if (!partial) return { ...base };
|
|
4264
|
+
return {
|
|
4265
|
+
whenScriptEmptyTokens: partial.whenScriptEmptyTokens ?? base.whenScriptEmptyTokens,
|
|
4266
|
+
whenAttachmentsOnlyTokens: partial.whenAttachmentsOnlyTokens ?? base.whenAttachmentsOnlyTokens,
|
|
4267
|
+
promptBaseTokens: partial.promptBaseTokens ?? base.promptBaseTokens,
|
|
4268
|
+
promptPerAttachmentTokens: partial.promptPerAttachmentTokens ?? base.promptPerAttachmentTokens,
|
|
4269
|
+
outputMinimumTokens: partial.outputMinimumTokens ?? base.outputMinimumTokens,
|
|
4270
|
+
outputToTextTokenRatio: partial.outputToTextTokenRatio ?? base.outputToTextTokenRatio,
|
|
4271
|
+
maxTotalTokens: partial.maxTotalTokens ?? base.maxTotalTokens
|
|
4272
|
+
};
|
|
4273
|
+
}
|
|
4274
|
+
function mergeAiModelsBilling(partial) {
|
|
4275
|
+
const d = DEFAULT_RESOLVED;
|
|
4276
|
+
if (!partial) return structuredClone(d);
|
|
4277
|
+
const v = partial.voiceGeneration;
|
|
4278
|
+
const tts = mergeTts(d.voiceGeneration.ttsTokenEstimate, v?.ttsTokenEstimate);
|
|
4279
|
+
return {
|
|
4280
|
+
retailMarkup: {
|
|
4281
|
+
multiplier: partial.retailMarkup?.multiplier ?? d.retailMarkup.multiplier
|
|
4282
|
+
},
|
|
4283
|
+
referenceAttachmentSurcharge: {
|
|
4284
|
+
perFileUsd: partial.referenceAttachmentSurcharge?.perFileUsd ?? d.referenceAttachmentSurcharge.perFileUsd,
|
|
4285
|
+
highResolutionExtraPerFileUsd: partial.referenceAttachmentSurcharge?.highResolutionExtraPerFileUsd ?? d.referenceAttachmentSurcharge.highResolutionExtraPerFileUsd,
|
|
4286
|
+
lowResolutionDiscountPerFileUsd: partial.referenceAttachmentSurcharge?.lowResolutionDiscountPerFileUsd ?? d.referenceAttachmentSurcharge.lowResolutionDiscountPerFileUsd
|
|
4287
|
+
},
|
|
4288
|
+
imageGeneration: {
|
|
4289
|
+
fallbackProviderCostPerImageUsd: partial.imageGeneration?.fallbackProviderCostPerImageUsd ?? d.imageGeneration.fallbackProviderCostPerImageUsd
|
|
4290
|
+
},
|
|
4291
|
+
textGeneration: {
|
|
4292
|
+
freeTierMaxPromptTokens: partial.textGeneration?.freeTierMaxPromptTokens ?? d.textGeneration.freeTierMaxPromptTokens,
|
|
4293
|
+
estimatedPromptTokensDefault: partial.textGeneration?.estimatedPromptTokensDefault ?? d.textGeneration.estimatedPromptTokensDefault,
|
|
4294
|
+
estimatedOutputTokensDefault: partial.textGeneration?.estimatedOutputTokensDefault ?? d.textGeneration.estimatedOutputTokensDefault
|
|
4295
|
+
},
|
|
4296
|
+
voiceGeneration: {
|
|
4297
|
+
minimumChargeUsd: v?.minimumChargeUsd ?? d.voiceGeneration.minimumChargeUsd,
|
|
4298
|
+
scriptEnhancementAddonUsd: v?.scriptEnhancementAddonUsd ?? d.voiceGeneration.scriptEnhancementAddonUsd,
|
|
4299
|
+
ttsTokenEstimate: tts
|
|
4300
|
+
},
|
|
4301
|
+
landingPageImage: {
|
|
4302
|
+
fixedChargeUsd: partial.landingPageImage?.fixedChargeUsd ?? d.landingPageImage.fixedChargeUsd
|
|
4303
|
+
}
|
|
4304
|
+
};
|
|
4305
|
+
}
|
|
4306
|
+
function roundMoney(amount, precision = 3) {
|
|
4307
|
+
const factor = 10 ** precision;
|
|
4308
|
+
return Math.round((amount + Number.EPSILON) * factor) / factor;
|
|
4309
|
+
}
|
|
4310
|
+
function getLegacyAiBillingFlat(exchangeRate, resolved = mergeAiModelsBilling(null)) {
|
|
4311
|
+
const t = resolved.voiceGeneration.ttsTokenEstimate;
|
|
4312
|
+
return {
|
|
4313
|
+
MULTIPLIER: resolved.retailMarkup.multiplier,
|
|
4314
|
+
FREE_TEXT_TOKENS_THRESHOLD: resolved.textGeneration.freeTierMaxPromptTokens,
|
|
4315
|
+
DEFAULT_EXCHANGE_RATE: FALLBACK_AI_EXCHANGE_RATE,
|
|
4316
|
+
DEFAULT_GOOGLE_IMAGE_COST_USD: resolved.imageGeneration.fallbackProviderCostPerImageUsd,
|
|
4317
|
+
DEFAULT_ATTACHMENT_COST_USD: resolved.referenceAttachmentSurcharge.perFileUsd,
|
|
4318
|
+
ATTACHMENT_HIGH_RES_EXTRA_USD: resolved.referenceAttachmentSurcharge.highResolutionExtraPerFileUsd,
|
|
4319
|
+
ATTACHMENT_LOW_RES_DISCOUNT_USD: resolved.referenceAttachmentSurcharge.lowResolutionDiscountPerFileUsd,
|
|
4320
|
+
VOICEOVER_FIXED_COST_DZD: roundMoney(
|
|
4321
|
+
resolved.voiceGeneration.minimumChargeUsd * exchangeRate,
|
|
4322
|
+
3
|
|
4323
|
+
),
|
|
4324
|
+
VOICEOVER_ENHANCE_ADDON_DZD: roundMoney(
|
|
4325
|
+
resolved.voiceGeneration.scriptEnhancementAddonUsd * exchangeRate,
|
|
4326
|
+
3
|
|
4327
|
+
),
|
|
4328
|
+
IMAGE_LANDING_PAGE_FIXED_COST_DZD: roundMoney(
|
|
4329
|
+
resolved.landingPageImage.fixedChargeUsd * exchangeRate,
|
|
4330
|
+
3
|
|
4331
|
+
),
|
|
4332
|
+
DEFAULT_TEXT_PROMPT_TOKENS: resolved.textGeneration.estimatedPromptTokensDefault,
|
|
4333
|
+
DEFAULT_TEXT_OUTPUT_TOKENS: resolved.textGeneration.estimatedOutputTokensDefault,
|
|
4334
|
+
VOICE_TTS_EMPTY_SCRIPT_TEXT_TOKENS: t.whenScriptEmptyTokens,
|
|
4335
|
+
VOICE_TTS_ATTACHMENT_ONLY_TEXT_TOKENS: t.whenAttachmentsOnlyTokens,
|
|
4336
|
+
VOICE_TTS_PROMPT_BASE: t.promptBaseTokens,
|
|
4337
|
+
VOICE_TTS_PROMPT_PER_ATTACHMENT: t.promptPerAttachmentTokens,
|
|
4338
|
+
VOICE_TTS_OUTPUT_MIN: t.outputMinimumTokens,
|
|
4339
|
+
VOICE_TTS_OUTPUT_TEXT_FACTOR: t.outputToTextTokenRatio,
|
|
4340
|
+
VOICE_TTS_TOKEN_CAP: t.maxTotalTokens
|
|
4341
|
+
};
|
|
4342
|
+
}
|
|
4343
|
+
var AI_BILLING = getLegacyAiBillingFlat(FALLBACK_AI_EXCHANGE_RATE);
|
|
4344
|
+
function findModel(models, modelId, fallbackId) {
|
|
4345
|
+
return models.find((m) => m.id === modelId) || models.find((m) => m.id === fallbackId) || models[0];
|
|
4346
|
+
}
|
|
4347
|
+
function modelHasVoiceCapability(model) {
|
|
4348
|
+
const caps = model?.capabilities;
|
|
4349
|
+
if (!Array.isArray(caps)) return false;
|
|
4350
|
+
return caps.some((c) => c === "voice" || c === "audio");
|
|
4351
|
+
}
|
|
4352
|
+
function findVoiceModel(models, modelId, fallbackId) {
|
|
4353
|
+
return models.find((m) => m.id === modelId) || models.find((m) => m.id === fallbackId) || models.find((m) => modelHasVoiceCapability(m));
|
|
4354
|
+
}
|
|
4355
|
+
function pickTtsProviderOutputUsd(model) {
|
|
4356
|
+
if (!model?.pricing?.length) return null;
|
|
4357
|
+
const voiceLike = modelHasVoiceCapability(model);
|
|
4358
|
+
for (const unit of ["audio", "voice"]) {
|
|
4359
|
+
const row = model.pricing.find((p) => p.unit === unit);
|
|
4360
|
+
if (row?.output == null) continue;
|
|
4361
|
+
const usd = row.output;
|
|
4362
|
+
if (usd > 0) return usd;
|
|
4363
|
+
}
|
|
4364
|
+
if (voiceLike) {
|
|
4365
|
+
const row = model.pricing.find((p) => p.unit === "image");
|
|
4366
|
+
if (row?.output == null) return null;
|
|
4367
|
+
const usd = row.output;
|
|
4368
|
+
if (usd > 0) return usd;
|
|
4369
|
+
}
|
|
4370
|
+
return null;
|
|
4371
|
+
}
|
|
4372
|
+
function ttsTokenEstimatesFromResolved(b, scriptCharLength, attachmentCount) {
|
|
4373
|
+
const t = b.voiceGeneration.ttsTokenEstimate;
|
|
4374
|
+
let textTok = Math.round(scriptCharLength / 4);
|
|
4375
|
+
if (textTok <= 0) {
|
|
4376
|
+
textTok = attachmentCount > 0 ? t.whenAttachmentsOnlyTokens : t.whenScriptEmptyTokens;
|
|
4377
|
+
}
|
|
4378
|
+
const rawPrompt = t.promptBaseTokens + textTok + attachmentCount * t.promptPerAttachmentTokens;
|
|
4379
|
+
const promptTokens = Math.min(t.maxTotalTokens, Math.max(0, rawPrompt));
|
|
4380
|
+
const rawOutput = Math.max(t.outputMinimumTokens, Math.round(textTok * t.outputToTextTokenRatio));
|
|
4381
|
+
const outputTokens = Math.min(t.maxTotalTokens, rawOutput);
|
|
4382
|
+
return { promptTokens, outputTokens };
|
|
4383
|
+
}
|
|
4384
|
+
function defaultVoiceTtsTokenEstimates(scriptCharLength, attachmentCount) {
|
|
4385
|
+
return ttsTokenEstimatesFromResolved(
|
|
4386
|
+
mergeAiModelsBilling(null),
|
|
4387
|
+
scriptCharLength,
|
|
4388
|
+
attachmentCount
|
|
4389
|
+
);
|
|
4390
|
+
}
|
|
4391
|
+
function pickVoiceTokenPricing(model, totalTokens) {
|
|
4392
|
+
const tokenPricings = (model?.pricing ?? []).filter((p) => p.unit === "tokens");
|
|
4393
|
+
if (!tokenPricings.length) return null;
|
|
4394
|
+
const isLargeContext = totalTokens > 2e5;
|
|
4395
|
+
const preferred = tokenPricings.find(
|
|
4396
|
+
(p) => isLargeContext ? String(p.contextThreshold ?? "").includes(">") : String(p.contextThreshold ?? "").includes("<=")
|
|
4397
|
+
) || tokenPricings[0];
|
|
4398
|
+
const input = preferred.input ?? 0;
|
|
4399
|
+
const output = preferred.output ?? 0;
|
|
4400
|
+
if (input <= 0 && output <= 0) return null;
|
|
4401
|
+
return { input, output };
|
|
4402
|
+
}
|
|
4403
|
+
var AiCalculator = class {
|
|
4404
|
+
config;
|
|
4405
|
+
constructor(config = {}) {
|
|
4406
|
+
const exchangeRate = config.exchangeRate ?? FALLBACK_AI_EXCHANGE_RATE;
|
|
4407
|
+
const billing = mergeAiModelsBilling(config.billing ?? null);
|
|
4408
|
+
const fallbackDzd = billing.imageGeneration.fallbackProviderCostPerImageUsd * exchangeRate;
|
|
4409
|
+
this.config = {
|
|
4410
|
+
exchangeRate,
|
|
4411
|
+
defaultImageCost: config.defaultImageCost ?? fallbackDzd,
|
|
4412
|
+
referenceImageCost: config.referenceImageCost ?? 5,
|
|
4413
|
+
resolutionCosts: config.resolutionCosts ?? {
|
|
4414
|
+
MEDIA_RESOLUTION_LOW: 0,
|
|
4415
|
+
MEDIA_RESOLUTION_MEDIUM: 5,
|
|
4416
|
+
MEDIA_RESOLUTION_HIGH: 10
|
|
4417
|
+
},
|
|
4418
|
+
models: config.models ?? [],
|
|
4419
|
+
billing
|
|
4420
|
+
};
|
|
4421
|
+
}
|
|
4422
|
+
/** TTS base DZD: localCost → flat USD row → tokens (per 1M) × estimates × rate × multiplier → floor. */
|
|
4423
|
+
_voiceoverBaseUserCostDzd(modelId, promptTokens, outputTokens) {
|
|
4424
|
+
const { exchangeRate, billing, models } = this.config;
|
|
4425
|
+
const b = billing;
|
|
4426
|
+
const floorDzd = roundMoney(b.voiceGeneration.minimumChargeUsd * exchangeRate);
|
|
4427
|
+
const model = findVoiceModel(models, modelId, "gemini-2.5-pro-preview-tts");
|
|
4428
|
+
if (model?.localCost !== void 0 && model.localCost !== null) {
|
|
4429
|
+
return { baseDzd: roundMoney(model.localCost), usedLocalCost: true };
|
|
4430
|
+
}
|
|
4431
|
+
const providerUsd = pickTtsProviderOutputUsd(model);
|
|
4432
|
+
if (providerUsd != null) {
|
|
4433
|
+
const providerDzd = providerUsd * exchangeRate;
|
|
4434
|
+
return {
|
|
4435
|
+
baseDzd: roundMoney(providerDzd * b.retailMarkup.multiplier),
|
|
4436
|
+
usedLocalCost: false
|
|
4437
|
+
};
|
|
4438
|
+
}
|
|
4439
|
+
const tokenPricing = pickVoiceTokenPricing(model, promptTokens + outputTokens);
|
|
4440
|
+
if (tokenPricing) {
|
|
4441
|
+
const providerCostUsd = promptTokens / 1e6 * tokenPricing.input + outputTokens / 1e6 * tokenPricing.output;
|
|
4442
|
+
const providerDzd = providerCostUsd * exchangeRate;
|
|
4443
|
+
return {
|
|
4444
|
+
baseDzd: roundMoney(providerDzd * b.retailMarkup.multiplier),
|
|
4445
|
+
usedLocalCost: false
|
|
4446
|
+
};
|
|
4447
|
+
}
|
|
4448
|
+
return { baseDzd: floorDzd, usedLocalCost: false };
|
|
4449
|
+
}
|
|
4450
|
+
_attachmentExtraUserDzd(attachmentCount, attachmentResolution) {
|
|
4451
|
+
if (attachmentCount <= 0) return 0;
|
|
4452
|
+
const { exchangeRate, billing } = this.config;
|
|
4453
|
+
const ref = billing.referenceAttachmentSurcharge;
|
|
4454
|
+
const m = billing.retailMarkup.multiplier;
|
|
4455
|
+
let attachCostUsd = attachmentCount * ref.perFileUsd;
|
|
4456
|
+
if (attachmentResolution === "high") {
|
|
4457
|
+
attachCostUsd += attachmentCount * ref.highResolutionExtraPerFileUsd;
|
|
4458
|
+
} else if (attachmentResolution === "low") {
|
|
4459
|
+
attachCostUsd -= attachmentCount * ref.lowResolutionDiscountPerFileUsd;
|
|
4460
|
+
}
|
|
4461
|
+
return roundMoney(attachCostUsd * exchangeRate * m);
|
|
4462
|
+
}
|
|
4463
|
+
/**
|
|
4464
|
+
* Estimate the cost of an image generation action.
|
|
4465
|
+
* Covers: image gen, logo gen, editOrGenerateSimpleImage.
|
|
4466
|
+
*/
|
|
4467
|
+
estimateImageGeneration(options = {}) {
|
|
4468
|
+
const {
|
|
4469
|
+
modelId = "gemini-3.1-flash-image-preview",
|
|
4470
|
+
attachmentCount = 0,
|
|
4471
|
+
attachmentResolution = "medium",
|
|
4472
|
+
resolution,
|
|
4473
|
+
imageSize,
|
|
4474
|
+
iterations = 1,
|
|
4475
|
+
referenceImageCount = 0
|
|
4476
|
+
} = options;
|
|
4477
|
+
const model = findModel(this.config.models, modelId, "gemini-3.1-flash-image-preview");
|
|
4478
|
+
const { exchangeRate, defaultImageCost, billing } = this.config;
|
|
4479
|
+
const mult = billing.retailMarkup.multiplier;
|
|
4480
|
+
const localCost = model?.localCost;
|
|
4481
|
+
const imagePricing = model?.pricing?.find((p) => p.unit === "image");
|
|
4482
|
+
const providerCostUsd = imagePricing?.output ? imagePricing.output : defaultImageCost / exchangeRate;
|
|
4483
|
+
const providerCostDzd = imagePricing?.output ? providerCostUsd * exchangeRate : defaultImageCost;
|
|
4484
|
+
const computedUserCostDzd = providerCostDzd * mult;
|
|
4485
|
+
const usedLocalCost = localCost !== void 0 && localCost !== null;
|
|
4486
|
+
const basePerIteration = usedLocalCost ? localCost : roundMoney(computedUserCostDzd);
|
|
4487
|
+
const baseCostDzd = roundMoney(basePerIteration * iterations);
|
|
4488
|
+
const refExtraDzd = roundMoney(referenceImageCount * this.config.referenceImageCost);
|
|
4489
|
+
const attachExtraDzd = this._attachmentExtraUserDzd(attachmentCount, attachmentResolution);
|
|
4490
|
+
const supportsImageSize = modelId === "gemini-3.1-flash-image-preview";
|
|
4491
|
+
let outputResKey = "MEDIA_RESOLUTION_HIGH";
|
|
4492
|
+
if (supportsImageSize && imageSize) {
|
|
4493
|
+
outputResKey = imageSize === "4K" ? "MEDIA_RESOLUTION_HIGH" : imageSize === "2K" ? "MEDIA_RESOLUTION_MEDIUM" : "MEDIA_RESOLUTION_LOW";
|
|
4494
|
+
} else if (resolution) {
|
|
4495
|
+
outputResKey = resolution;
|
|
4496
|
+
}
|
|
4497
|
+
const outputResExtraDzd = supportsImageSize ? roundMoney(this.config.resolutionCosts[outputResKey] ?? 0) : 0;
|
|
4498
|
+
let referenceResolutionExtraDzd = 0;
|
|
4499
|
+
if (referenceImageCount > 0 && resolution) {
|
|
4500
|
+
const low = this.config.resolutionCosts.MEDIA_RESOLUTION_LOW ?? 0;
|
|
4501
|
+
const tier = this.config.resolutionCosts[resolution] ?? 0;
|
|
4502
|
+
referenceResolutionExtraDzd = roundMoney(Math.max(0, tier - low));
|
|
4503
|
+
}
|
|
4504
|
+
const resExtraDzd = roundMoney(outputResExtraDzd + referenceResolutionExtraDzd);
|
|
4505
|
+
const userCostDzd = roundMoney(baseCostDzd + refExtraDzd + attachExtraDzd + resExtraDzd);
|
|
4506
|
+
return {
|
|
4507
|
+
providerCostUsd: providerCostUsd * iterations,
|
|
4508
|
+
providerCostDzd: providerCostDzd * iterations,
|
|
4509
|
+
userCostDzd,
|
|
4510
|
+
exchangeRate,
|
|
4511
|
+
multiplier: mult,
|
|
4512
|
+
usedLocalCost,
|
|
4513
|
+
breakdown: {
|
|
4514
|
+
baseCostDzd,
|
|
4515
|
+
referenceImageExtraDzd: refExtraDzd,
|
|
4516
|
+
attachmentExtraDzd: attachExtraDzd,
|
|
4517
|
+
outputResolutionExtraDzd: outputResExtraDzd,
|
|
4518
|
+
referenceResolutionExtraDzd,
|
|
4519
|
+
resolutionExtraDzd: resExtraDzd,
|
|
4520
|
+
iterations,
|
|
4521
|
+
referenceImageCount,
|
|
4522
|
+
attachmentCount
|
|
4523
|
+
}
|
|
4524
|
+
};
|
|
4525
|
+
}
|
|
4526
|
+
/**
|
|
4527
|
+
* Estimate the cost of a text generation action.
|
|
4528
|
+
* Covers: updateProductUsingAi, generateSimpleCode, generateCustomComponentCode.
|
|
4529
|
+
* Uses estimated tokens (exact cost billed post-generation).
|
|
4530
|
+
*/
|
|
4531
|
+
estimateTextGeneration(options = {}) {
|
|
4532
|
+
const tg = this.config.billing.textGeneration;
|
|
4533
|
+
const mult = this.config.billing.retailMarkup.multiplier;
|
|
4534
|
+
const {
|
|
4535
|
+
modelId = "gemini-3-flash-preview",
|
|
4536
|
+
estimatedPromptTokens = tg.estimatedPromptTokensDefault,
|
|
4537
|
+
estimatedOutputTokens = tg.estimatedOutputTokensDefault
|
|
4538
|
+
} = options;
|
|
4539
|
+
const totalTokens = estimatedPromptTokens + estimatedOutputTokens;
|
|
4540
|
+
const { exchangeRate } = this.config;
|
|
4541
|
+
const model = findModel(this.config.models, modelId, "gemini-3-flash-preview");
|
|
4542
|
+
const tokenPricing = model?.pricing?.find((p) => p.unit === "tokens");
|
|
4543
|
+
if (!tokenPricing || totalTokens < tg.freeTierMaxPromptTokens) {
|
|
4544
|
+
return {
|
|
4545
|
+
providerCostUsd: 0,
|
|
4546
|
+
providerCostDzd: 0,
|
|
4547
|
+
userCostDzd: 0,
|
|
4548
|
+
exchangeRate,
|
|
4549
|
+
multiplier: mult,
|
|
4550
|
+
usedLocalCost: false,
|
|
4551
|
+
breakdown: {
|
|
4552
|
+
estimatedPromptTokens,
|
|
4553
|
+
estimatedOutputTokens,
|
|
4554
|
+
isFree: true
|
|
4555
|
+
}
|
|
4556
|
+
};
|
|
4557
|
+
}
|
|
4558
|
+
const inputPrice = tokenPricing.input ?? 0;
|
|
4559
|
+
const outputPrice = tokenPricing.output ?? 0;
|
|
4560
|
+
const providerCostUsd = estimatedPromptTokens / 1e6 * inputPrice + estimatedOutputTokens / 1e6 * outputPrice;
|
|
4561
|
+
const providerCostDzd = providerCostUsd * exchangeRate;
|
|
4562
|
+
const userCostDzd = roundMoney(providerCostDzd * mult);
|
|
4563
|
+
return {
|
|
4564
|
+
providerCostUsd,
|
|
4565
|
+
providerCostDzd,
|
|
4566
|
+
userCostDzd,
|
|
4567
|
+
exchangeRate,
|
|
4568
|
+
multiplier: mult,
|
|
4569
|
+
usedLocalCost: false,
|
|
4570
|
+
breakdown: {
|
|
4571
|
+
estimatedPromptTokens,
|
|
4572
|
+
estimatedOutputTokens,
|
|
4573
|
+
isFree: false
|
|
4574
|
+
}
|
|
4575
|
+
};
|
|
4576
|
+
}
|
|
4577
|
+
/**
|
|
4578
|
+
* Voiceover: base + attachment surcharge + optional script-enhancement add-on.
|
|
4579
|
+
*/
|
|
4580
|
+
estimateVoiceover(options = {}) {
|
|
4581
|
+
const modelId = options.modelId ?? "gemini-2.5-pro-preview-tts";
|
|
4582
|
+
const attachmentCount = options.attachmentCount ?? 0;
|
|
4583
|
+
const attachmentResolution = options.attachmentResolution ?? "medium";
|
|
4584
|
+
const enhanceScript = options.enhanceScript !== false;
|
|
4585
|
+
const charLen = options.scriptCharLength ?? 0;
|
|
4586
|
+
const b = this.config.billing;
|
|
4587
|
+
const cap = b.voiceGeneration.ttsTokenEstimate.maxTotalTokens;
|
|
4588
|
+
const tokenEst = (
|
|
4589
|
+
// eslint-disable-next-line eqeqeq
|
|
4590
|
+
options.estimatedPromptTokens != null && options.estimatedOutputTokens != null ? {
|
|
4591
|
+
promptTokens: Math.max(0, Math.min(cap, options.estimatedPromptTokens)),
|
|
4592
|
+
outputTokens: Math.max(0, Math.min(cap, options.estimatedOutputTokens))
|
|
4593
|
+
} : ttsTokenEstimatesFromResolved(b, charLen, attachmentCount)
|
|
4594
|
+
);
|
|
4595
|
+
const { exchangeRate } = this.config;
|
|
4596
|
+
const { baseDzd, usedLocalCost } = this._voiceoverBaseUserCostDzd(
|
|
4597
|
+
modelId,
|
|
4598
|
+
tokenEst.promptTokens,
|
|
4599
|
+
tokenEst.outputTokens
|
|
4600
|
+
);
|
|
4601
|
+
const attachExtra = this._attachmentExtraUserDzd(attachmentCount, attachmentResolution);
|
|
4602
|
+
const enhanceExtra = enhanceScript ? roundMoney(b.voiceGeneration.scriptEnhancementAddonUsd * exchangeRate) : 0;
|
|
4603
|
+
const userCostDzd = roundMoney(baseDzd + attachExtra + enhanceExtra);
|
|
4604
|
+
return {
|
|
4605
|
+
providerCostUsd: userCostDzd / exchangeRate,
|
|
4606
|
+
providerCostDzd: userCostDzd,
|
|
4607
|
+
userCostDzd,
|
|
4608
|
+
exchangeRate,
|
|
4609
|
+
multiplier: 1,
|
|
4610
|
+
usedLocalCost,
|
|
4611
|
+
breakdown: {
|
|
4612
|
+
fixedCostDzd: baseDzd,
|
|
4613
|
+
attachmentExtraDzd: attachExtra,
|
|
4614
|
+
enhanceAddonDzd: enhanceExtra,
|
|
4615
|
+
attachmentCount,
|
|
4616
|
+
estimatedPromptTokens: tokenEst.promptTokens,
|
|
4617
|
+
estimatedOutputTokens: tokenEst.outputTokens
|
|
4618
|
+
}
|
|
4619
|
+
};
|
|
4620
|
+
}
|
|
4621
|
+
/** Get the fixed cost for image landing page generation. */
|
|
4622
|
+
estimateImageLandingPage() {
|
|
4623
|
+
const { exchangeRate, billing } = this.config;
|
|
4624
|
+
const costDzd = roundMoney(billing.landingPageImage.fixedChargeUsd * exchangeRate);
|
|
4625
|
+
return {
|
|
4626
|
+
providerCostUsd: costDzd / exchangeRate,
|
|
4627
|
+
providerCostDzd: costDzd,
|
|
4628
|
+
userCostDzd: costDzd,
|
|
4629
|
+
exchangeRate,
|
|
4630
|
+
multiplier: 1,
|
|
4631
|
+
usedLocalCost: false,
|
|
4632
|
+
breakdown: { fixedCostDzd: costDzd }
|
|
4633
|
+
};
|
|
4634
|
+
}
|
|
4635
|
+
};
|
|
4636
|
+
|
|
4195
4637
|
// src/utils.ts
|
|
4196
4638
|
var convertDartColorToCssNumber = (dartColor) => {
|
|
4197
4639
|
const alpha = dartColor >> 24 & 255;
|
|
@@ -4276,8 +4718,10 @@ function validatePhoneNumber(phone) {
|
|
|
4276
4718
|
return null;
|
|
4277
4719
|
}
|
|
4278
4720
|
export {
|
|
4721
|
+
AI_BILLING,
|
|
4279
4722
|
ATTACHMENT_TYPES,
|
|
4280
4723
|
ActionsService,
|
|
4724
|
+
AiCalculator,
|
|
4281
4725
|
AppRepository,
|
|
4282
4726
|
CartService,
|
|
4283
4727
|
CategoryRepository,
|
|
@@ -4290,6 +4734,7 @@ export {
|
|
|
4290
4734
|
EcomanagerDeliveryIntegrationApi,
|
|
4291
4735
|
EcotrackDeliveryIntegrationApi,
|
|
4292
4736
|
EmbaddedContactType,
|
|
4737
|
+
FALLBACK_AI_EXCHANGE_RATE,
|
|
4293
4738
|
FeedbackPriority,
|
|
4294
4739
|
FeedbackRepository,
|
|
4295
4740
|
FeedbackStatus,
|
|
@@ -4346,6 +4791,9 @@ export {
|
|
|
4346
4791
|
createImageGenerationFormData,
|
|
4347
4792
|
cssColorToHslString,
|
|
4348
4793
|
dartColorToCssColor,
|
|
4794
|
+
defaultVoiceTtsTokenEstimates,
|
|
4795
|
+
formatProductLandingPageOrderReference,
|
|
4796
|
+
formatProductOrderReference,
|
|
4349
4797
|
generatePublicIntegrationsData,
|
|
4350
4798
|
generatePublicIntegrationsDataGoogleAnalytics,
|
|
4351
4799
|
generatePublicIntegrationsDataGoogleSheets,
|
|
@@ -4366,9 +4814,11 @@ export {
|
|
|
4366
4814
|
generatePublicStoreIntegrationWebhooks,
|
|
4367
4815
|
generatePublicStoreIntegrations,
|
|
4368
4816
|
getAvailableShippingTypes,
|
|
4817
|
+
getLegacyAiBillingFlat,
|
|
4369
4818
|
getShippingPrice,
|
|
4370
4819
|
isAttachmentType,
|
|
4371
4820
|
isShippingAvailable,
|
|
4821
|
+
mergeAiModelsBilling,
|
|
4372
4822
|
normalizeAttachmentPayload,
|
|
4373
4823
|
normalizeAttachmentPayloads,
|
|
4374
4824
|
normalizeImageGeneration,
|