@zlooks.cn/images-server 1.0.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.
Files changed (141) hide show
  1. package/dist/assets/provider.d.ts +3 -0
  2. package/dist/assets/provider.d.ts.map +1 -0
  3. package/dist/assets/provider.js +6 -0
  4. package/dist/assets/provider.js.map +1 -0
  5. package/dist/assets/read-image-asset.d.ts +5 -0
  6. package/dist/assets/read-image-asset.d.ts.map +1 -0
  7. package/dist/assets/read-image-asset.js +88 -0
  8. package/dist/assets/read-image-asset.js.map +1 -0
  9. package/dist/assets/response-policy.d.ts +6 -0
  10. package/dist/assets/response-policy.d.ts.map +1 -0
  11. package/dist/assets/response-policy.js +49 -0
  12. package/dist/assets/response-policy.js.map +1 -0
  13. package/dist/caches/public-image-cache.d.ts +18 -0
  14. package/dist/caches/public-image-cache.d.ts.map +1 -0
  15. package/dist/caches/public-image-cache.js +58 -0
  16. package/dist/caches/public-image-cache.js.map +1 -0
  17. package/dist/command/index.d.ts +3 -0
  18. package/dist/command/index.d.ts.map +1 -0
  19. package/dist/command/index.js +23 -0
  20. package/dist/command/index.js.map +1 -0
  21. package/dist/domain/image-error.d.ts +5 -0
  22. package/dist/domain/image-error.d.ts.map +1 -0
  23. package/dist/domain/image-error.js +9 -0
  24. package/dist/domain/image-error.js.map +1 -0
  25. package/dist/domain/list-cursor.d.ts +10 -0
  26. package/dist/domain/list-cursor.d.ts.map +1 -0
  27. package/dist/domain/list-cursor.js +31 -0
  28. package/dist/domain/list-cursor.js.map +1 -0
  29. package/dist/domain/output-schema.d.ts +63 -0
  30. package/dist/domain/output-schema.d.ts.map +1 -0
  31. package/dist/domain/output-schema.js +25 -0
  32. package/dist/domain/output-schema.js.map +1 -0
  33. package/dist/domain/schema.d.ts +69 -0
  34. package/dist/domain/schema.d.ts.map +1 -0
  35. package/dist/domain/schema.js +44 -0
  36. package/dist/domain/schema.js.map +1 -0
  37. package/dist/identity.d.ts +3 -0
  38. package/dist/identity.d.ts.map +1 -0
  39. package/dist/identity.js +3 -0
  40. package/dist/identity.js.map +1 -0
  41. package/dist/mcp/provider.d.ts +2 -0
  42. package/dist/mcp/provider.d.ts.map +1 -0
  43. package/dist/mcp/provider.js +96 -0
  44. package/dist/mcp/provider.js.map +1 -0
  45. package/dist/messages/public-asset/read.msg.d.ts +3 -0
  46. package/dist/messages/public-asset/read.msg.d.ts.map +1 -0
  47. package/dist/messages/public-asset/read.msg.js +10 -0
  48. package/dist/messages/public-asset/read.msg.js.map +1 -0
  49. package/dist/migrations/index.d.ts +3 -0
  50. package/dist/migrations/index.d.ts.map +1 -0
  51. package/dist/migrations/index.js +3 -0
  52. package/dist/migrations/index.js.map +1 -0
  53. package/dist/models/delete-image.model.d.ts +21 -0
  54. package/dist/models/delete-image.model.d.ts.map +1 -0
  55. package/dist/models/delete-image.model.js +36 -0
  56. package/dist/models/delete-image.model.js.map +1 -0
  57. package/dist/models/list-image.model.d.ts +21 -0
  58. package/dist/models/list-image.model.d.ts.map +1 -0
  59. package/dist/models/list-image.model.js +15 -0
  60. package/dist/models/list-image.model.js.map +1 -0
  61. package/dist/models/read-image.model.d.ts +20 -0
  62. package/dist/models/read-image.model.d.ts.map +1 -0
  63. package/dist/models/read-image.model.js +15 -0
  64. package/dist/models/read-image.model.js.map +1 -0
  65. package/dist/models/upload-image.model.d.ts +22 -0
  66. package/dist/models/upload-image.model.d.ts.map +1 -0
  67. package/dist/models/upload-image.model.js +52 -0
  68. package/dist/models/upload-image.model.js.map +1 -0
  69. package/dist/persistence/entities.d.ts +22 -0
  70. package/dist/persistence/entities.d.ts.map +1 -0
  71. package/dist/persistence/entities.js +20 -0
  72. package/dist/persistence/entities.js.map +1 -0
  73. package/dist/persistence/image-query.d.ts +5 -0
  74. package/dist/persistence/image-query.d.ts.map +1 -0
  75. package/dist/persistence/image-query.js +44 -0
  76. package/dist/persistence/image-query.js.map +1 -0
  77. package/dist/persistence/image-store.d.ts +30 -0
  78. package/dist/persistence/image-store.d.ts.map +1 -0
  79. package/dist/persistence/image-store.js +63 -0
  80. package/dist/persistence/image-store.js.map +1 -0
  81. package/dist/presentation/image-projection.d.ts +24 -0
  82. package/dist/presentation/image-projection.d.ts.map +1 -0
  83. package/dist/presentation/image-projection.js +19 -0
  84. package/dist/presentation/image-projection.js.map +1 -0
  85. package/dist/runtime/recover-images.d.ts +5 -0
  86. package/dist/runtime/recover-images.d.ts.map +1 -0
  87. package/dist/runtime/recover-images.js +21 -0
  88. package/dist/runtime/recover-images.js.map +1 -0
  89. package/dist/services/application.service.d.ts +4 -0
  90. package/dist/services/application.service.d.ts.map +1 -0
  91. package/dist/services/application.service.js +22 -0
  92. package/dist/services/application.service.js.map +1 -0
  93. package/dist/services/config.service.d.ts +25 -0
  94. package/dist/services/config.service.d.ts.map +1 -0
  95. package/dist/services/config.service.js +19 -0
  96. package/dist/services/config.service.js.map +1 -0
  97. package/dist/services/database.service.d.ts +3 -0
  98. package/dist/services/database.service.d.ts.map +1 -0
  99. package/dist/services/database.service.js +23 -0
  100. package/dist/services/database.service.js.map +1 -0
  101. package/dist/services/images-runtime.service.d.ts +9 -0
  102. package/dist/services/images-runtime.service.d.ts.map +1 -0
  103. package/dist/services/images-runtime.service.js +16 -0
  104. package/dist/services/images-runtime.service.js.map +1 -0
  105. package/dist/services/images.boot.d.ts +3 -0
  106. package/dist/services/images.boot.d.ts.map +1 -0
  107. package/dist/services/images.boot.js +8 -0
  108. package/dist/services/images.boot.js.map +1 -0
  109. package/dist/services/logger.service.d.ts +4 -0
  110. package/dist/services/logger.service.d.ts.map +1 -0
  111. package/dist/services/logger.service.js +8 -0
  112. package/dist/services/logger.service.js.map +1 -0
  113. package/dist/services/mcp-provider.service.d.ts +3 -0
  114. package/dist/services/mcp-provider.service.d.ts.map +1 -0
  115. package/dist/services/mcp-provider.service.js +15 -0
  116. package/dist/services/mcp-provider.service.js.map +1 -0
  117. package/dist/services/public-assets.service.d.ts +4 -0
  118. package/dist/services/public-assets.service.d.ts.map +1 -0
  119. package/dist/services/public-assets.service.js +15 -0
  120. package/dist/services/public-assets.service.js.map +1 -0
  121. package/dist/services/redis.service.d.ts +3 -0
  122. package/dist/services/redis.service.d.ts.map +1 -0
  123. package/dist/services/redis.service.js +35 -0
  124. package/dist/services/redis.service.js.map +1 -0
  125. package/dist/storage/image-path.d.ts +3 -0
  126. package/dist/storage/image-path.d.ts.map +1 -0
  127. package/dist/storage/image-path.js +17 -0
  128. package/dist/storage/image-path.js.map +1 -0
  129. package/dist/storage/inspect-image.d.ts +9 -0
  130. package/dist/storage/inspect-image.d.ts.map +1 -0
  131. package/dist/storage/inspect-image.js +36 -0
  132. package/dist/storage/inspect-image.js.map +1 -0
  133. package/dist/storage/local-storage.d.ts +10 -0
  134. package/dist/storage/local-storage.d.ts.map +1 -0
  135. package/dist/storage/local-storage.js +65 -0
  136. package/dist/storage/local-storage.js.map +1 -0
  137. package/dist/storage/read-upload-bytes.d.ts +3 -0
  138. package/dist/storage/read-upload-bytes.d.ts.map +1 -0
  139. package/dist/storage/read-upload-bytes.js +11 -0
  140. package/dist/storage/read-upload-bytes.js.map +1 -0
  141. package/package.json +69 -0
