@sortedyuan/media 0.0.0-stage → 0.3.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yuan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,13 @@
1
- # Temporary Holding Version
1
+ # @sortedyuan/media
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Image attachments, ordered presentation content, raster validation and filesystem
4
+ storage shared by May applications and channels. Runtime dependencies are
5
+ `@sortedyuan/core`, `@sortedyuan/session` and `sharp`. Requires Node.js 22 or later.
6
+
7
+ `FileMediaStore.save()` and `verify()` coordinate file access across local
8
+ processes. Each saved image retains empty `.access` and `.access.gate` files beside
9
+ it. Initial access to an older image needs directory write permission to create
10
+ these files; subsequent verification only needs read permission on all three files.
11
+
12
+ See the [English guide](../../docs/en/guides/images.md) and
13
+ [简体中文指南](../../docs/zh-CN/guides/images.md) for APIs and supported sources.
@@ -0,0 +1,44 @@
1
+ import type { ContentPart, MediaSource } from "@sortedyuan/core";
2
+ export interface ImageAttachment {
3
+ readonly id: string;
4
+ readonly mediaType?: string;
5
+ readonly url?: string;
6
+ readonly fileId?: string;
7
+ }
8
+ export type DisplayPart = {
9
+ readonly type: "text";
10
+ readonly text: string;
11
+ } | {
12
+ readonly type: "image";
13
+ readonly image: ImageAttachment;
14
+ };
15
+ export interface ImageData {
16
+ readonly data: Uint8Array;
17
+ readonly mediaType: string;
18
+ readonly width: number;
19
+ readonly height: number;
20
+ }
21
+ export interface SavedImage extends ImageData {
22
+ readonly id: string;
23
+ readonly path: string;
24
+ }
25
+ export type MediaReader = (source: MediaSource, signal?: AbortSignal) => Promise<ImageData>;
26
+ export interface MediaCapabilities {
27
+ readonly images: boolean;
28
+ readonly maxImageBytes: number;
29
+ readonly mediaTypes: readonly string[];
30
+ }
31
+ export declare const MAX_IMAGE_BYTES: number;
32
+ export declare function imageAttachment(source: MediaSource): ImageAttachment;
33
+ export declare function displayParts(content: readonly ContentPart[]): DisplayPart[];
34
+ export declare function inspectImage(data: Uint8Array): Promise<ImageData>;
35
+ export declare const readEmbeddedImage: MediaReader;
36
+ export declare class FileMediaStore {
37
+ readonly directory: string;
38
+ readonly read: MediaReader;
39
+ constructor(directory: string, read?: MediaReader);
40
+ save(source: MediaSource, signal?: AbortSignal): Promise<SavedImage>;
41
+ verify(saved: SavedImage): Promise<ImageData>;
42
+ }
43
+ export declare function imagePng(image: ImageData): Promise<Buffer>;
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGjE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AACD,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;CAAE,CAAC;AAChE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AACD,MAAM,WAAW,UAAW,SAAQ,SAAS;IAAG,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAC5F,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5F,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AACD,eAAO,MAAM,eAAe,QAAmB,CAAC;AAEhD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAQpE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAO3E;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAUvE;AAED,eAAO,MAAM,iBAAiB,EAAE,WAQ/B,CAAC;AAEF,qBAAa,cAAc;IACb,QAAQ,CAAC,SAAS,EAAE,MAAM;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW;IAAlE,YAAqB,SAAS,EAAE,MAAM,EAAW,IAAI,GAAE,WAA+B,EAAI;IACpF,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAczE;IACK,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAElD;CACF;AAED,wBAAsB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhE"}
package/dist/index.js ADDED
@@ -0,0 +1,94 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { mkdir, open, rename, readFile, rm } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { withFileAccess } from "@sortedyuan/session/file-access";
5
+ export const MAX_IMAGE_BYTES = 32 * 1024 * 1024;
6
+ export function imageAttachment(source) {
7
+ const id = createHash("sha256").update(JSON.stringify(source)).digest("hex");
8
+ if (source.type === "url") {
9
+ const url = new URL(source.url);
10
+ if (!["http:", "https:"].includes(url.protocol) || url.username || url.password)
11
+ throw new Error("Image URL must use HTTP(S) without credentials");
12
+ return { id, url: url.href };
13
+ }
14
+ return source.type === "base64" ? { id, mediaType: source.mediaType } : { id, fileId: source.fileId };
15
+ }
16
+ export function displayParts(content) {
17
+ return content.flatMap(part => {
18
+ if (part.type === "reasoning")
19
+ return [];
20
+ if (part.type === "image")
21
+ return [{ type: "image", image: imageAttachment(part.source) }];
22
+ if (part.type === "text")
23
+ return [{ type: "text", text: part.text }];
24
+ return [{ type: "text", text: `[${part.type}]` }];
25
+ });
26
+ }
27
+ export async function inspectImage(data) {
28
+ if (!data.byteLength || data.byteLength > MAX_IMAGE_BYTES)
29
+ throw new Error("Image size must be between 1 byte and 32 MiB");
30
+ const { default: sharp } = await import("sharp");
31
+ const decoder = sharp(data, { limitInputPixels: 40_000_000, failOn: "error" });
32
+ const metadata = await decoder.metadata();
33
+ const formats = { png: "image/png", jpeg: "image/jpeg", webp: "image/webp", gif: "image/gif", avif: "image/avif" };
34
+ const mediaType = metadata.format === "heif" && metadata.compression === "av1" ? "image/avif" : formats[metadata.format ?? ""];
35
+ if (!mediaType || !metadata.width || !metadata.height)
36
+ throw new Error("Unsupported raster image format");
37
+ await decoder.stats();
38
+ return { data, mediaType, width: metadata.autoOrient.width, height: metadata.autoOrient.height };
39
+ }
40
+ export const readEmbeddedImage = async (source) => {
41
+ if (source.type !== "base64")
42
+ throw new Error(`Image source ${source.type} requires a host-provided MediaReader`);
43
+ if (source.data.length > Math.ceil(MAX_IMAGE_BYTES / 3) * 4)
44
+ throw new Error("Image exceeds 32 MiB");
45
+ const data = Buffer.from(source.data, "base64");
46
+ if (data.toString("base64") !== source.data)
47
+ throw new Error("Invalid image base64");
48
+ const image = await inspectImage(data);
49
+ if (image.mediaType !== source.mediaType)
50
+ throw new Error("Image MIME type does not match its contents");
51
+ return image;
52
+ };
53
+ export class FileMediaStore {
54
+ directory;
55
+ read;
56
+ constructor(directory, read = readEmbeddedImage) {
57
+ this.directory = directory;
58
+ this.read = read;
59
+ }
60
+ async save(source, signal) {
61
+ const supplied = await this.read(source, signal);
62
+ const image = await inspectImage(supplied.data);
63
+ if (image.mediaType !== supplied.mediaType)
64
+ throw new Error("MediaReader returned a mismatched MIME type");
65
+ const id = imageAttachment(source).id;
66
+ const extension = image.mediaType === "image/jpeg" ? "jpg" : image.mediaType.slice(6);
67
+ const path = join(this.directory, `${id}.${extension}`);
68
+ await mkdir(this.directory, { recursive: true, mode: 0o700 });
69
+ const temporary = join(this.directory, `${id}.${randomUUID()}.partial`);
70
+ const file = await open(temporary, "wx", 0o600);
71
+ try {
72
+ await file.writeFile(image.data);
73
+ await file.sync();
74
+ }
75
+ finally {
76
+ await file.close();
77
+ }
78
+ try {
79
+ await withFileAccess(path, "exclusive", () => rename(temporary, path));
80
+ }
81
+ finally {
82
+ await rm(temporary, { force: true });
83
+ }
84
+ return { ...image, id, path };
85
+ }
86
+ async verify(saved) {
87
+ return inspectImage(await withFileAccess(saved.path, "shared", () => readFile(saved.path)));
88
+ }
89
+ }
90
+ export async function imagePng(image) {
91
+ const { default: sharp } = await import("sharp");
92
+ return sharp(image.data, { limitInputPixels: 40_000_000, failOn: "error" }).rotate().png().toBuffer();
93
+ }
94
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "@sortedyuan/media",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.3.1",
4
+ "type": "module",
5
+ "description": "Reusable image attachments and file storage for May applications.",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "!dist/.tsbuildinfo"
15
+ ],
16
+ "dependencies": {
17
+ "@sortedyuan/core": "0.2.0",
18
+ "@sortedyuan/session": "0.4.0",
19
+ "sharp": "^0.34.5"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.0.0"
23
+ },
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
27
+ "license": "MIT",
28
+ "scripts": {
29
+ "build": "tsc -b",
30
+ "test": "pnpm run build && node --test test/*.test.mjs"
31
+ }
6
32
  }