apimo.js 1.0.4 → 1.1.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/README.md +173 -191
- package/dist/core/api.d.ts +155 -131
- package/dist/core/api.js +124 -84
- package/dist/errors/index.d.ts +176 -0
- package/dist/errors/index.js +234 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/schemas/agency.d.ts +50 -359
- package/dist/schemas/common.d.ts +18 -111
- package/dist/schemas/internal.d.ts +2 -2
- package/dist/schemas/internal.js +4 -4
- package/dist/schemas/property.d.ts +250 -1373
- package/dist/services/storage/dummy.cache.js +5 -20
- package/dist/services/storage/filesystem.cache.js +41 -58
- package/dist/services/storage/memory.cache.js +31 -46
- package/package.json +11 -8
|
@@ -1,28 +1,13 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { CacheExpiredError } from './types';
|
|
11
2
|
export class DummyCache {
|
|
12
3
|
constructor() {
|
|
13
4
|
}
|
|
14
|
-
getEntries(_catalogName, _culture) {
|
|
15
|
-
|
|
16
|
-
throw new CacheExpiredError();
|
|
17
|
-
});
|
|
5
|
+
async getEntries(_catalogName, _culture) {
|
|
6
|
+
throw new CacheExpiredError();
|
|
18
7
|
}
|
|
19
|
-
setEntries(_catalogName, _culture, _entries) {
|
|
20
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
});
|
|
8
|
+
async setEntries(_catalogName, _culture, _entries) {
|
|
22
9
|
}
|
|
23
|
-
getEntry(_catalogName, _culture, _id) {
|
|
24
|
-
|
|
25
|
-
throw new CacheExpiredError();
|
|
26
|
-
});
|
|
10
|
+
async getEntry(_catalogName, _culture, _id) {
|
|
11
|
+
throw new CacheExpiredError();
|
|
27
12
|
}
|
|
28
13
|
}
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { mkdirSync } from 'node:fs';
|
|
11
2
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
12
3
|
import * as path from 'node:path';
|
|
@@ -20,59 +11,51 @@ export class FilesystemCache {
|
|
|
20
11
|
this.cacheExpirationMs = (_b = settings === null || settings === void 0 ? void 0 : settings.cacheExpirationMs) !== null && _b !== void 0 ? _b : MS_IN_ONE_WEEK;
|
|
21
12
|
mkdirSync(this.path, { recursive: true });
|
|
22
13
|
}
|
|
23
|
-
setEntries(catalogName, culture, entries) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
cache: formattedEntries,
|
|
33
|
-
});
|
|
34
|
-
return writeFile(filePath, dump);
|
|
14
|
+
async setEntries(catalogName, culture, entries) {
|
|
15
|
+
const filePath = this.getCacheFilePath(catalogName, culture);
|
|
16
|
+
const formattedEntries = Object.fromEntries(entries.map(({ id, name, name_plurial }) => [id.toString(), {
|
|
17
|
+
name,
|
|
18
|
+
namePlural: name_plurial,
|
|
19
|
+
}]));
|
|
20
|
+
const dump = JSON.stringify({
|
|
21
|
+
timestamp: Date.now(),
|
|
22
|
+
cache: formattedEntries,
|
|
35
23
|
});
|
|
24
|
+
return writeFile(filePath, dump);
|
|
36
25
|
}
|
|
37
|
-
readFileOrThrow(filePath) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
});
|
|
26
|
+
async readFileOrThrow(filePath) {
|
|
27
|
+
try {
|
|
28
|
+
return await readFile(filePath, 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
catch (_a) {
|
|
31
|
+
throw new CacheExpiredError();
|
|
32
|
+
}
|
|
46
33
|
}
|
|
47
|
-
getEntry(catalogName, culture, id) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return (_a = parsed.cache[id.toString()]) !== null && _a !== void 0 ? _a : null;
|
|
58
|
-
});
|
|
34
|
+
async getEntry(catalogName, culture, id) {
|
|
35
|
+
var _a;
|
|
36
|
+
const filePath = this.getCacheFilePath(catalogName, culture);
|
|
37
|
+
const data = await this.readFileOrThrow(filePath);
|
|
38
|
+
const parsed = JSON.parse(data);
|
|
39
|
+
const currentTimestamp = Date.now();
|
|
40
|
+
if (parsed.timestamp + this.cacheExpirationMs < currentTimestamp) {
|
|
41
|
+
throw new CacheExpiredError();
|
|
42
|
+
}
|
|
43
|
+
return (_a = parsed.cache[id.toString()]) !== null && _a !== void 0 ? _a : null;
|
|
59
44
|
}
|
|
60
|
-
getEntries(catalogName, culture) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
name_plurial: entry === null || entry === void 0 ? void 0 : entry.namePlural,
|
|
75
|
-
});
|
|
45
|
+
async getEntries(catalogName, culture) {
|
|
46
|
+
const filePath = this.getCacheFilePath(catalogName, culture);
|
|
47
|
+
const data = await this.readFileOrThrow(filePath);
|
|
48
|
+
const parsed = JSON.parse(data);
|
|
49
|
+
const currentTimestamp = Date.now();
|
|
50
|
+
if (parsed.timestamp + this.cacheExpirationMs < currentTimestamp) {
|
|
51
|
+
throw new CacheExpiredError();
|
|
52
|
+
}
|
|
53
|
+
return Object.entries(parsed.cache).map(([id, entry]) => {
|
|
54
|
+
var _a;
|
|
55
|
+
return ({
|
|
56
|
+
id: Number.parseInt(id, 10),
|
|
57
|
+
name: (_a = entry === null || entry === void 0 ? void 0 : entry.name) !== null && _a !== void 0 ? _a : 'missing',
|
|
58
|
+
name_plurial: entry === null || entry === void 0 ? void 0 : entry.namePlural,
|
|
76
59
|
});
|
|
77
60
|
});
|
|
78
61
|
}
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { CacheExpiredError } from './types';
|
|
11
2
|
const MS_IN_ONE_WEEK = 7 * 24 * 60 * 60 * 1000;
|
|
12
3
|
export class MemoryCache {
|
|
@@ -15,46 +6,40 @@ export class MemoryCache {
|
|
|
15
6
|
this.cacheExpirationMs = (_a = settings === null || settings === void 0 ? void 0 : settings.cacheExpirationMs) !== null && _a !== void 0 ? _a : MS_IN_ONE_WEEK;
|
|
16
7
|
this._MEMORY = new Map();
|
|
17
8
|
}
|
|
18
|
-
setEntries(catalogName, culture, entries) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
cache: memoryEntry,
|
|
27
|
-
});
|
|
9
|
+
async setEntries(catalogName, culture, entries) {
|
|
10
|
+
const memoryEntry = new Map(entries.map(({ id, name, name_plurial }) => [id, {
|
|
11
|
+
name,
|
|
12
|
+
namePlural: name_plurial,
|
|
13
|
+
}]));
|
|
14
|
+
this._MEMORY.set(this.getCacheKey(catalogName, culture), {
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
cache: memoryEntry,
|
|
28
17
|
});
|
|
29
18
|
}
|
|
30
|
-
getEntry(catalogName, culture, id) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return (_a = memoryEntry.cache.get(id)) !== null && _a !== void 0 ? _a : null;
|
|
41
|
-
});
|
|
19
|
+
async getEntry(catalogName, culture, id) {
|
|
20
|
+
var _a;
|
|
21
|
+
const memoryEntry = this._MEMORY.get(this.getCacheKey(catalogName, culture));
|
|
22
|
+
if (!memoryEntry) {
|
|
23
|
+
throw new CacheExpiredError();
|
|
24
|
+
}
|
|
25
|
+
if (memoryEntry.timestamp + this.cacheExpirationMs < Date.now()) {
|
|
26
|
+
throw new CacheExpiredError();
|
|
27
|
+
}
|
|
28
|
+
return (_a = memoryEntry.cache.get(id)) !== null && _a !== void 0 ? _a : null;
|
|
42
29
|
}
|
|
43
|
-
getEntries(catalogName, culture) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}));
|
|
57
|
-
});
|
|
30
|
+
async getEntries(catalogName, culture) {
|
|
31
|
+
const memoryEntry = this._MEMORY.get(this.getCacheKey(catalogName, culture));
|
|
32
|
+
if (!memoryEntry) {
|
|
33
|
+
throw new CacheExpiredError();
|
|
34
|
+
}
|
|
35
|
+
if (memoryEntry.timestamp + this.cacheExpirationMs < Date.now()) {
|
|
36
|
+
throw new CacheExpiredError();
|
|
37
|
+
}
|
|
38
|
+
return Array.from(memoryEntry.cache.entries()).map(([id, { name, namePlural }]) => ({
|
|
39
|
+
id,
|
|
40
|
+
name,
|
|
41
|
+
name_plurial: namePlural,
|
|
42
|
+
}));
|
|
58
43
|
}
|
|
59
44
|
getCacheKey(catalogName, culture) {
|
|
60
45
|
return `${catalogName}.${culture}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apimo.js",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A wrapper for the Apimo API with catalog caching for building custom Real Estate website using their technologies.",
|
|
5
5
|
"author": "Vitaly Lysen <vitaly@lysen.dev> (https://lysen.dev)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,22 +38,25 @@
|
|
|
38
38
|
"run": "node dist/index.js",
|
|
39
39
|
"test": "vitest run",
|
|
40
40
|
"test-coverage": "vitest run --coverage",
|
|
41
|
-
"lint": "eslint ."
|
|
41
|
+
"lint": "eslint . --fix",
|
|
42
|
+
"type-check": "tsc --noEmit",
|
|
43
|
+
"prepare": "husky"
|
|
42
44
|
},
|
|
43
45
|
"dependencies": {
|
|
44
46
|
"bottleneck": "^2.19.5",
|
|
45
47
|
"merge-anything": "^6.0.6",
|
|
46
|
-
"zod": "^3.
|
|
48
|
+
"zod": "^4.3.6"
|
|
47
49
|
},
|
|
48
50
|
"devDependencies": {
|
|
49
51
|
"@anatine/zod-mock": "^3.14.0",
|
|
50
|
-
"@antfu/eslint-config": "^
|
|
51
|
-
"@faker-js/faker": "^
|
|
52
|
-
"@types/node": "^
|
|
53
|
-
"@vitest/coverage-v8": "^
|
|
52
|
+
"@antfu/eslint-config": "^7.2.0",
|
|
53
|
+
"@faker-js/faker": "^10.2.0",
|
|
54
|
+
"@types/node": "^25.1.0",
|
|
55
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
54
56
|
"dotenv": "^17.2.1",
|
|
55
57
|
"eslint": "^9.32.0",
|
|
58
|
+
"husky": "^9.1.7",
|
|
56
59
|
"typescript": "^5.9.2",
|
|
57
|
-
"vitest": "^
|
|
60
|
+
"vitest": "^4.0.18"
|
|
58
61
|
}
|
|
59
62
|
}
|