pixelkiln 0.70.1 → 0.71.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/index.d.cts CHANGED
@@ -18099,6 +18099,8 @@ interface GallerySkeleton {
18099
18099
  keypointsFile: string;
18100
18100
  /** The parsed file; null until it exists. A malformed file fails the whole resolve, as in `plan`. */
18101
18101
  set: SkeletonSet | null;
18102
+ /** The file's bytes as resolved; a save from the page must quote it, so a concurrent edit is refused. */
18103
+ sha256: string | null;
18102
18104
  }
18103
18105
  interface GalleryCharacter {
18104
18106
  /** Which family this belongs to: a skeleton-based `character`, or a skeleton-free `objectPro`. */
package/dist/index.d.ts CHANGED
@@ -18099,6 +18099,8 @@ interface GallerySkeleton {
18099
18099
  keypointsFile: string;
18100
18100
  /** The parsed file; null until it exists. A malformed file fails the whole resolve, as in `plan`. */
18101
18101
  set: SkeletonSet | null;
18102
+ /** The file's bytes as resolved; a save from the page must quote it, so a concurrent edit is refused. */
18103
+ sha256: string | null;
18102
18104
  }
18103
18105
  interface GalleryCharacter {
18104
18106
  /** Which family this belongs to: a skeleton-based `character`, or a skeleton-free `objectPro`. */
package/dist/index.js CHANGED
@@ -15623,6 +15623,15 @@ var SkeletonAnimationRequestSchema = z10.object({
15623
15623
  /** Replace an existing `keypointsFile` with `set`. */
15624
15624
  overwrite: z10.boolean().optional()
15625
15625
  }).strict();
15626
+ var SkeletonKeypointsUpdateSchema = z10.object({
15627
+ action: z10.literal("update-skeleton-keypoints"),
15628
+ project: z10.string().min(1).optional(),
15629
+ styleId: z10.string().min(1),
15630
+ assetId: z10.string().min(1),
15631
+ /** The file's SHA-256 when the page loaded it; anything else on disk is a concurrent edit. */
15632
+ expectedSha256: z10.string().regex(/^[0-9a-f]{64}$/),
15633
+ set: SkeletonSetSchema
15634
+ }).strict();
15626
15635
  async function createSkeletonAnimation(manifestPath, request) {
15627
15636
  const root = path28.dirname(path28.resolve(manifestPath));
15628
15637
  const file = path28.resolve(root, request.keypointsFile);
@@ -15668,6 +15677,26 @@ async function createSkeletonAnimation(manifestPath, request) {
15668
15677
  throw error;
15669
15678
  }
15670
15679
  }
15680
+ async function updateSkeletonKeypoints(ctx, request) {
15681
+ const key = lockKey(request.styleId, request.assetId);
15682
+ const spec = ctx.specs.find((candidate) => lockKey(candidate.styleId, candidate.assetId) === key);
15683
+ if (!spec) throw new ManifestEditError(`"${key}" is not declared by the manifest`);
15684
+ const file = spec.revision?.mode === "animate-skeleton" ? spec.revision.keypointsFile : void 0;
15685
+ if (!file) throw new ManifestEditError(`${key} is not an animate-skeleton revision`);
15686
+ const relative = path28.relative(ctx.loaded.root, file);
15687
+ if (relative.startsWith("..") || path28.isAbsolute(relative)) {
15688
+ throw new ManifestEditError(`${key}'s keypoints file is outside the project; edit it by hand`);
15689
+ }
15690
+ const current = existsSync23(file) ? sha256(await readFile21(file)) : null;
15691
+ if (current !== request.expectedSha256) {
15692
+ throw Object.assign(
15693
+ new Error(`${relative.split(path28.sep).join("/")} changed on disk since this page loaded it; press Refresh and edit again`),
15694
+ { status: 409 }
15695
+ );
15696
+ }
15697
+ await writeFile12(file, JSON.stringify(request.set, null, 2) + "\n");
15698
+ return relative.split(path28.sep).join("/");
15699
+ }
15671
15700
 
15672
15701
  // src/gallery/edit.ts
15673
15702
  var Base64 = z11.string().regex(/^[A-Za-z0-9+/]*={0,2}$/).max(Math.ceil(MAX_HAND_EDIT_BYTES / 3) * 4);
@@ -15744,6 +15773,18 @@ function createGalleryEditHandler(opts) {
15744
15773
  }
15745
15774
  return opts.reload();
15746
15775
  }
15776
+ const poses = SkeletonKeypointsUpdateSchema.safeParse(body);
15777
+ if (poses.success) {
15778
+ if (!opts.loadProject) throw new ManifestEditError("pose edits are not available in this gallery");
15779
+ const written = await updateSkeletonKeypoints(await opts.loadProject(poses.data.project), poses.data);
15780
+ log(` poses saved: ${written} (${poses.data.styleId}/${poses.data.assetId} is stale until generated again)`);
15781
+ return opts.reload();
15782
+ }
15783
+ if (body?.action === "update-skeleton-keypoints") {
15784
+ throw new ManifestEditError(
15785
+ "invalid pose edit: " + poses.error.issues.slice(0, 3).map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ")
15786
+ );
15787
+ }
15747
15788
  const skeleton = SkeletonAnimationRequestSchema.safeParse(body);
15748
15789
  if (skeleton.success) {
15749
15790
  let manifestPath2;
@@ -16117,7 +16158,8 @@ async function buildGallerySnapshot(opts) {
16117
16158
  mirrorOfKey: spec.mirror ? lockKey(spec.styleId, spec.mirror.sourceAssetId) : entry?.mirror ? lockKey(spec.styleId, entry.mirror.sourceAssetId) : null,
16118
16159
  skeleton: spec.revision?.mode === "animate-skeleton" && spec.revision.keypointsFile ? {
16119
16160
  keypointsFile: portableOutputPath(spec.revision.keypointsFile, root),
16120
- set: spec.revision.skeleton ?? null
16161
+ set: spec.revision.skeleton ?? null,
16162
+ sha256: spec.revision.keypointsSha256 ?? null
16121
16163
  } : null,
16122
16164
  character: describeCharacter(spec, entry),
16123
16165
  outputs,