docs-combiner 0.2.2 → 1.0.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.
Files changed (53) hide show
  1. package/dist/agentApi/agentControlClaim.js +26 -0
  2. package/dist/agentApi/approachMatrixView.js +19 -0
  3. package/dist/agentApi/capabilitiesMeta.js +78 -0
  4. package/dist/agentApi/catalogUrlPresets.js +26 -0
  5. package/dist/agentApi/constants.js +11 -0
  6. package/dist/agentApi/creativeSelections.js +25 -0
  7. package/dist/agentApi/escalation.js +221 -0
  8. package/dist/agentApi/generatedPairsGuard.js +85 -0
  9. package/dist/agentApi/httpHelpers.js +77 -0
  10. package/dist/agentApi/imagesReadiness.js +60 -0
  11. package/dist/agentApi/jobStatus.js +113 -0
  12. package/dist/agentApi/productImageDrive.js +39 -0
  13. package/dist/agentApi/regenerateImages.js +125 -0
  14. package/dist/agentApi/rendererTypes.js +3 -0
  15. package/dist/agentApi/routes.js +440 -0
  16. package/dist/agentApi/sessionSnapshot.js +82 -0
  17. package/dist/agentApi/sessionTypes.js +2 -0
  18. package/dist/agentApi/spec.js +1045 -0
  19. package/dist/agentApi/types.js +2 -0
  20. package/dist/agentApi/validation.js +32 -0
  21. package/dist/campaignsCsv.js +420 -0
  22. package/dist/contentPairs.js +62 -0
  23. package/dist/flexcardBalance.js +88 -0
  24. package/dist/integrations/driveApi.js +420 -0
  25. package/dist/integrations/httpTimeout.js +116 -0
  26. package/dist/integrations/openrouter.js +532 -0
  27. package/dist/main.js +830 -165
  28. package/dist/models.js +17 -0
  29. package/dist/offerSettings.js +19 -0
  30. package/dist/preload.js +28 -0
  31. package/dist/promptOverrides.js +437 -0
  32. package/dist/prompts.js +1243 -0
  33. package/dist/renderer.js +19 -19
  34. package/dist/renderer.js.LICENSE.txt +4 -0
  35. package/dist/renderer.js.map +1 -1
  36. package/dist/server/app.js +378 -0
  37. package/dist/server/auth.js +74 -0
  38. package/dist/server/contentJobs.js +367 -0
  39. package/dist/server/driveCatalog.js +122 -0
  40. package/dist/server/driveProxy.js +220 -0
  41. package/dist/server/flexcardMeta.js +29 -0
  42. package/dist/server/googleAuth.js +84 -0
  43. package/dist/server/imageAssets.js +87 -0
  44. package/dist/server/imageJobs.js +776 -0
  45. package/dist/server/index.js +38 -0
  46. package/dist/server/jobEvents.js +116 -0
  47. package/dist/server/jobs.js +358 -0
  48. package/dist/server/openRouterMeta.js +58 -0
  49. package/dist/server/spec.js +544 -0
  50. package/dist/server/storage.js +133 -0
  51. package/dist/server/telegram.js +53 -0
  52. package/dist/server/workspaceSnapshot.js +273 -0
  53. package/package.json +18 -4
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.proxyDriveList = proxyDriveList;
13
+ exports.proxyDriveMetadata = proxyDriveMetadata;
14
+ exports.proxyDriveDownload = proxyDriveDownload;
15
+ exports.proxyDriveCreateFolder = proxyDriveCreateFolder;
16
+ exports.proxyDriveMultipartUpload = proxyDriveMultipartUpload;
17
+ exports.proxyDriveMediaUpdate = proxyDriveMediaUpdate;
18
+ exports.proxyDriveDelete = proxyDriveDelete;
19
+ exports.proxyDrivePermission = proxyDrivePermission;
20
+ const driveApi_1 = require("../integrations/driveApi");
21
+ const httpTimeout_1 = require("../integrations/httpTimeout");
22
+ const googleAuth_1 = require("./googleAuth");
23
+ function isPlainObject(value) {
24
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
25
+ }
26
+ function badRequest(message) {
27
+ const err = new Error(message);
28
+ err.status = 400;
29
+ return err;
30
+ }
31
+ function responseJsonOrText(response) {
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ const text = yield response.text();
34
+ if (!text.trim())
35
+ return null;
36
+ try {
37
+ return JSON.parse(text);
38
+ }
39
+ catch (_a) {
40
+ return { text };
41
+ }
42
+ });
43
+ }
44
+ function normalizeBool(value) {
45
+ return value === true || value === 'true';
46
+ }
47
+ function normalizePart(raw) {
48
+ if (!isPlainObject(raw))
49
+ throw badRequest('Invalid multipart part.');
50
+ const name = typeof raw.name === 'string' ? raw.name.trim() : '';
51
+ if (!name)
52
+ throw badRequest('Multipart part name is required.');
53
+ return {
54
+ name,
55
+ filename: typeof raw.filename === 'string' && raw.filename.trim() ? raw.filename.trim() : undefined,
56
+ contentType: typeof raw.contentType === 'string' && raw.contentType.trim() ? raw.contentType.trim() : undefined,
57
+ text: typeof raw.text === 'string' ? raw.text : undefined,
58
+ base64: typeof raw.base64 === 'string' ? raw.base64 : undefined,
59
+ };
60
+ }
61
+ function buildFormData(parts) {
62
+ var _a;
63
+ const form = new FormData();
64
+ for (const part of parts) {
65
+ const bytes = part.base64 !== undefined
66
+ ? Buffer.from(part.base64, 'base64')
67
+ : Buffer.from((_a = part.text) !== null && _a !== void 0 ? _a : '', 'utf8');
68
+ const blob = new Blob([bytes], { type: part.contentType || 'application/octet-stream' });
69
+ if (part.filename)
70
+ form.append(part.name, blob, part.filename);
71
+ else
72
+ form.append(part.name, blob);
73
+ }
74
+ return form;
75
+ }
76
+ function proxyDriveList(store, body) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ if (!isPlainObject(body))
79
+ throw badRequest('JSON object payload is required.');
80
+ const q = typeof body.q === 'string' ? body.q : '';
81
+ const fields = typeof body.fields === 'string' ? body.fields : '';
82
+ if (!q || !fields)
83
+ throw badRequest('q and fields are required.');
84
+ const supportsAllDrives = normalizeBool(body.supportsAllDrives);
85
+ const pageSize = Number(body.pageSize);
86
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
87
+ const response = yield (0, driveApi_1.driveListFiles)(token, q, fields, {
88
+ supportsAllDrives,
89
+ pageSize: Number.isFinite(pageSize) && pageSize > 0 ? pageSize : undefined,
90
+ });
91
+ return { status: response.status, value: yield responseJsonOrText(response) };
92
+ }));
93
+ });
94
+ }
95
+ function proxyDriveMetadata(store, fileId, query) {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ const cleanFileId = fileId.trim();
98
+ const fields = typeof query.fields === 'string' ? query.fields : '';
99
+ if (!cleanFileId || !fields)
100
+ throw badRequest('fileId and fields are required.');
101
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
102
+ const response = yield (0, driveApi_1.driveGetFileMetadata)(token, cleanFileId, fields, {
103
+ supportsAllDrives: normalizeBool(query.supportsAllDrives),
104
+ });
105
+ return { status: response.status, value: yield responseJsonOrText(response) };
106
+ }));
107
+ });
108
+ }
109
+ function proxyDriveDownload(store, fileId) {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ const cleanFileId = fileId.trim();
112
+ if (!cleanFileId)
113
+ throw badRequest('fileId is required.');
114
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
115
+ const response = yield (0, driveApi_1.driveDownloadFile)(token, cleanFileId);
116
+ const arrayBuffer = yield response.arrayBuffer();
117
+ return {
118
+ status: response.status,
119
+ value: {
120
+ contentType: response.headers.get('content-type') || 'application/octet-stream',
121
+ base64: Buffer.from(arrayBuffer).toString('base64'),
122
+ },
123
+ };
124
+ }));
125
+ });
126
+ }
127
+ function proxyDriveCreateFolder(store, body) {
128
+ return __awaiter(this, void 0, void 0, function* () {
129
+ if (!isPlainObject(body))
130
+ throw badRequest('JSON object payload is required.');
131
+ const folderName = typeof body.folderName === 'string' ? body.folderName.trim() : '';
132
+ const parentFolderId = typeof body.parentFolderId === 'string' ? body.parentFolderId.trim() : '';
133
+ if (!folderName || !parentFolderId)
134
+ throw badRequest('folderName and parentFolderId are required.');
135
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
136
+ const response = yield (0, driveApi_1.driveCreateFolderRequest)(token, folderName, parentFolderId);
137
+ return { status: response.status, value: yield responseJsonOrText(response) };
138
+ }));
139
+ });
140
+ }
141
+ function proxyDriveMultipartUpload(store, body) {
142
+ return __awaiter(this, void 0, void 0, function* () {
143
+ if (!isPlainObject(body))
144
+ throw badRequest('JSON object payload is required.');
145
+ const parts = Array.isArray(body.parts) ? body.parts.map(normalizePart) : [];
146
+ if (parts.length === 0)
147
+ throw badRequest('parts array is required.');
148
+ const existingFileId = typeof body.existingFileId === 'string' && body.existingFileId.trim()
149
+ ? body.existingFileId.trim()
150
+ : '';
151
+ const supportsAllDrives = normalizeBool(body.supportsAllDrives);
152
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
153
+ const suffix = supportsAllDrives ? '&supportsAllDrives=true' : '';
154
+ const url = existingFileId
155
+ ? `${driveApi_1.DRIVE_UPLOAD_FILES_URL}/${encodeURIComponent(existingFileId)}?uploadType=multipart${suffix}`
156
+ : `${driveApi_1.DRIVE_UPLOAD_FILES_URL}?uploadType=multipart${suffix}`;
157
+ const response = yield (0, httpTimeout_1.fetchWithTimeout)(url, {
158
+ method: existingFileId ? 'PATCH' : 'POST',
159
+ headers: { Authorization: `Bearer ${token}` },
160
+ body: buildFormData(parts),
161
+ }, { timeoutMs: httpTimeout_1.UPLOAD_NETWORK_TIMEOUT_MS });
162
+ return { status: response.status, value: yield responseJsonOrText(response) };
163
+ }));
164
+ });
165
+ }
166
+ function proxyDriveMediaUpdate(store, fileId, body) {
167
+ return __awaiter(this, void 0, void 0, function* () {
168
+ if (!isPlainObject(body))
169
+ throw badRequest('JSON object payload is required.');
170
+ const cleanFileId = fileId.trim();
171
+ const contentType = typeof body.contentType === 'string' && body.contentType.trim()
172
+ ? body.contentType.trim()
173
+ : 'application/octet-stream';
174
+ const fields = typeof body.fields === 'string' && body.fields.trim() ? body.fields.trim() : '';
175
+ const bytes = typeof body.base64 === 'string'
176
+ ? Buffer.from(body.base64, 'base64')
177
+ : Buffer.from(typeof body.text === 'string' ? body.text : '', 'utf8');
178
+ if (!cleanFileId)
179
+ throw badRequest('fileId is required.');
180
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
181
+ const fieldsSuffix = fields ? `&fields=${encodeURIComponent(fields)}` : '';
182
+ const response = yield (0, httpTimeout_1.fetchWithTimeout)(`${driveApi_1.DRIVE_UPLOAD_FILES_URL}/${encodeURIComponent(cleanFileId)}?uploadType=media${fieldsSuffix}`, {
183
+ method: 'PATCH',
184
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': contentType },
185
+ body: bytes,
186
+ }, { timeoutMs: httpTimeout_1.UPLOAD_NETWORK_TIMEOUT_MS });
187
+ return { status: response.status, value: yield responseJsonOrText(response) };
188
+ }));
189
+ });
190
+ }
191
+ function proxyDriveDelete(store, fileId, query) {
192
+ return __awaiter(this, void 0, void 0, function* () {
193
+ const cleanFileId = fileId.trim();
194
+ if (!cleanFileId)
195
+ throw badRequest('fileId is required.');
196
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
197
+ const response = yield (0, driveApi_1.driveDeleteFileRequest)(token, cleanFileId, {
198
+ supportsAllDrives: normalizeBool(query.supportsAllDrives),
199
+ });
200
+ return { status: response.status, value: yield responseJsonOrText(response) };
201
+ }));
202
+ });
203
+ }
204
+ function proxyDrivePermission(store, fileId, body) {
205
+ return __awaiter(this, void 0, void 0, function* () {
206
+ if (!isPlainObject(body))
207
+ throw badRequest('JSON object payload is required.');
208
+ const cleanFileId = fileId.trim();
209
+ const role = typeof body.role === 'string' ? body.role.trim() : '';
210
+ const type = typeof body.type === 'string' ? body.type.trim() : '';
211
+ if (!cleanFileId || !role || !type)
212
+ throw badRequest('fileId, role and type are required.');
213
+ return (0, googleAuth_1.withGoogleAccessTokenRetry)(store, (token) => __awaiter(this, void 0, void 0, function* () {
214
+ const response = yield (0, driveApi_1.driveCreatePermissionRequest)(token, cleanFileId, { role, type }, {
215
+ supportsAllDrives: normalizeBool(body.supportsAllDrives),
216
+ });
217
+ return { status: response.status, value: yield responseJsonOrText(response) };
218
+ }));
219
+ });
220
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getFlexCardBalance = getFlexCardBalance;
13
+ const flexcardBalance_1 = require("../flexcardBalance");
14
+ function badRequest(message) {
15
+ const err = new Error(message);
16
+ err.status = 400;
17
+ return err;
18
+ }
19
+ function getFlexCardBalance(store) {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ var _a;
22
+ const config = yield store.readConfig();
23
+ const apiKey = (_a = config.flexcardApiKey) === null || _a === void 0 ? void 0 : _a.trim();
24
+ if (!apiKey)
25
+ throw badRequest('flexcardApiKey is not configured on the server.');
26
+ const usdTotal = yield (0, flexcardBalance_1.fetchFlexCardFinanceAccountsUsdTotal)(apiKey);
27
+ return { ok: true, usdTotal };
28
+ });
29
+ }
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.refreshServerGoogleAccessToken = refreshServerGoogleAccessToken;
13
+ exports.getServerGoogleAccessToken = getServerGoogleAccessToken;
14
+ exports.withGoogleAccessTokenRetry = withGoogleAccessTokenRetry;
15
+ const driveApi_1 = require("../integrations/driveApi");
16
+ function refreshServerGoogleAccessToken(store) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ var _a, _b, _c;
19
+ const config = yield store.readConfig();
20
+ const clientId = (_a = config.clientId) === null || _a === void 0 ? void 0 : _a.trim();
21
+ const clientSecret = (_b = config.clientSecret) === null || _b === void 0 ? void 0 : _b.trim();
22
+ const refreshToken = (_c = config.refreshToken) === null || _c === void 0 ? void 0 : _c.trim();
23
+ if (!clientId || !clientSecret || !refreshToken)
24
+ return null;
25
+ const response = yield (0, driveApi_1.googleOAuthTokenRequest)({
26
+ client_id: clientId,
27
+ client_secret: clientSecret,
28
+ refresh_token: refreshToken,
29
+ grant_type: 'refresh_token',
30
+ });
31
+ if (!response.ok) {
32
+ yield store.patchSecrets({ accessToken: '' });
33
+ return null;
34
+ }
35
+ const data = yield response.json();
36
+ const accessToken = typeof (data === null || data === void 0 ? void 0 : data.access_token) === 'string' ? data.access_token : '';
37
+ if (!accessToken) {
38
+ yield store.patchSecrets({ accessToken: '' });
39
+ return null;
40
+ }
41
+ yield store.patchSecrets({
42
+ accessToken,
43
+ refreshToken: typeof (data === null || data === void 0 ? void 0 : data.refresh_token) === 'string' && data.refresh_token ? data.refresh_token : refreshToken,
44
+ });
45
+ return accessToken;
46
+ });
47
+ }
48
+ function getServerGoogleAccessToken(store) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ var _a;
51
+ const config = yield store.readConfig();
52
+ const accessToken = (_a = config.accessToken) === null || _a === void 0 ? void 0 : _a.trim();
53
+ if (accessToken)
54
+ return accessToken;
55
+ return refreshServerGoogleAccessToken(store);
56
+ });
57
+ }
58
+ function withGoogleAccessTokenRetry(store, fn) {
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ const token = yield getServerGoogleAccessToken(store);
61
+ if (!token) {
62
+ const err = new Error('Google OAuth secrets are not configured on the server.');
63
+ err.status = 400;
64
+ throw err;
65
+ }
66
+ let first;
67
+ try {
68
+ first = yield fn(token);
69
+ }
70
+ catch (err) {
71
+ if ((err === null || err === void 0 ? void 0 : err.status) !== 401)
72
+ throw err;
73
+ first = { status: 401, value: undefined };
74
+ }
75
+ if (first.status !== 401) {
76
+ return first;
77
+ }
78
+ const refreshed = yield refreshServerGoogleAccessToken(store);
79
+ if (!refreshed) {
80
+ throw new Error('Google access token expired and refresh failed. Run Google login and sync secrets to the VPS.');
81
+ }
82
+ return fn(refreshed);
83
+ });
84
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultServerImageAssetStore = exports.ServerImageAssetStore = void 0;
4
+ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
5
+ const DEFAULT_MAX_ASSETS = 5000;
6
+ const DEFAULT_MAX_BYTES = 1024 * 1024 * 1024;
7
+ function randomAssetId() {
8
+ return `asset_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 12)}`;
9
+ }
10
+ class ServerImageAssetStore {
11
+ constructor(options = {}) {
12
+ var _a, _b, _c, _d, _e;
13
+ this.assets = new Map();
14
+ this.totalBytes = 0;
15
+ this.ttlMs = (_a = options.ttlMs) !== null && _a !== void 0 ? _a : DEFAULT_TTL_MS;
16
+ this.maxAssets = (_b = options.maxAssets) !== null && _b !== void 0 ? _b : DEFAULT_MAX_ASSETS;
17
+ this.maxBytes = (_c = options.maxBytes) !== null && _c !== void 0 ? _c : DEFAULT_MAX_BYTES;
18
+ this.now = (_d = options.now) !== null && _d !== void 0 ? _d : (() => new Date());
19
+ this.idFactory = (_e = options.idFactory) !== null && _e !== void 0 ? _e : randomAssetId;
20
+ }
21
+ put(imageDataUrl, metadata = {}) {
22
+ this.cleanupExpired();
23
+ const now = this.now();
24
+ const bytes = Buffer.byteLength(imageDataUrl, 'utf8');
25
+ const asset = {
26
+ id: this.idFactory(),
27
+ imageDataUrl,
28
+ bytes,
29
+ createdAt: now.toISOString(),
30
+ lastAccessedAt: now.toISOString(),
31
+ expiresAt: new Date(now.getTime() + this.ttlMs).toISOString(),
32
+ metadata,
33
+ };
34
+ this.delete(asset.id);
35
+ this.assets.set(asset.id, asset);
36
+ this.totalBytes += bytes;
37
+ this.enforceLimits();
38
+ return asset;
39
+ }
40
+ get(assetId) {
41
+ this.cleanupExpired();
42
+ const asset = this.assets.get(assetId);
43
+ if (!asset)
44
+ return null;
45
+ const now = this.now();
46
+ asset.lastAccessedAt = now.toISOString();
47
+ asset.expiresAt = new Date(now.getTime() + this.ttlMs).toISOString();
48
+ return Object.assign(Object.assign({}, asset), { metadata: Object.assign({}, asset.metadata) });
49
+ }
50
+ delete(assetId) {
51
+ const asset = this.assets.get(assetId);
52
+ if (!asset)
53
+ return false;
54
+ this.assets.delete(assetId);
55
+ this.totalBytes -= asset.bytes;
56
+ return true;
57
+ }
58
+ stats() {
59
+ this.cleanupExpired();
60
+ return {
61
+ count: this.assets.size,
62
+ bytes: this.totalBytes,
63
+ maxAssets: this.maxAssets,
64
+ maxBytes: this.maxBytes,
65
+ ttlMs: this.ttlMs,
66
+ };
67
+ }
68
+ cleanupExpired() {
69
+ const nowMs = this.now().getTime();
70
+ for (const [assetId, asset] of this.assets.entries()) {
71
+ if (new Date(asset.expiresAt).getTime() <= nowMs) {
72
+ this.assets.delete(assetId);
73
+ this.totalBytes -= asset.bytes;
74
+ }
75
+ }
76
+ }
77
+ enforceLimits() {
78
+ while (this.assets.size > this.maxAssets || this.totalBytes > this.maxBytes) {
79
+ const oldest = [...this.assets.values()].sort((a, b) => a.lastAccessedAt.localeCompare(b.lastAccessedAt) || a.createdAt.localeCompare(b.createdAt))[0];
80
+ if (!oldest)
81
+ return;
82
+ this.delete(oldest.id);
83
+ }
84
+ }
85
+ }
86
+ exports.ServerImageAssetStore = ServerImageAssetStore;
87
+ exports.defaultServerImageAssetStore = new ServerImageAssetStore();