pixelkiln 0.47.0 → 0.48.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/dist/cli.js +131 -46
- package/dist/cli.js.map +1 -1
- package/dist/client/gallery.js +6 -1
- package/dist/index.cjs +97 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +203 -6
- package/dist/index.d.ts +203 -6
- package/dist/index.js +97 -27
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +12 -6
- package/docs/ARTIFACTS.md +8 -1
- package/docs/CHARACTERS.md +5 -1
- package/docs/CLI.md +10 -1
- package/docs/ENDPOINTS.md +11 -1
- package/docs/GENERATORS.md +4 -0
- package/docs/PIXELLAB.md +15 -7
- package/package.json +1 -1
package/dist/client/gallery.js
CHANGED
|
@@ -1050,7 +1050,9 @@ function historySection(item) {
|
|
|
1050
1050
|
else thumb.append(el('span', null, g.cached ? '' : 'not cached'));
|
|
1051
1051
|
const facts = el('div', 'facts');
|
|
1052
1052
|
const head = el('div');
|
|
1053
|
-
|
|
1053
|
+
const billedNote = g.billed && (g.billed.unit !== g.costUnit || g.billed.amount !== g.cost)
|
|
1054
|
+
? ' (billed ' + fmtCost(g.billed.unit, g.billed.amount) + ')' : '';
|
|
1055
|
+
head.append(el('b', null, '#' + g.index), document.createTextNode(' · ' + fmtWhen(g.downloadedAt || g.submittedAt) + ' · ' + fmtCost(g.costUnit, g.cost) + billedNote +
|
|
1054
1056
|
(g.outputs.length > 1 ? ' · ' + g.outputs.length + ' files' : '')));
|
|
1055
1057
|
facts.append(head);
|
|
1056
1058
|
const prompt = el('div', 'prompt' + (g.promptDiffers ? ' differs' : ''), (g.promptDiffers ? 'prompt: ' : 'same prompt: ') + g.prompt);
|
|
@@ -1876,6 +1878,9 @@ function renderDrawer() {
|
|
|
1876
1878
|
if (item.currentPrompt) row(dl, 'prompt now', el('div', 'prompt state-warn', item.currentPrompt));
|
|
1877
1879
|
row(dl, 'size', item.width + ' × ' + item.height + ' px');
|
|
1878
1880
|
if (item.status) row(dl, 'cost', fmtCost(item.costUnit, item.cost));
|
|
1881
|
+
if (item.billed && (item.billed.unit !== item.costUnit || item.billed.amount !== item.cost)) {
|
|
1882
|
+
row(dl, 'billed', fmtCost(item.billed.unit, item.billed.amount));
|
|
1883
|
+
}
|
|
1879
1884
|
if (item.postprocess && item.postprocess.palette) {
|
|
1880
1885
|
// What fetch did to the provider's bytes before writing them.
|
|
1881
1886
|
const p = item.postprocess.palette;
|
package/dist/index.cjs
CHANGED
|
@@ -967,6 +967,8 @@ var LockHistoryEntrySchema = import_zod.z.object({
|
|
|
967
967
|
downloadedAt: import_zod.z.string().nullable().default(null),
|
|
968
968
|
cost: import_zod.z.number().finite().nonnegative().default(0),
|
|
969
969
|
costUnit: import_zod.z.string().min(1).default("generations"),
|
|
970
|
+
/** What the provider actually billed, read from the completed job; null when never read. */
|
|
971
|
+
billed: import_zod.z.object({ amount: import_zod.z.number(), unit: import_zod.z.string() }).nullable().default(null),
|
|
970
972
|
provider: import_zod.z.string().default("pixellab"),
|
|
971
973
|
postprocess: PostprocessSchema.optional(),
|
|
972
974
|
/** When the replacement was submitted. */
|
|
@@ -1058,6 +1060,14 @@ var LockEntrySchema = import_zod.z.object({
|
|
|
1058
1060
|
cost: import_zod.z.number().finite().nonnegative().default(0),
|
|
1059
1061
|
/** Unit for `cost`. Defaults preserve pre-unit PixelLab lockfiles. */
|
|
1060
1062
|
costUnit: import_zod.z.string().min(1).default("generations"),
|
|
1063
|
+
/**
|
|
1064
|
+
* What the provider actually billed, read from the completed job rather
|
|
1065
|
+
* than estimated at submit time. Null until a poll reads it, and for a
|
|
1066
|
+
* provider or generator `poll` does not read it from at all; `cost` above
|
|
1067
|
+
* is still what a wave budget spends against, since the real number is
|
|
1068
|
+
* only known after the fact.
|
|
1069
|
+
*/
|
|
1070
|
+
billed: import_zod.z.object({ amount: import_zod.z.number(), unit: import_zod.z.string() }).nullable().default(null),
|
|
1061
1071
|
/** Which provider produced this. Absent on entries written before providers. */
|
|
1062
1072
|
provider: import_zod.z.string().default("pixellab"),
|
|
1063
1073
|
/** Generations this entry replaced, newest first; see LockHistoryEntrySchema. */
|
|
@@ -1311,7 +1321,13 @@ var CharacterListSchema = import_zod2.z.object({ characters: import_zod2.z.array
|
|
|
1311
1321
|
var BackgroundJobSchema = import_zod2.z.object({
|
|
1312
1322
|
id: import_zod2.z.string(),
|
|
1313
1323
|
status: import_zod2.z.string(),
|
|
1314
|
-
last_response: import_zod2.z.record(import_zod2.z.unknown()).nullable().optional()
|
|
1324
|
+
last_response: import_zod2.z.record(import_zod2.z.unknown()).nullable().optional(),
|
|
1325
|
+
/**
|
|
1326
|
+
* The billed amount, confirmed live for a `map` object and a standard
|
|
1327
|
+
* character base (docs/ENDPOINTS.md, "Limits and billing"); duplicated at
|
|
1328
|
+
* `last_response.billing_usage` on the jobs observed so far.
|
|
1329
|
+
*/
|
|
1330
|
+
usage: UsageSchema
|
|
1315
1331
|
}).passthrough();
|
|
1316
1332
|
var DeleteAnimationsSchema = import_zod2.z.object({ success: import_zod2.z.boolean(), deleted_count: import_zod2.z.number().int().default(0), error: import_zod2.z.string().nullable().optional() }).passthrough();
|
|
1317
1333
|
function validateResponse(schema, raw, operation) {
|
|
@@ -2406,6 +2422,14 @@ function pixelLabObjectUrl(generator, objectId) {
|
|
|
2406
2422
|
}
|
|
2407
2423
|
return null;
|
|
2408
2424
|
}
|
|
2425
|
+
function billedFromUsage(usage) {
|
|
2426
|
+
if (!usage) return null;
|
|
2427
|
+
if (usage.type === "usd" || usage.type === void 0 && typeof usage.usd === "number") {
|
|
2428
|
+
return typeof usage.usd === "number" ? { amount: usage.usd, unit: "usd" } : null;
|
|
2429
|
+
}
|
|
2430
|
+
if (typeof usage.generations === "number") return { amount: usage.generations, unit: "generations" };
|
|
2431
|
+
return null;
|
|
2432
|
+
}
|
|
2409
2433
|
function characterCost(spec) {
|
|
2410
2434
|
const character = spec.character;
|
|
2411
2435
|
if (!character) return generationCost(spec.width, spec.height, "1dir");
|
|
@@ -2776,6 +2800,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2776
2800
|
if (character.status !== "completed" || !character.rotation_urls) return { status: "processing" };
|
|
2777
2801
|
const sources = rotationSources(character);
|
|
2778
2802
|
if (!sources.length) return { status: "failed", error: "character completed with no rotation images" };
|
|
2803
|
+
const backgroundJobId = context?.metadata?.character?.backgroundJobId;
|
|
2779
2804
|
return {
|
|
2780
2805
|
status: "ready",
|
|
2781
2806
|
objectId: character.id,
|
|
@@ -2791,7 +2816,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2791
2816
|
size: character.size,
|
|
2792
2817
|
updatedAt: character.updated_at ?? null
|
|
2793
2818
|
}
|
|
2794
|
-
}
|
|
2819
|
+
},
|
|
2820
|
+
billed: await this.billedForJob(backgroundJobId)
|
|
2795
2821
|
};
|
|
2796
2822
|
}
|
|
2797
2823
|
/**
|
|
@@ -2803,7 +2829,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2803
2829
|
*/
|
|
2804
2830
|
async pollCharacterAnimation(job, context) {
|
|
2805
2831
|
const fps = context?.spec?.character?.animation?.fps ?? 8;
|
|
2806
|
-
const review = (frames, animationId, groupId) => ({
|
|
2832
|
+
const review = (frames, animationId, groupId, billed) => ({
|
|
2807
2833
|
status: "review-set",
|
|
2808
2834
|
objectId: `${job.characterId}#${groupId ?? animationId ?? job.name}`,
|
|
2809
2835
|
frameUrls: frames,
|
|
@@ -2819,7 +2845,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2819
2845
|
animationName: job.name,
|
|
2820
2846
|
direction: job.direction
|
|
2821
2847
|
}
|
|
2822
|
-
}
|
|
2848
|
+
},
|
|
2849
|
+
billed
|
|
2823
2850
|
});
|
|
2824
2851
|
let cleanedUp = job.jobIds.length === 0;
|
|
2825
2852
|
for (const id of job.jobIds) {
|
|
@@ -2839,13 +2866,13 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2839
2866
|
if (Array.isArray(frames) && frames.length && frames.every((f) => typeof f === "string")) {
|
|
2840
2867
|
const character2 = await this.client.getCharacter(job.characterId);
|
|
2841
2868
|
const group = findAnimation(character2, job.name, job.direction, animationId);
|
|
2842
|
-
return review(frames, animationId, group?.groupId ?? null);
|
|
2869
|
+
return review(frames, animationId, group?.groupId ?? null, billedFromUsage(status.usage));
|
|
2843
2870
|
}
|
|
2844
2871
|
}
|
|
2845
2872
|
const recorded = context?.metadata?.character?.animationId ?? null;
|
|
2846
2873
|
const character = await this.client.getCharacter(job.characterId);
|
|
2847
2874
|
const found = findAnimation(character, job.name, job.direction, recorded);
|
|
2848
|
-
if (found) return review(found.frames, found.animationId, found.groupId);
|
|
2875
|
+
if (found) return review(found.frames, found.animationId, found.groupId, null);
|
|
2849
2876
|
return cleanedUp ? { status: "failed", error: `animation job is gone upstream and no "${job.name}" ${job.direction} animation exists on the character` } : { status: "processing" };
|
|
2850
2877
|
}
|
|
2851
2878
|
async submit(spec, styleImages, context) {
|
|
@@ -2878,7 +2905,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2878
2905
|
// unlike 1dir's {type, base64, format} payload.
|
|
2879
2906
|
styleImages: styleImages.map(({ base64, width, height }) => ({ base64, width, height }))
|
|
2880
2907
|
});
|
|
2881
|
-
return { jobId: res2.tile_id };
|
|
2908
|
+
return { jobId: res2.tile_id, metadata: { backgroundJobId: res2.background_job_id } };
|
|
2882
2909
|
}
|
|
2883
2910
|
if (spec.generator === "1dir") {
|
|
2884
2911
|
const res2 = await this.client.create1Direction({
|
|
@@ -2887,7 +2914,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2887
2914
|
view: spec.view === "sidescroller" ? "sidescroller" : "top-down",
|
|
2888
2915
|
styleImages
|
|
2889
2916
|
});
|
|
2890
|
-
return { jobId: res2.object_id };
|
|
2917
|
+
return { jobId: res2.object_id, metadata: { backgroundJobId: res2.background_job_id } };
|
|
2891
2918
|
}
|
|
2892
2919
|
const res = await this.client.createMapObject({
|
|
2893
2920
|
description: spec.prompt,
|
|
@@ -2899,7 +2926,22 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2899
2926
|
detail: spec.detail,
|
|
2900
2927
|
seed: spec.seed
|
|
2901
2928
|
});
|
|
2902
|
-
return { jobId: res.object_id };
|
|
2929
|
+
return { jobId: res.object_id, metadata: { backgroundJobId: res.background_job_id } };
|
|
2930
|
+
}
|
|
2931
|
+
/**
|
|
2932
|
+
* What a background job actually billed, once its own record is still
|
|
2933
|
+
* around to ask; see `billedFromUsage`. A stale or already-cleaned-up job
|
|
2934
|
+
* (a map object's record expires in hours; see `pollMap`) means "not
|
|
2935
|
+
* known", not a failure worth surfacing.
|
|
2936
|
+
*/
|
|
2937
|
+
async billedForJob(backgroundJobId) {
|
|
2938
|
+
if (!backgroundJobId) return null;
|
|
2939
|
+
try {
|
|
2940
|
+
const job = await this.client.getBackgroundJob(backgroundJobId);
|
|
2941
|
+
return billedFromUsage(job.usage);
|
|
2942
|
+
} catch {
|
|
2943
|
+
return null;
|
|
2944
|
+
}
|
|
2903
2945
|
}
|
|
2904
2946
|
async poll(jobId, generator, context) {
|
|
2905
2947
|
if (generator === "pixflux") {
|
|
@@ -2913,16 +2955,17 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2913
2955
|
error: "pixflux result is no longer cached locally; re-run submit for this asset"
|
|
2914
2956
|
};
|
|
2915
2957
|
}
|
|
2916
|
-
if (generator === "map") return this.pollMap(jobId);
|
|
2917
|
-
if (generator === "tiles") return this.pollTiles(jobId, Boolean(context?.tileFeature));
|
|
2958
|
+
if (generator === "map") return this.pollMap(jobId, context);
|
|
2959
|
+
if (generator === "tiles") return this.pollTiles(jobId, Boolean(context?.tileFeature), context);
|
|
2918
2960
|
if (generator === "character") return this.pollCharacter(jobId, context);
|
|
2961
|
+
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
2919
2962
|
const obj = await this.client.getObject(jobId);
|
|
2920
2963
|
if (obj.status === "review") {
|
|
2921
|
-
return { status: "review", candidateUrls: obj.frame_urls ?? [] };
|
|
2964
|
+
return { status: "review", candidateUrls: obj.frame_urls ?? [], billed: await this.billedForJob(backgroundJobId) };
|
|
2922
2965
|
}
|
|
2923
2966
|
if (obj.status === "completed") {
|
|
2924
2967
|
const url = firstUrl(obj.rotation_urls) ?? obj.preview_url ?? null;
|
|
2925
|
-
return { status: "ready", objectId: obj.id, sourceUrl: url, sources: url ? [{ url }] : [] };
|
|
2968
|
+
return { status: "ready", objectId: obj.id, sourceUrl: url, sources: url ? [{ url }] : [], billed: await this.billedForJob(backgroundJobId) };
|
|
2926
2969
|
}
|
|
2927
2970
|
if (obj.status === "failed") return { status: "failed", error: "generation failed upstream" };
|
|
2928
2971
|
return {
|
|
@@ -2938,7 +2981,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2938
2981
|
* `/objects` four months on, with `/map-objects` returning 404 for the same
|
|
2939
2982
|
* id. So a 404 here is not evidence the work is lost.
|
|
2940
2983
|
*/
|
|
2941
|
-
async pollMap(jobId) {
|
|
2984
|
+
async pollMap(jobId, context) {
|
|
2985
|
+
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
2942
2986
|
try {
|
|
2943
2987
|
const obj = await this.client.getMapObject(jobId);
|
|
2944
2988
|
if (obj.status === "completed" && obj.download_url) {
|
|
@@ -2946,7 +2990,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2946
2990
|
status: "ready",
|
|
2947
2991
|
objectId: jobId,
|
|
2948
2992
|
sourceUrl: obj.download_url,
|
|
2949
|
-
sources: [{ url: obj.download_url }]
|
|
2993
|
+
sources: [{ url: obj.download_url }],
|
|
2994
|
+
billed: await this.billedForJob(backgroundJobId)
|
|
2950
2995
|
};
|
|
2951
2996
|
}
|
|
2952
2997
|
if (obj.status === "failed") return { status: "failed", error: "generation failed upstream" };
|
|
@@ -2957,7 +3002,7 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2957
3002
|
const survivor = await this.client.getObject(jobId).catch(() => null);
|
|
2958
3003
|
const url = firstUrl(survivor?.rotation_urls) ?? survivor?.preview_url ?? null;
|
|
2959
3004
|
if (survivor?.status === "completed" && url) {
|
|
2960
|
-
return { status: "ready", objectId: survivor.id, sourceUrl: url, sources: [{ url }] };
|
|
3005
|
+
return { status: "ready", objectId: survivor.id, sourceUrl: url, sources: [{ url }], billed: null };
|
|
2961
3006
|
}
|
|
2962
3007
|
return {
|
|
2963
3008
|
status: "failed",
|
|
@@ -2970,12 +3015,14 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2970
3015
|
* `storage_urls` once finished. There is no `status` field to read and no
|
|
2971
3016
|
* progress percentage on offer, so "processing" here carries no ETA.
|
|
2972
3017
|
*/
|
|
2973
|
-
async pollTiles(tileId, connectable) {
|
|
3018
|
+
async pollTiles(tileId, connectable, context) {
|
|
2974
3019
|
try {
|
|
2975
3020
|
const set = await this.client.getTilesPro(tileId);
|
|
2976
3021
|
const tiles = tilesInIndexOrder(set.storage_urls);
|
|
2977
3022
|
if (!tiles.length) return { status: "failed", error: "tiles job returned no storage urls" };
|
|
2978
|
-
|
|
3023
|
+
const backgroundJobId = context?.metadata?.backgroundJobId;
|
|
3024
|
+
const billed = await this.billedForJob(backgroundJobId);
|
|
3025
|
+
if (!connectable) return { status: "review", candidateUrls: tiles.map((tile) => tile.url), billed };
|
|
2979
3026
|
return {
|
|
2980
3027
|
status: "ready",
|
|
2981
3028
|
objectId: tileId,
|
|
@@ -2987,7 +3034,8 @@ var PixelLabProvider = class _PixelLabProvider {
|
|
|
2987
3034
|
metadata: {
|
|
2988
3035
|
tileKind: set.kind,
|
|
2989
3036
|
...set.tile_rules ? { tileRules: set.tile_rules } : {}
|
|
2990
|
-
}
|
|
3037
|
+
},
|
|
3038
|
+
billed
|
|
2991
3039
|
};
|
|
2992
3040
|
} catch (err) {
|
|
2993
3041
|
if (err instanceof PixelLabError && err.status === 423) return { status: "processing" };
|
|
@@ -9228,6 +9276,7 @@ function retireGeneration(entry, retiredAt) {
|
|
|
9228
9276
|
downloadedAt: entry.downloadedAt,
|
|
9229
9277
|
cost: entry.cost,
|
|
9230
9278
|
costUnit: entry.costUnit,
|
|
9279
|
+
billed: entry.billed,
|
|
9231
9280
|
provider: entry.provider,
|
|
9232
9281
|
postprocess: entry.postprocess,
|
|
9233
9282
|
retiredAt
|
|
@@ -9318,6 +9367,7 @@ async function revertGeneration(provider, spec, lock, lockPath, opts) {
|
|
|
9318
9367
|
downloadedAt: generation.downloadedAt,
|
|
9319
9368
|
cost: generation.cost,
|
|
9320
9369
|
costUnit: generation.costUnit,
|
|
9370
|
+
billed: generation.billed,
|
|
9321
9371
|
provider: generation.provider,
|
|
9322
9372
|
postprocess: generation.postprocess,
|
|
9323
9373
|
history
|
|
@@ -9523,15 +9573,27 @@ function packSprites(inputs, options = {}) {
|
|
|
9523
9573
|
const sheetH = rows * cellH;
|
|
9524
9574
|
const rgba = Buffer.alloc(sheetW * sheetH * 4);
|
|
9525
9575
|
const frames = [];
|
|
9576
|
+
const pivot = options.pivot ?? "top-left";
|
|
9526
9577
|
sprites.forEach((sprite, i) => {
|
|
9527
|
-
const
|
|
9528
|
-
const
|
|
9578
|
+
const cellOx = i % columns * cellW;
|
|
9579
|
+
const cellOy = Math.floor(i / columns) * cellH;
|
|
9580
|
+
const offsetX = pivot === "bottom-center" ? Math.floor((cellW - sprite.width) / 2) : 0;
|
|
9581
|
+
const offsetY = pivot === "bottom-center" ? cellH - sprite.height : 0;
|
|
9582
|
+
const ox = cellOx + offsetX;
|
|
9583
|
+
const oy = cellOy + offsetY;
|
|
9529
9584
|
for (let y = 0; y < sprite.height; y++) {
|
|
9530
9585
|
const src = y * sprite.width * 4;
|
|
9531
9586
|
const dst = ((oy + y) * sheetW + ox) * 4;
|
|
9532
9587
|
sprite.pixels.copy(rgba, dst, src, src + sprite.width * 4);
|
|
9533
9588
|
}
|
|
9534
|
-
frames.push({
|
|
9589
|
+
frames.push({
|
|
9590
|
+
id: sprite.id,
|
|
9591
|
+
x: ox,
|
|
9592
|
+
y: oy,
|
|
9593
|
+
width: sprite.width,
|
|
9594
|
+
height: sprite.height,
|
|
9595
|
+
...offsetX || offsetY ? { offsetX, offsetY } : {}
|
|
9596
|
+
});
|
|
9535
9597
|
});
|
|
9536
9598
|
return {
|
|
9537
9599
|
png: encodeRgbaPng(sheetW, sheetH, rgba),
|
|
@@ -10048,12 +10110,15 @@ function renderAsepriteSheet(atlas, opts) {
|
|
|
10048
10110
|
}
|
|
10049
10111
|
const frames = {};
|
|
10050
10112
|
for (const frame of atlas.frames) {
|
|
10113
|
+
const offsetX = frame.offsetX ?? 0;
|
|
10114
|
+
const offsetY = frame.offsetY ?? 0;
|
|
10115
|
+
const pivoted = offsetX !== 0 || offsetY !== 0;
|
|
10051
10116
|
frames[frame.id] = {
|
|
10052
10117
|
frame: { x: frame.x, y: frame.y, w: frame.width, h: frame.height },
|
|
10053
10118
|
rotated: false,
|
|
10054
|
-
trimmed:
|
|
10055
|
-
spriteSourceSize: { x: 0, y: 0, w: frame.width, h: frame.height },
|
|
10056
|
-
sourceSize: { w: frame.width, h: frame.height },
|
|
10119
|
+
trimmed: pivoted,
|
|
10120
|
+
spriteSourceSize: pivoted ? { x: offsetX, y: offsetY, w: frame.width, h: frame.height } : { x: 0, y: 0, w: frame.width, h: frame.height },
|
|
10121
|
+
sourceSize: pivoted ? { w: atlas.cell.width, h: atlas.cell.height } : { w: frame.width, h: frame.height },
|
|
10057
10122
|
duration: durations.get(frame.id) ?? ASEPRITE_DEFAULT_DURATION_MS
|
|
10058
10123
|
};
|
|
10059
10124
|
}
|
|
@@ -10384,7 +10449,8 @@ async function poll(provider, lock, lockPath, opts = {}) {
|
|
|
10384
10449
|
...entry.providerMetadata[provider.id],
|
|
10385
10450
|
...state.metadata
|
|
10386
10451
|
}
|
|
10387
|
-
} : entry.providerMetadata
|
|
10452
|
+
} : entry.providerMetadata,
|
|
10453
|
+
billed: state.billed ?? entry.billed
|
|
10388
10454
|
});
|
|
10389
10455
|
result.review++;
|
|
10390
10456
|
log(
|
|
@@ -10404,7 +10470,8 @@ async function poll(provider, lock, lockPath, opts = {}) {
|
|
|
10404
10470
|
...state.metadata
|
|
10405
10471
|
}
|
|
10406
10472
|
} : entry.providerMetadata,
|
|
10407
|
-
error: null
|
|
10473
|
+
error: null,
|
|
10474
|
+
billed: state.billed ?? entry.billed
|
|
10408
10475
|
});
|
|
10409
10476
|
result.completed++;
|
|
10410
10477
|
log(` ready ${key}`);
|
|
@@ -12263,6 +12330,7 @@ function describeHistory(media, entry, cacheDir) {
|
|
|
12263
12330
|
height: generation.height,
|
|
12264
12331
|
cost: generation.cost,
|
|
12265
12332
|
costUnit: generation.costUnit,
|
|
12333
|
+
billed: generation.billed,
|
|
12266
12334
|
submittedAt: generation.submittedAt,
|
|
12267
12335
|
downloadedAt: generation.downloadedAt,
|
|
12268
12336
|
retiredAt: generation.retiredAt,
|
|
@@ -12506,6 +12574,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
12506
12574
|
fps: quality?.frameSet?.fps ?? metadataFps(entry) ?? spec.quality?.fps ?? null,
|
|
12507
12575
|
cost: entry?.cost ?? 0,
|
|
12508
12576
|
costUnit: entry?.costUnit ?? spec.costUnit,
|
|
12577
|
+
billed: entry?.billed ?? null,
|
|
12509
12578
|
estimatedCost: spec.cost,
|
|
12510
12579
|
candidates: spec.candidates,
|
|
12511
12580
|
submittedAt: entry?.submittedAt ?? null,
|
|
@@ -12569,6 +12638,7 @@ async function buildGallerySnapshot(opts) {
|
|
|
12569
12638
|
fps: metadataFps(entry),
|
|
12570
12639
|
cost: entry.cost,
|
|
12571
12640
|
costUnit: entry.costUnit,
|
|
12641
|
+
billed: entry.billed,
|
|
12572
12642
|
estimatedCost: null,
|
|
12573
12643
|
candidates: null,
|
|
12574
12644
|
submittedAt: entry.submittedAt,
|