@effected/images 0.4.0 → 0.6.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/ImageBackend.js +6 -2
- package/ImageBackendError.js +15 -3
- package/ImageCache.js +1 -2
- package/ImageCacheKey.js +1 -2
- package/ImageCacheKeyError.js +1 -2
- package/ImageFacts.js +1 -2
- package/ImageFormat.js +1 -2
- package/ImageGenerateError.js +1 -2
- package/ImageParseError.js +1 -2
- package/README.md +1 -1
- package/cache.d.ts +13 -12
- package/index.d.ts +0 -6
- package/internal/avif.js +1 -2
- package/internal/bytes.js +1 -2
- package/internal/canonical.js +1 -2
- package/internal/detect.js +1 -2
- package/internal/digest.js +1 -2
- package/internal/gif.js +1 -2
- package/internal/jpeg.js +1 -2
- package/internal/png.js +1 -2
- package/internal/result.js +1 -2
- package/internal/webp.js +1 -2
- package/package.json +1 -1
package/ImageBackend.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ImageBackendError } from "./ImageBackendError.js";
|
|
|
3
3
|
import { DIGEST_PATTERN } from "./internal/digest.js";
|
|
4
4
|
import { Context, Effect, FileSystem, Layer, Option, Path, Random } from "effect";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// src/ImageBackend.ts
|
|
7
7
|
/** `[extension, media type]` pairs, in the fixed order `get` probes them, from the package's one extension table. */
|
|
8
8
|
const FILES = Object.entries(EXTENSIONS).map(([format, ext]) => [ext, MIME_TYPES[format]]);
|
|
9
9
|
/** Media type to extension. Read only through `Object.hasOwn`: a content type is caller input. */
|
|
@@ -50,6 +50,7 @@ var ImageBackend = class ImageBackend extends Context.Service()("@effected/image
|
|
|
50
50
|
for (const [ext, contentType] of FILES) {
|
|
51
51
|
const bytes = yield* fs.readFile(fileFor(key, ext)).pipe(Effect.map(Option.some), Effect.catchReason("PlatformError", "NotFound", () => Effect.succeedNone), Effect.mapError((cause) => new ImageBackendError({
|
|
52
52
|
operation: "get",
|
|
53
|
+
reason: "backend",
|
|
53
54
|
key,
|
|
54
55
|
cause
|
|
55
56
|
})));
|
|
@@ -65,6 +66,7 @@ var ImageBackend = class ImageBackend extends Context.Service()("@effected/image
|
|
|
65
66
|
const ext = params.contentType !== void 0 && Object.hasOwn(EXTENSION_BY_TYPE, params.contentType) ? EXTENSION_BY_TYPE[params.contentType] : void 0;
|
|
66
67
|
if (ext === void 0) return yield* new ImageBackendError({
|
|
67
68
|
operation: "set",
|
|
69
|
+
reason: "unsupported-content-type",
|
|
68
70
|
key: params.key,
|
|
69
71
|
cause: /* @__PURE__ */ new Error(`unsupported content type ${JSON.stringify(params.contentType ?? null)}`)
|
|
70
72
|
});
|
|
@@ -78,6 +80,7 @@ var ImageBackend = class ImageBackend extends Context.Service()("@effected/image
|
|
|
78
80
|
yield* fs.rename(temp, target);
|
|
79
81
|
}).pipe(Effect.onError(() => fs.remove(temp, { force: true }).pipe(Effect.ignore)), Effect.mapError((cause) => new ImageBackendError({
|
|
80
82
|
operation: "set",
|
|
83
|
+
reason: "backend",
|
|
81
84
|
key: params.key,
|
|
82
85
|
cause
|
|
83
86
|
})));
|
|
@@ -101,11 +104,13 @@ var ImageBackend = class ImageBackend extends Context.Service()("@effected/image
|
|
|
101
104
|
contentType: entry.contentType
|
|
102
105
|
}))), Effect.mapError((cause) => new ImageBackendError({
|
|
103
106
|
operation: "get",
|
|
107
|
+
reason: "backend",
|
|
104
108
|
key: k,
|
|
105
109
|
cause
|
|
106
110
|
})), Effect.withSpan("ImageBackend.get")),
|
|
107
111
|
set: (params) => source.set(params).pipe(Effect.mapError((cause) => new ImageBackendError({
|
|
108
112
|
operation: "set",
|
|
113
|
+
reason: "backend",
|
|
109
114
|
key: params.key,
|
|
110
115
|
cause
|
|
111
116
|
})), Effect.withSpan("ImageBackend.set"))
|
|
@@ -113,5 +118,4 @@ var ImageBackend = class ImageBackend extends Context.Service()("@effected/image
|
|
|
113
118
|
}
|
|
114
119
|
};
|
|
115
120
|
|
|
116
|
-
//#endregion
|
|
117
121
|
export { ImageBackend };
|
package/ImageBackendError.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/ImageBackendError.ts
|
|
4
4
|
const causeMessage = (cause) => {
|
|
5
5
|
let current = cause;
|
|
6
6
|
for (let depth = 0; depth < 8 && current instanceof Error && current.cause instanceof Error; depth++) current = current.cause;
|
|
@@ -9,20 +9,32 @@ const causeMessage = (cause) => {
|
|
|
9
9
|
/**
|
|
10
10
|
* An image backend read or write failed.
|
|
11
11
|
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* `reason` says why, so a caller branches on a literal rather than reading
|
|
14
|
+
* the message: `backend` is a failure of the store underneath (the file
|
|
15
|
+
* system for `layerDirectory`, the adapted service for `layerFrom`), and
|
|
16
|
+
* `unsupported-content-type` is a `set` whose content type the directory
|
|
17
|
+
* backend has no file extension for. `backend` names the source rather than
|
|
18
|
+
* claiming file IO, because `layerFrom` wraps any source failure — a store
|
|
19
|
+
* `Cache` error included — under it.
|
|
20
|
+
*
|
|
21
|
+
* `reason` is required: a hand-written backend states which case it hit.
|
|
22
|
+
*
|
|
12
23
|
* @public
|
|
13
24
|
*/
|
|
14
25
|
var ImageBackendError = class extends Schema.TaggedError()("ImageBackendError", {
|
|
15
26
|
/** The backend operation that failed. */
|
|
16
27
|
operation: Schema.Literals(["get", "set"]),
|
|
28
|
+
/** Why it failed: the store underneath, or a content type the backend cannot store. */
|
|
29
|
+
reason: Schema.Literals(["backend", "unsupported-content-type"]),
|
|
17
30
|
/** The key involved. */
|
|
18
31
|
key: Schema.String,
|
|
19
32
|
/** The underlying failure, preserved structurally. */
|
|
20
33
|
cause: Schema.Defect()
|
|
21
34
|
}) {
|
|
22
35
|
get message() {
|
|
23
|
-
return `Image backend ${this.operation} failed for key "${this.key}": ${causeMessage(this.cause)}`;
|
|
36
|
+
return `Image backend ${this.operation} failed for key "${this.key}" (${this.reason}): ${causeMessage(this.cause)}`;
|
|
24
37
|
}
|
|
25
38
|
};
|
|
26
39
|
|
|
27
|
-
//#endregion
|
|
28
40
|
export { ImageBackendError };
|
package/ImageCache.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ImageBackend } from "./ImageBackend.js";
|
|
|
3
3
|
import { ImageGenerateError } from "./ImageGenerateError.js";
|
|
4
4
|
import { Context, Effect, Layer, Option, Result } from "effect";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// src/ImageCache.ts
|
|
7
7
|
/**
|
|
8
8
|
* True when `accept` admits the facts' format. With `accept` omitted the call's `F` is every format, so admitting
|
|
9
9
|
* everything is exactly the narrowing the guard claims.
|
|
@@ -66,5 +66,4 @@ var ImageCache = class ImageCache extends Context.Service()("@effected/images/Im
|
|
|
66
66
|
}));
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
//#endregion
|
|
70
69
|
export { ImageCache };
|
package/ImageCacheKey.js
CHANGED
|
@@ -4,7 +4,7 @@ import { canonicalJson } from "./internal/canonical.js";
|
|
|
4
4
|
import { Crypto, Effect, Result, Schema } from "effect";
|
|
5
5
|
import * as Hex from "effect/encoding/Hex";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// src/ImageCacheKey.ts
|
|
8
8
|
/**
|
|
9
9
|
* The identity of one generated image: a SHA-256 digest of the salt and the schema-encoded parameters.
|
|
10
10
|
*
|
|
@@ -52,5 +52,4 @@ var ImageCacheKey = class ImageCacheKey extends Schema.Class("ImageCacheKey")({
|
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
//#endregion
|
|
56
55
|
export { ImageCacheKey };
|
package/ImageCacheKeyError.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/ImageCacheKeyError.ts
|
|
4
4
|
/**
|
|
5
5
|
* Cache-key parameters that could not be turned into a key.
|
|
6
6
|
*
|
|
@@ -27,5 +27,4 @@ var ImageCacheKeyError = class extends Schema.TaggedError()("ImageCacheKeyError"
|
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
//#endregion
|
|
31
30
|
export { ImageCacheKeyError };
|
package/ImageFacts.js
CHANGED
|
@@ -8,7 +8,7 @@ import { readPng } from "./internal/png.js";
|
|
|
8
8
|
import { readWebp } from "./internal/webp.js";
|
|
9
9
|
import { Effect, Result, Schema } from "effect";
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
// src/ImageFacts.ts
|
|
12
12
|
const READERS = {
|
|
13
13
|
png: readPng,
|
|
14
14
|
jpeg: readJpeg,
|
|
@@ -74,5 +74,4 @@ var ImageFacts = class ImageFacts extends Schema.Class("ImageFacts")({
|
|
|
74
74
|
static fromBytes = Effect.fn("ImageFacts.fromBytes")((bytes) => Effect.fromResult(ImageFacts.fromBytesResult(bytes)));
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
//#endregion
|
|
78
77
|
export { ImageFacts };
|
package/ImageFormat.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/ImageFormat.ts
|
|
4
4
|
/**
|
|
5
5
|
* The image formats `@effected/images` reads.
|
|
6
6
|
*
|
|
@@ -51,5 +51,4 @@ const ImageMimeTypeSchema = Schema.Literals([
|
|
|
51
51
|
MIME_TYPES.avif
|
|
52
52
|
]);
|
|
53
53
|
|
|
54
|
-
//#endregion
|
|
55
54
|
export { EXTENSIONS, ImageFormat, ImageMimeTypeSchema, MIME_TYPES };
|
package/ImageGenerateError.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ImageFormat } from "./ImageFormat.js";
|
|
2
2
|
import { Schema } from "effect";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/ImageGenerateError.ts
|
|
5
5
|
/**
|
|
6
6
|
* A generator produced bytes the cache will not store.
|
|
7
7
|
*
|
|
@@ -30,5 +30,4 @@ var ImageGenerateError = class extends Schema.TaggedError()("ImageGenerateError"
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
//#endregion
|
|
34
33
|
export { ImageGenerateError };
|
package/ImageParseError.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ImageFormat } from "./ImageFormat.js";
|
|
2
2
|
import { Schema } from "effect";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/ImageParseError.ts
|
|
5
5
|
/**
|
|
6
6
|
* Bytes that could not be read as an image header.
|
|
7
7
|
*
|
|
@@ -31,5 +31,4 @@ var ImageParseError = class extends Schema.TaggedError()("ImageParseError", {
|
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
//#endregion
|
|
35
34
|
export { ImageParseError };
|
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ The directory backend stores `<directory>/<key>.<ext>` through a temp file and a
|
|
|
142
142
|
- `ImageFormat` — the literal union `png | jpeg | gif | webp | avif`.
|
|
143
143
|
- `ImageParseError` — the one parse failure, with a `reason` and, once a signature matched, the `format`.
|
|
144
144
|
- `ImageCacheKey` / `ImageCacheKeyError` — content-addressed keys from schema-encoded parameters; failure reasons `encode`, `non-json` and `digest`.
|
|
145
|
-
- `ImageBackend` / `ImageBackendError` — the storage port, a directory backend, a no-store backend and a structural adapter
|
|
145
|
+
- `ImageBackend` / `ImageBackendError` — the storage port, a directory backend, a no-store backend and a structural adapter; failure reasons `backend` and `unsupported-content-type`.
|
|
146
146
|
- `ImageCache` / `ImageGenerateError` — `getOrGenerate` with an optional `accept` format list that narrows the result's format.
|
|
147
147
|
|
|
148
148
|
SVG, BMP, ICO, TIFF, HEIC, JPEG XL, EXIF orientation, image transformation and cache eviction are out of scope.
|
package/cache.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Context, Crypto, Effect, FileSystem, Layer, Option, Path, Schema } from "effect";
|
|
2
2
|
import * as Images from "@effected/images";
|
|
3
|
-
//#region src/ImageBackendError.d.ts
|
|
4
3
|
declare const ImageBackendError_base: Schema.Class<ImageBackendError, Schema.TaggedStruct<"ImageBackendError", {
|
|
5
4
|
/** The backend operation that failed. */
|
|
6
5
|
readonly operation: Schema.Literals<readonly ["get", "set"]>;
|
|
6
|
+
/** Why it failed: the store underneath, or a content type the backend cannot store. */
|
|
7
|
+
readonly reason: Schema.Literals<readonly ["backend", "unsupported-content-type"]>;
|
|
7
8
|
/** The key involved. */
|
|
8
9
|
readonly key: Schema.String;
|
|
9
10
|
/** The underlying failure, preserved structurally. */
|
|
@@ -12,13 +13,22 @@ declare const ImageBackendError_base: Schema.Class<ImageBackendError, Schema.Tag
|
|
|
12
13
|
/**
|
|
13
14
|
* An image backend read or write failed.
|
|
14
15
|
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* `reason` says why, so a caller branches on a literal rather than reading
|
|
18
|
+
* the message: `backend` is a failure of the store underneath (the file
|
|
19
|
+
* system for `layerDirectory`, the adapted service for `layerFrom`), and
|
|
20
|
+
* `unsupported-content-type` is a `set` whose content type the directory
|
|
21
|
+
* backend has no file extension for. `backend` names the source rather than
|
|
22
|
+
* claiming file IO, because `layerFrom` wraps any source failure — a store
|
|
23
|
+
* `Cache` error included — under it.
|
|
24
|
+
*
|
|
25
|
+
* `reason` is required: a hand-written backend states which case it hit.
|
|
26
|
+
*
|
|
15
27
|
* @public
|
|
16
28
|
*/
|
|
17
29
|
export declare class ImageBackendError extends ImageBackendError_base {
|
|
18
30
|
get message(): string;
|
|
19
31
|
}
|
|
20
|
-
//#endregion
|
|
21
|
-
//#region src/ImageBackend.d.ts
|
|
22
32
|
/**
|
|
23
33
|
* Bytes and media type a backend holds for one key.
|
|
24
34
|
*
|
|
@@ -107,8 +117,6 @@ export declare class ImageBackend extends ImageBackend_base {
|
|
|
107
117
|
*/
|
|
108
118
|
static layerFrom<I>(key: Context.Key<I, ImageBackendSource>): Layer.Layer<ImageBackend, never, I>;
|
|
109
119
|
}
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region src/ImageCacheKeyError.d.ts
|
|
112
120
|
declare const ImageCacheKeyError_base: Schema.Class<ImageCacheKeyError, Schema.TaggedStruct<"ImageCacheKeyError", {
|
|
113
121
|
/** Which step failed. */
|
|
114
122
|
readonly reason: Schema.Literals<readonly ["encode", "non-json", "digest"]>;
|
|
@@ -129,8 +137,6 @@ declare const ImageCacheKeyError_base: Schema.Class<ImageCacheKeyError, Schema.T
|
|
|
129
137
|
export declare class ImageCacheKeyError extends ImageCacheKeyError_base {
|
|
130
138
|
get message(): string;
|
|
131
139
|
}
|
|
132
|
-
//#endregion
|
|
133
|
-
//#region src/ImageCacheKey.d.ts
|
|
134
140
|
/**
|
|
135
141
|
* Options for {@link ImageCacheKey.fromParams}.
|
|
136
142
|
*
|
|
@@ -166,8 +172,6 @@ export declare class ImageCacheKey extends ImageCacheKey_base {
|
|
|
166
172
|
*/
|
|
167
173
|
static fromParams<S extends Schema.ConstraintEncoder<unknown>>(schema: S, params: S["Type"], options: ImageCacheKeyOptions): Effect.Effect<ImageCacheKey, ImageCacheKeyError, Crypto.Crypto>;
|
|
168
174
|
}
|
|
169
|
-
//#endregion
|
|
170
|
-
//#region src/ImageGenerateError.d.ts
|
|
171
175
|
declare const ImageGenerateError_base: Schema.Class<ImageGenerateError, Schema.TaggedStruct<"ImageGenerateError", {
|
|
172
176
|
/** Why the output was refused. */
|
|
173
177
|
readonly reason: Schema.Literals<readonly ["empty", "unparseable", "rejected-format"]>;
|
|
@@ -190,8 +194,6 @@ declare const ImageGenerateError_base: Schema.Class<ImageGenerateError, Schema.T
|
|
|
190
194
|
export declare class ImageGenerateError extends ImageGenerateError_base {
|
|
191
195
|
get message(): string;
|
|
192
196
|
}
|
|
193
|
-
//#endregion
|
|
194
|
-
//#region src/ImageCache.d.ts
|
|
195
197
|
/**
|
|
196
198
|
* Options for {@link ImageCacheShape.getOrGenerate}.
|
|
197
199
|
*
|
|
@@ -252,6 +254,5 @@ export declare class ImageCache extends ImageCache_base {
|
|
|
252
254
|
/** The cache over whichever {@link ImageBackend} the app provides. */
|
|
253
255
|
static readonly layer: Layer.Layer<ImageCache, never, ImageBackend>;
|
|
254
256
|
}
|
|
255
|
-
//#endregion
|
|
256
257
|
export type { GetOrGenerateOptions, ImageBackendSetParams, ImageBackendShape, ImageBackendSource, ImageCacheKeyOptions, ImageCacheResult, ImageCacheShape, StoredImage };
|
|
257
258
|
//# sourceMappingURL=cache.d.ts.map
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Effect, Result, Schema } from "effect";
|
|
2
|
-
//#region src/ImageParseError.d.ts
|
|
3
2
|
declare const ImageParseError_base: Schema.Class<ImageParseError, Schema.TaggedStruct<"ImageParseError", {
|
|
4
3
|
/** Why the header could not be read. */
|
|
5
4
|
readonly reason: Schema.Literals<readonly ["unrecognized", "truncated", "malformed"]>;
|
|
@@ -22,8 +21,6 @@ declare const ImageParseError_base: Schema.Class<ImageParseError, Schema.TaggedS
|
|
|
22
21
|
export declare class ImageParseError extends ImageParseError_base {
|
|
23
22
|
get message(): string;
|
|
24
23
|
}
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region src/ImageFacts.d.ts
|
|
27
24
|
/**
|
|
28
25
|
* One of the five media types `ImageFacts.mimeType` holds, one per `ImageFormat`.
|
|
29
26
|
*
|
|
@@ -77,8 +74,6 @@ export declare class ImageFacts extends ImageFacts_base {
|
|
|
77
74
|
*/
|
|
78
75
|
static readonly fromBytes: (bytes: Uint8Array) => Effect.Effect<ImageFacts, ImageParseError>;
|
|
79
76
|
}
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/ImageFormat.d.ts
|
|
82
77
|
/**
|
|
83
78
|
* The image formats `@effected/images` reads.
|
|
84
79
|
*
|
|
@@ -91,6 +86,5 @@ export declare const ImageFormat: Schema.Literals<readonly ["png", "jpeg", "gif"
|
|
|
91
86
|
* @public
|
|
92
87
|
*/
|
|
93
88
|
export type ImageFormat = typeof ImageFormat.Type;
|
|
94
|
-
//#endregion
|
|
95
89
|
export type { ImageExtension, ImageMimeType };
|
|
96
90
|
//# sourceMappingURL=index.d.ts.map
|
package/internal/avif.js
CHANGED
|
@@ -2,7 +2,7 @@ import { ascii, u32be } from "./bytes.js";
|
|
|
2
2
|
import { dimensions, malformed, truncated } from "./result.js";
|
|
3
3
|
import { Result } from "effect";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// src/internal/avif.ts
|
|
6
6
|
/** Boxes the walk may visit before it gives up. Hostile input cannot loop past it. */
|
|
7
7
|
const AVIF_BOX_BUDGET = 1024;
|
|
8
8
|
/** Brands scanned in the ftyp box, at most. */
|
|
@@ -91,5 +91,4 @@ const readAvif = (b) => {
|
|
|
91
91
|
return best === void 0 ? malformed("no ispe property") : dimensions(best.width, best.height);
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
-
//#endregion
|
|
95
94
|
export { AVIF_BOX_BUDGET, isAvifBrand, readAvif };
|
package/internal/bytes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/internal/bytes.ts
|
|
2
2
|
const u16be = (b, o) => b[o] << 8 | b[o + 1];
|
|
3
3
|
const u16le = (b, o) => b[o] | b[o + 1] << 8;
|
|
4
4
|
const u24le = (b, o) => b[o] | b[o + 1] << 8 | b[o + 2] << 16;
|
|
@@ -10,5 +10,4 @@ const ascii = (b, o, length) => {
|
|
|
10
10
|
};
|
|
11
11
|
const matches = (b, o, signature) => b.length >= o + signature.length && signature.every((byte, i) => b[o + i] === byte);
|
|
12
12
|
|
|
13
|
-
//#endregion
|
|
14
13
|
export { ascii, matches, u16be, u16le, u24le, u32be };
|
package/internal/canonical.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Result } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/internal/canonical.ts
|
|
4
4
|
const MAX_DEPTH = 256;
|
|
5
5
|
const isPlainObject = (value) => {
|
|
6
6
|
const proto = Object.getPrototypeOf(value);
|
|
@@ -44,5 +44,4 @@ const encode = (value, depth) => {
|
|
|
44
44
|
*/
|
|
45
45
|
const canonicalJson = (value) => encode(value, 0);
|
|
46
46
|
|
|
47
|
-
//#endregion
|
|
48
47
|
export { canonicalJson };
|
package/internal/detect.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ascii, matches } from "./bytes.js";
|
|
2
2
|
import { isAvifBrand } from "./avif.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/internal/detect.ts
|
|
5
5
|
const PNG = [
|
|
6
6
|
137,
|
|
7
7
|
80,
|
|
@@ -27,5 +27,4 @@ const detectFormat = (b) => {
|
|
|
27
27
|
if (isAvifBrand(b)) return "avif";
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
//#endregion
|
|
31
30
|
export { detectFormat };
|
package/internal/digest.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// src/internal/digest.ts
|
|
2
2
|
/** A lowercase hex SHA-256 digest: the shape of every image cache key, and the only name a directory backend writes. */
|
|
3
3
|
const DIGEST_PATTERN = /^[0-9a-f]{64}$/u;
|
|
4
4
|
|
|
5
|
-
//#endregion
|
|
6
5
|
export { DIGEST_PATTERN };
|
package/internal/gif.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { u16le } from "./bytes.js";
|
|
2
2
|
import { dimensions, truncated } from "./result.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/internal/gif.ts
|
|
5
5
|
/** The logical screen descriptor follows the 6-byte signature: width(2 LE), height(2 LE). */
|
|
6
6
|
const readGif = (b) => b.length < 10 ? truncated(`need 10 bytes for the screen descriptor, have ${b.length}`) : dimensions(u16le(b, 6), u16le(b, 8));
|
|
7
7
|
|
|
8
|
-
//#endregion
|
|
9
8
|
export { readGif };
|
package/internal/jpeg.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { u16be } from "./bytes.js";
|
|
2
2
|
import { dimensions, malformed, truncated } from "./result.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/internal/jpeg.ts
|
|
5
5
|
/** Markers plus fill bytes the walk may consume before it gives up. Hostile input cannot loop past it. */
|
|
6
6
|
const JPEG_STEP_BUDGET = 4096;
|
|
7
7
|
/** SOFn frame headers: C0-CF except C4 (DHT), C8 (JPG) and CC (DAC). */
|
|
@@ -37,5 +37,4 @@ const readJpeg = (b) => {
|
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
//#endregion
|
|
41
40
|
export { JPEG_STEP_BUDGET, readJpeg };
|
package/internal/png.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ascii, u32be } from "./bytes.js";
|
|
2
2
|
import { dimensions, malformed, truncated } from "./result.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/internal/png.ts
|
|
5
5
|
/** IHDR is the first chunk: length(4)=13, type(4)="IHDR", width(4), height(4) after the 8-byte signature. */
|
|
6
6
|
const readPng = (b) => {
|
|
7
7
|
if (b.length < 24) return truncated(`need 24 bytes for IHDR dimensions, have ${b.length}`);
|
|
@@ -11,5 +11,4 @@ const readPng = (b) => {
|
|
|
11
11
|
return dimensions(u32be(b, 16), u32be(b, 20));
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
//#endregion
|
|
15
14
|
export { readPng };
|
package/internal/result.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Result } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/internal/result.ts
|
|
4
4
|
const MAX_DIMENSION = 2147483647;
|
|
5
5
|
const truncated = (detail) => Result.fail({
|
|
6
6
|
reason: "truncated",
|
|
@@ -17,5 +17,4 @@ const dimensions = (width, height) => legal(width) && legal(height) ? Result.suc
|
|
|
17
17
|
height
|
|
18
18
|
}) : malformed(`dimensions ${width}x${height} out of range 1..${MAX_DIMENSION}`);
|
|
19
19
|
|
|
20
|
-
//#endregion
|
|
21
20
|
export { MAX_DIMENSION, dimensions, malformed, truncated };
|
package/internal/webp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ascii, u16le, u24le } from "./bytes.js";
|
|
2
2
|
import { dimensions, malformed, truncated } from "./result.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// src/internal/webp.ts
|
|
5
5
|
const PAYLOAD = 20;
|
|
6
6
|
const readWebp = (b) => {
|
|
7
7
|
if (b.length < 16) return truncated("need the first chunk's fourcc");
|
|
@@ -29,5 +29,4 @@ const readWebp = (b) => {
|
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
//#endregion
|
|
33
32
|
export { readWebp };
|