@@ -0,0 +1,3 @@
1
+ import type { AssetAnnouncement } from '@zlooks.cn/public-asset';
2
+ export declare const imageAssetProvider: Pick<AssetAnnouncement, 'providerId' | 'namespace' | 'prefix' | 'methods'>;
3
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/assets/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,eAAO,MAAM,kBAAkB,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAGzG,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { IMAGES_ID, IMAGES_NAMESPACE } from '../identity.js';
2
+ export const imageAssetProvider = {
3
+ providerId: IMAGES_ID, namespace: IMAGES_NAMESPACE,
4
+ prefix: '/media/images/', methods: ['GET', 'HEAD'],
5
+ };
6
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/assets/provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,MAAM,CAAC,MAAM,kBAAkB,GAA+E;IAC5G,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB;IAClD,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;CACnD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type AssetMetadata } from '@zlooks.cn/public-asset';
2
+ import type { ImageStore } from '../persistence/image-store.js';
3
+ import type { LocalImageStorage } from '../storage/local-storage.js';
4
+ export declare function readImageAsset(store: ImageStore, storage: LocalImageStorage, input: unknown, signal: AbortSignal): AsyncGenerator<AssetMetadata | Buffer>;
5
+ //# sourceMappingURL=read-image-asset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-image-asset.d.ts","sourceRoot":"","sources":["../../src/assets/read-image-asset.ts"],"names":[],"mappings":"AACA,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACpG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,wBAAuB,cAAc,CACnC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,WAAW,GAClB,cAAc,CAAC,aAAa,GAAG,MAAM,CAAC,CAsDxC"}
@@ -0,0 +1,88 @@
1
+ import rangeParser from 'range-parser';
2
+ import { ASSET_CHUNK_BYTES, assetRequestSchema } from '@zlooks.cn/public-asset';
3
+ import { imagePreconditionStatus, permitsImageRange, imageReadHeaders, emptyImageResponse } from './response-policy.js';
4
+ export async function* readImageAsset(store, storage, input, signal) {
5
+ signal.throwIfAborted();
6
+ const parsed = assetRequestSchema.safeParse(input);
7
+ if (!parsed.success) {
8
+ yield emptyImageResponse(400);
9
+ return;
10
+ }
11
+ const request = parsed.data;
12
+ const path = /^\/media\/images\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})\.(jpg|png|webp|gif|avif)$/.exec(request.path);
13
+ if (!path) {
14
+ yield emptyImageResponse(404);
15
+ return;
16
+ }
17
+ let row;
18
+ try {
19
+ row = await store.readAsset(path[1], signal);
20
+ }
21
+ catch {
22
+ signal.throwIfAborted();
23
+ yield emptyImageResponse(503);
24
+ return;
25
+ }
26
+ if (!row || row.extension !== path[2]) {
27
+ yield emptyImageResponse(404);
28
+ return;
29
+ }
30
+ const file = await storage.open(row.relativePath).catch(() => null);
31
+ if (!file) {
32
+ yield emptyImageResponse(503);
33
+ return;
34
+ }
35
+ try {
36
+ signal.throwIfAborted();
37
+ const stat = await file.stat();
38
+ if (!stat.isFile() || stat.size !== row.byteSize) {
39
+ yield emptyImageResponse(503);
40
+ return;
41
+ }
42
+ const etag = `"${row.sha256}"`;
43
+ const modified = new Date(row.modifiedAt);
44
+ const headers = imageReadHeaders(etag, modified);
45
+ const precondition = imagePreconditionStatus(request.headers, etag, modified);
46
+ if (precondition) {
47
+ yield precondition === 304 ? { status: 304, headers } : emptyImageResponse(precondition);
48
+ return;
49
+ }
50
+ let start = 0;
51
+ let end = row.byteSize - 1;
52
+ let partial = false;
53
+ if (request.method === 'GET' && request.headers.range && permitsImageRange(request.headers['if-range'], etag, modified)) {
54
+ const ranges = rangeParser(row.byteSize, request.headers.range);
55
+ if (typeof ranges === 'number' || ranges.type !== 'bytes' || ranges.length !== 1) {
56
+ const response = emptyImageResponse(416);
57
+ response.headers['content-range'] = `bytes */${row.byteSize}`;
58
+ yield response;
59
+ return;
60
+ }
61
+ ({ start, end } = ranges[0]);
62
+ partial = true;
63
+ }
64
+ yield {
65
+ status: partial ? 206 : 200,
66
+ headers: {
67
+ ...headers, 'content-length': String(end - start + 1), 'content-type': row.mediaType,
68
+ ...(partial ? { 'content-range': `bytes ${start}-${end}/${row.byteSize}` } : {}),
69
+ },
70
+ };
71
+ if (request.method === 'HEAD')
72
+ return;
73
+ const stream = file.createReadStream({ start, end, autoClose: false, highWaterMark: ASSET_CHUNK_BYTES, signal });
74
+ try {
75
+ for await (const chunk of stream) {
76
+ signal.throwIfAborted();
77
+ yield chunk;
78
+ }
79
+ }
80
+ finally {
81
+ stream.destroy();
82
+ }
83
+ }
84
+ finally {
85
+ await file.close();
86
+ }
87
+ }
88
+ //# sourceMappingURL=read-image-asset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-image-asset.js","sourceRoot":"","sources":["../../src/assets/read-image-asset.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { AssetMetadata, AssetRequest } from '@zlooks.cn/public-asset';
2
+ export declare function imageReadHeaders(etag: string, modified: Date): AssetMetadata['headers'];
3
+ export declare function emptyImageResponse(status: number): AssetMetadata;
4
+ export declare function imagePreconditionStatus(headers: AssetRequest['headers'], etag: string, modified: Date): 304 | 412 | undefined;
5
+ export declare function permitsImageRange(value: string | undefined, etag: string, modified: Date): boolean;
6
+ //# sourceMappingURL=response-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-policy.d.ts","sourceRoot":"","sources":["../../src/assets/response-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE3E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,CAOvF;AACD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAEhE;AACD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,SAAS,CAS7H;AACD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,OAAO,CAIlG"}
@@ -0,0 +1,49 @@
1
+ export function imageReadHeaders(etag, modified) {
2
+ return {
3
+ etag, 'last-modified': modified.toUTCString(), 'accept-ranges': 'bytes',
4
+ 'cache-control': 'public, max-age=31536000, immutable',
5
+ 'content-disposition': 'inline', 'x-content-type-options': 'nosniff',
6
+ 'access-control-allow-origin': '*', 'cross-origin-resource-policy': 'cross-origin',
7
+ };
8
+ }
9
+ export function emptyImageResponse(status) {
10
+ return { status, headers: { 'content-length': '0', 'cache-control': 'no-store', 'access-control-allow-origin': '*' } };
11
+ }
12
+ export function imagePreconditionStatus(headers, etag, modified) {
13
+ const match = headers['if-match'];
14
+ if (match && !matchesTag(match, etag, false))
15
+ return 412;
16
+ if (!match && isOlder(headers['if-unmodified-since'], modified))
17
+ return 412;
18
+ const none = headers['if-none-match'];
19
+ if (none)
20
+ return matchesTag(none, etag, true) ? 304 : undefined;
21
+ const since = parseDate(headers['if-modified-since']);
22
+ if (since !== undefined && modifiedSeconds(modified) <= since)
23
+ return 304;
24
+ return undefined;
25
+ }
26
+ export function permitsImageRange(value, etag, modified) {
27
+ if (!value || value === etag)
28
+ return true;
29
+ const date = parseDate(value);
30
+ return date !== undefined && date >= modifiedSeconds(modified);
31
+ }
32
+ function matchesTag(value, etag, weak) {
33
+ return value.split(',').some((item) => {
34
+ const tag = item.trim();
35
+ return tag === '*' || (weak ? tag.replace(/^W\//, '') : tag) === etag;
36
+ });
37
+ }
38
+ function parseDate(value) {
39
+ if (!value)
40
+ return undefined;
41
+ const time = Date.parse(value);
42
+ return Number.isFinite(time) ? Math.floor(time / 1000) : undefined;
43
+ }
44
+ function modifiedSeconds(modified) { return Math.floor(modified.getTime() / 1000); }
45
+ function isOlder(value, modified) {
46
+ const date = parseDate(value);
47
+ return date !== undefined && date < modifiedSeconds(modified);
48
+ }
49
+ //# sourceMappingURL=response-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-policy.js","sourceRoot":"","sources":["../../src/assets/response-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Redis } from 'ioredis';
2
+ import type { ImageRow } from '../persistence/entities.js';
3
+ export declare class PublicImageCache {
4
+ private readonly prefix;
5
+ private readonly locks;
6
+ private readonly entry;
7
+ constructor(redis: Redis, prefix: string, load: (id: string) => Promise<ImageRow>);
8
+ read(id: string, signal: AbortSignal): Promise<{
9
+ extension: "avif" | "gif" | "jpg" | "png" | "webp";
10
+ relativePath: string;
11
+ byteSize: number;
12
+ mediaType: "image/avif" | "image/gif" | "image/jpeg" | "image/png" | "image/webp";
13
+ sha256: string;
14
+ modifiedAt: number;
15
+ } | undefined>;
16
+ change<T>(id: string, mutation: () => Promise<T>, signal?: AbortSignal): Promise<T>;
17
+ }
18
+ //# sourceMappingURL=public-image-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-image-cache.d.ts","sourceRoot":"","sources":["../../src/caches/public-image-cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAe3D,qBAAa,gBAAgB;IAID,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IAEvB,YAAY,KAAK,EAAE,KAAK,EAAmB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,EAiBjG;IAEK,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;;;;;;;mBAKzC;IAEK,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAUxF;CACF"}
@@ -0,0 +1,58 @@
1
+ import { Cache, defineCache, RedisCache } from '@hile/cache';
2
+ import { RedisLock } from '@hile/redis-lock';
3
+ import { z } from 'zod';
4
+ import { ImageError } from '../domain/image-error.js';
5
+ import { validateImagePath } from '../storage/image-path.js';
6
+ import { IMAGE_MAX_BYTES, mediaTypeSchema } from '../domain/schema.js';
7
+ const imageAssetSchema = z.strictObject({
8
+ extension: z.enum(['jpg', 'png', 'webp', 'gif', 'avif']),
9
+ relativePath: z.string().transform(validateImagePath),
10
+ byteSize: z.number().int().positive().max(IMAGE_MAX_BYTES),
11
+ mediaType: mediaTypeSchema,
12
+ sha256: z.string().regex(/^[a-f0-9]{64}$/),
13
+ modifiedAt: z.number().int().min(0).max(8_640_000_000_000_000),
14
+ });
15
+ const lockOptions = { ttl: 30_000, wait: 5_000 };
16
+ export class PublicImageCache {
17
+ prefix;
18
+ locks;
19
+ entry;
20
+ constructor(redis, prefix, load) {
21
+ this.prefix = prefix;
22
+ this.locks = new RedisLock(redis, { renew: true });
23
+ const definition = defineCache('image:{id:string}', async ({ id }) => {
24
+ const row = await load(id).catch((error) => {
25
+ if (error instanceof ImageError && error.code === 'NOT_FOUND')
26
+ return undefined;
27
+ throw error;
28
+ });
29
+ if (!row || row.status !== 'ready' || !row.relativePath || !row.extension || !row.byteSize || !row.mediaType || !row.sha256) {
30
+ return new Cache(undefined);
31
+ }
32
+ const asset = imageAssetSchema.parse({
33
+ extension: row.extension, relativePath: row.relativePath, byteSize: row.byteSize,
34
+ mediaType: row.mediaType, sha256: row.sha256, modifiedAt: (row.readyAt ?? row.createdAt).getTime(),
35
+ });
36
+ return new Cache(asset).setExpire(300);
37
+ }, { singleflight: lockOptions, negative: { ttl: 5 } });
38
+ this.entry = new RedisCache(prefix, redis, { locks: this.locks }).loadCache(definition);
39
+ }
40
+ async read(id, signal) {
41
+ signal.throwIfAborted();
42
+ const asset = await (await this.entry).read({ id });
43
+ signal.throwIfAborted();
44
+ return asset === undefined ? undefined : imageAssetSchema.parse(asset);
45
+ }
46
+ async change(id, mutation, signal) {
47
+ signal?.throwIfAborted();
48
+ // Share @hile/cache 4.0.1's singleflight lock: an old fill must finish before invalidation.
49
+ return this.locks.withLock(`${this.prefix}image:${id}:lock`, lockOptions, async () => {
50
+ signal?.throwIfAborted();
51
+ // Invalidate before committing; a Redis failure must not leave changed DB state behind a live cache.
52
+ await (await this.entry).remove({ id });
53
+ signal?.throwIfAborted();
54
+ return mutation();
55
+ });
56
+ }
57
+ }
58
+ //# sourceMappingURL=public-image-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-image-cache.js","sourceRoot":"","sources":["../../src/caches/public-image-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEvE,MAAM,gBAAgB,GAAG,CAAC,CAAC,YAAY,CAAC;IACtC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACxD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,iBAAiB,CAAC;IACrD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC;IAC1D,SAAS,EAAE,eAAe;IAC1B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;IAC1C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,qBAAqB,CAAC;CAC/D,CAAC,CAAC;AACH,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAEjD,MAAM,OAAO,gBAAgB;IAIgB,MAAM;IAHhC,KAAK,CAAY;IACjB,KAAK,CAAC;IAEvB,YAAY,KAAY,EAAmB,MAAc,EAAE,IAAuC;sBAAvD,MAAM;QAC/C,IAAI,CAAC,KAAK,GAAG,IAAI,SAAS,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,WAAW,CAAC,mBAAmB,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;YACnE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAClD,IAAI,KAAK,YAAY,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;oBAAE,OAAO,SAAS,CAAC;gBAChF,MAAM,KAAK,CAAC;YACd,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;gBAC5H,OAAO,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;YAC9B,CAAC;YACD,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC;gBACnC,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBAChF,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;aACnG,CAAC,CAAC;YACH,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC1F,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,MAAmB;QACxC,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,MAAM,CAAI,EAAU,EAAE,QAA0B,EAAE,MAAoB;QAC1E,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,4FAA4F;QAC5F,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE;YACnF,MAAM,EAAE,cAAc,EAAE,CAAC;YACzB,qGAAqG;YACrG,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACxC,MAAM,EAAE,cAAc,EAAE,CAAC;YACzB,OAAO,QAAQ,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/command/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from 'node:url';
3
+ import { createRegistryDatabaseDataSource, registerDatabaseCommands } from '@zlooks.cn/database-command';
4
+ import { runServiceCommand } from '@zlooks.cn/service-command';
5
+ import { imagesMigrations } from '../migrations/index.js';
6
+ import { ImageEntity } from '../persistence/entities.js';
7
+ import { IMAGES_NAMESPACE } from '../identity.js';
8
+ await runServiceCommand({
9
+ packageRoot: fileURLToPath(new URL('../../', import.meta.url)),
10
+ requiresReactServer: false,
11
+ configure(program) {
12
+ registerDatabaseCommands(program, {
13
+ createDataSource: (envFile) => createRegistryDatabaseDataSource(envFile, {
14
+ commandNamespace: `${IMAGES_NAMESPACE}.db.command`, entities: [ImageEntity],
15
+ }),
16
+ migrations: imagesMigrations,
17
+ });
18
+ },
19
+ }).catch((error) => {
20
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
21
+ process.exitCode = 1;
22
+ });
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/command/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,gCAAgC,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACzG,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,iBAAiB,CAAC;IACtB,WAAW,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,mBAAmB,EAAE,KAAK;IAC1B,SAAS,CAAC,OAAO;QACf,wBAAwB,CAAC,OAAO,EAAE;YAChC,gBAAgB,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,gCAAgC,CAAC,OAAO,EAAE;gBACvE,gBAAgB,EAAE,GAAG,gBAAgB,aAAa,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC;aAC5E,CAAC;YACF,UAAU,EAAE,gBAAgB;SAC7B,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare class ImageError extends Error {
2
+ readonly code: string;
3
+ constructor(code: string, message: string);
4
+ }
5
+ //# sourceMappingURL=image-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-error.d.ts","sourceRoot":"","sources":["../../src/domain/image-error.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;aACP,IAAI,EAAE,MAAM;IAAxC,YAA4B,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAGxD;CACF"}
@@ -0,0 +1,9 @@
1
+ export class ImageError extends Error {
2
+ code;
3
+ constructor(code, message) {
4
+ super(message);
5
+ this.code = code;
6
+ this.name = 'ImageError';
7
+ }
8
+ }
9
+ //# sourceMappingURL=image-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-error.js","sourceRoot":"","sources":["../../src/domain/image-error.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAW,SAAQ,KAAK;IACP,IAAI;IAAhC,YAA4B,IAAY,EAAE,OAAe;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;oBADW,IAAI;QAE9B,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { ListImageInput } from './schema.js';
2
+ export declare function encodeCursor(filter: ListImageInput, row: {
3
+ id: string;
4
+ createdAt: Date;
5
+ }): string;
6
+ export declare function decodeCursor(filter: ListImageInput): {
7
+ id: string;
8
+ createdAt: Date;
9
+ } | undefined;
10
+ //# sourceMappingURL=list-cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-cursor.d.ts","sourceRoot":"","sources":["../../src/domain/list-cursor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAalD,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,CAAA;CAAE,GAAG,MAAM,CAGjG;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,CAAA;CAAE,GAAG,SAAS,CAUhG"}
@@ -0,0 +1,31 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { z } from 'zod';
3
+ import { ImageError } from './image-error.js';
4
+ const cursorSchema = z.strictObject({
5
+ filter: z.string().regex(/^[a-f0-9]{64}$/),
6
+ id: z.uuid(),
7
+ createdAt: z.iso.datetime(),
8
+ });
9
+ function filterFingerprint({ cursor: _cursor, limit: _limit, ...filter }) {
10
+ const entries = Object.entries(filter).sort(([left], [right]) => left.localeCompare(right));
11
+ return createHash('sha256').update(JSON.stringify(entries)).digest('hex');
12
+ }
13
+ export function encodeCursor(filter, row) {
14
+ const cursor = { filter: filterFingerprint(filter), id: row.id, createdAt: row.createdAt.toISOString() };
15
+ return Buffer.from(JSON.stringify(cursor)).toString('base64url');
16
+ }
17
+ export function decodeCursor(filter) {
18
+ if (!filter.cursor)
19
+ return;
20
+ try {
21
+ const decoded = JSON.parse(Buffer.from(filter.cursor, 'base64url').toString('utf8'));
22
+ const cursor = cursorSchema.parse(decoded);
23
+ if (cursor.filter !== filterFingerprint(filter))
24
+ throw new Error('Filter mismatch');
25
+ return { id: cursor.id, createdAt: new Date(cursor.createdAt) };
26
+ }
27
+ catch {
28
+ throw new ImageError('INVALID_CURSOR', '分页游标无效或查询条件已改变');
29
+ }
30
+ }
31
+ //# sourceMappingURL=list-cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-cursor.js","sourceRoot":"","sources":["../../src/domain/list-cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,MAAM,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;IAC1C,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;IACZ,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAEH,SAAS,iBAAiB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAkB;IACtF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5F,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAsB,EAAE,GAAoC;IACvF,MAAM,MAAM,GAAG,EAAE,MAAM,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;IACzG,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO;IAC3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,iBAAiB,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACpF,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { z } from 'zod';
2
+ /** Public metadata only; persistence paths, request fingerprints and credentials stay private. */
3
+ export declare const imageMetadataSchema: z.ZodObject<{
4
+ id: z.ZodUUID;
5
+ originalFilename: z.ZodNullable<z.ZodString>;
6
+ status: z.ZodEnum<{
7
+ deleted: "deleted";
8
+ deleting: "deleting";
9
+ failed: "failed";
10
+ ready: "ready";
11
+ uploading: "uploading";
12
+ }>;
13
+ url: z.ZodNullable<z.ZodURL>;
14
+ mediaType: z.ZodNullable<z.ZodEnum<{
15
+ "image/avif": "image/avif";
16
+ "image/gif": "image/gif";
17
+ "image/jpeg": "image/jpeg";
18
+ "image/png": "image/png";
19
+ "image/webp": "image/webp";
20
+ }>>;
21
+ byteSize: z.ZodNullable<z.ZodNumber>;
22
+ width: z.ZodNullable<z.ZodNumber>;
23
+ height: z.ZodNullable<z.ZodNumber>;
24
+ sha256: z.ZodNullable<z.ZodString>;
25
+ createdBy: z.ZodString;
26
+ createdAt: z.ZodISODateTime;
27
+ readyAt: z.ZodNullable<z.ZodISODateTime>;
28
+ deletedAt: z.ZodNullable<z.ZodISODateTime>;
29
+ failureCode: z.ZodNullable<z.ZodString>;
30
+ }, z.core.$strict>;
31
+ export declare const imagePageSchema: z.ZodObject<{
32
+ items: z.ZodArray<z.ZodObject<{
33
+ id: z.ZodUUID;
34
+ originalFilename: z.ZodNullable<z.ZodString>;
35
+ status: z.ZodEnum<{
36
+ deleted: "deleted";
37
+ deleting: "deleting";
38
+ failed: "failed";
39
+ ready: "ready";
40
+ uploading: "uploading";
41
+ }>;
42
+ url: z.ZodNullable<z.ZodURL>;
43
+ mediaType: z.ZodNullable<z.ZodEnum<{
44
+ "image/avif": "image/avif";
45
+ "image/gif": "image/gif";
46
+ "image/jpeg": "image/jpeg";
47
+ "image/png": "image/png";
48
+ "image/webp": "image/webp";
49
+ }>>;
50
+ byteSize: z.ZodNullable<z.ZodNumber>;
51
+ width: z.ZodNullable<z.ZodNumber>;
52
+ height: z.ZodNullable<z.ZodNumber>;
53
+ sha256: z.ZodNullable<z.ZodString>;
54
+ createdBy: z.ZodString;
55
+ createdAt: z.ZodISODateTime;
56
+ readyAt: z.ZodNullable<z.ZodISODateTime>;
57
+ deletedAt: z.ZodNullable<z.ZodISODateTime>;
58
+ failureCode: z.ZodNullable<z.ZodString>;
59
+ }, z.core.$strict>>;
60
+ hasMore: z.ZodBoolean;
61
+ nextCursor: z.ZodNullable<z.ZodString>;
62
+ }, z.core.$strict>;
63
+ //# sourceMappingURL=output-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-schema.d.ts","sourceRoot":"","sources":["../../src/domain/output-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,kGAAkG;AAClG,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAe9B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAI1B,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ import { IMAGE_MAX_BYTES, mediaTypeSchema, statusSchema } from './schema.js';
3
+ /** Public metadata only; persistence paths, request fingerprints and credentials stay private. */
4
+ export const imageMetadataSchema = z.strictObject({
5
+ id: z.uuid().describe('不可变图片 ID;用于 read-image、delete-image 和 images://image/{id}。'),
6
+ originalFilename: z.string().max(200).nullable().describe('上传时提供的原始文件名;未提供时为 null,仅作搜索元数据。'),
7
+ status: statusSchema.describe('uploading 上传中;ready 原图可读;failed 上传失败;deleting 原图已禁用、清理中;deleted 已删除。'),
8
+ url: z.url().nullable().describe('仅 ready 状态返回公开原图 URL,其余为 null。公开 GET/HEAD 无需身份或防盗链参数,缓存副本不能随删除撤销。'),
9
+ mediaType: mediaTypeSchema.nullable().describe('服务检测出的真实图片 MIME type;尚未完成检测时为 null。'),
10
+ byteSize: z.number().int().min(1).max(IMAGE_MAX_BYTES).nullable().describe('原始文件字节数;尚未完成检测时为 null,不是 Base64 字符数。'),
11
+ width: z.number().int().positive().nullable().describe('图片宽度,单位像素;尚未完成检测时为 null。'),
12
+ height: z.number().int().positive().nullable().describe('图片高度,单位像素;动画为单帧高度,尚未完成检测时为 null。'),
13
+ sha256: z.string().regex(/^[a-f0-9]{64}$/).nullable().describe('原始字节 SHA-256;删除时用作 expectedSha256,尚未完成检测时为 null。不表示跨图片去重。'),
14
+ createdBy: z.string().min(1).max(128).describe('创建图片的 MCP clientId,缺失时为 subject。'),
15
+ createdAt: z.iso.datetime().describe('数据库记录创建时间,UTC ISO-8601;list-image 时间筛选基于此字段。'),
16
+ readyAt: z.iso.datetime().nullable().describe('原图持久化并提交 ready 的 UTC 时间;未就绪时为 null,删除后保留。'),
17
+ deletedAt: z.iso.datetime().nullable().describe('完成删除的 UTC 时间;未完成时为 null,重复删除保留首次时间。'),
18
+ failureCode: z.string().max(64).nullable().describe('上传失败或启动恢复记录的安全错误码;无失败时为 null,不含底层异常或本地路径。'),
19
+ });
20
+ export const imagePageSchema = z.strictObject({
21
+ items: z.array(imageMetadataSchema).max(100).describe('当前页图片元数据;空结果为 [],不返回图片字节、本地路径或上传幂等键。'),
22
+ hasMore: z.boolean().describe('是否存在下一页;false 时停止翻页。分页不是跨请求的数据库快照。'),
23
+ nextCursor: z.string().min(1).max(2048).nullable().describe('下一页续查值:保持筛选及排序,将此值作为 cursor;hasMore=false 时为 null。'),
24
+ });
25
+ //# sourceMappingURL=output-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-schema.js","sourceRoot":"","sources":["../../src/domain/output-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7E,kGAAkG;AAClG,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,YAAY,CAAC;IAChD,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;IACnF,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;IAC5F,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,sEAAsE,CAAC;IACrG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;IACrG,SAAS,EAAE,eAAe,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IACrF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;IAClH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;IAClF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAC3F,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;IAC3H,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAClF,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;IACpF,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;IAC1F,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IACtF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;CACjG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,YAAY,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;IAC7F,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;IACnE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;CAClH,CAAC,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { z } from 'zod';
2
+ export declare const IMAGE_MAX_BYTES: number;
3
+ export declare const BASE64_MAX_BYTES: number;
4
+ export declare const mediaTypeSchema: z.ZodEnum<{
5
+ "image/avif": "image/avif";
6
+ "image/gif": "image/gif";
7
+ "image/jpeg": "image/jpeg";
8
+ "image/png": "image/png";
9
+ "image/webp": "image/webp";
10
+ }>;
11
+ export declare const statusSchema: z.ZodEnum<{
12
+ deleted: "deleted";
13
+ deleting: "deleting";
14
+ failed: "failed";
15
+ ready: "ready";
16
+ uploading: "uploading";
17
+ }>;
18
+ export declare const uploadImageSchema: z.ZodObject<{
19
+ idempotencyKey: z.ZodString;
20
+ filename: z.ZodOptional<z.ZodString>;
21
+ source: z.ZodLiteral<"base64">;
22
+ base64: z.ZodString;
23
+ }, z.core.$strict>;
24
+ export declare const readImageSchema: z.ZodObject<{
25
+ id: z.ZodUUID;
26
+ }, z.core.$strict>;
27
+ export declare const deleteImageSchema: z.ZodObject<{
28
+ id: z.ZodUUID;
29
+ expectedSha256: z.ZodString;
30
+ }, z.core.$strict>;
31
+ export declare const listImageSchema: z.ZodObject<{
32
+ createdFrom: z.ZodOptional<z.ZodPipe<z.ZodISODateTime, z.ZodTransform<string, string>>>;
33
+ createdTo: z.ZodOptional<z.ZodPipe<z.ZodISODateTime, z.ZodTransform<string, string>>>;
34
+ mediaTypes: z.ZodOptional<z.ZodPipe<z.ZodArray<z.ZodEnum<{
35
+ "image/avif": "image/avif";
36
+ "image/gif": "image/gif";
37
+ "image/jpeg": "image/jpeg";
38
+ "image/png": "image/png";
39
+ "image/webp": "image/webp";
40
+ }>>, z.ZodTransform<("image/avif" | "image/gif" | "image/jpeg" | "image/png" | "image/webp")[], ("image/avif" | "image/gif" | "image/jpeg" | "image/png" | "image/webp")[]>>>;
41
+ filenameContains: z.ZodOptional<z.ZodString>;
42
+ minBytes: z.ZodOptional<z.ZodNumber>;
43
+ maxBytes: z.ZodOptional<z.ZodNumber>;
44
+ minWidth: z.ZodOptional<z.ZodNumber>;
45
+ maxWidth: z.ZodOptional<z.ZodNumber>;
46
+ minHeight: z.ZodOptional<z.ZodNumber>;
47
+ maxHeight: z.ZodOptional<z.ZodNumber>;
48
+ statuses: z.ZodPipe<z.ZodDefault<z.ZodArray<z.ZodEnum<{
49
+ deleted: "deleted";
50
+ deleting: "deleting";
51
+ failed: "failed";
52
+ ready: "ready";
53
+ uploading: "uploading";
54
+ }>>>, z.ZodTransform<("deleted" | "deleting" | "failed" | "ready" | "uploading")[], ("deleted" | "deleting" | "failed" | "ready" | "uploading")[]>>;
55
+ createdBy: z.ZodOptional<z.ZodString>;
56
+ sha256: z.ZodOptional<z.ZodString>;
57
+ order: z.ZodDefault<z.ZodEnum<{
58
+ asc: "asc";
59
+ desc: "desc";
60
+ }>>;
61
+ limit: z.ZodDefault<z.ZodNumber>;
62
+ cursor: z.ZodOptional<z.ZodString>;
63
+ }, z.core.$strict>;
64
+ export type ListImageInput = z.infer<typeof listImageSchema>;
65
+ export type ListImageRequest = z.input<typeof listImageSchema>;
66
+ export type ReadImageInput = z.infer<typeof readImageSchema>;
67
+ export type UploadImageInput = z.infer<typeof uploadImageSchema>;
68
+ export type DeleteImageInput = z.infer<typeof deleteImageSchema>;
69
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/domain/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe,QAAmB,CAAC;AAChD,eAAO,MAAM,gBAAgB,QAAkB,CAAC;AAChD,eAAO,MAAM,eAAe;;;;;;EAA+E,CAAC;AAC5G,eAAO,MAAM,YAAY;;;;;;EAAkE,CAAC;AAK5F,eAAO,MAAM,iBAAiB;;;;;kBAG5B,CAAC;AACH,eAAO,MAAM,eAAe;;kBAA+F,CAAC;AAC5H,eAAO,MAAM,iBAAiB;;;kBAA0K,CAAC;AAIzM,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsB1B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC7D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC/D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC7D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACjE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}