@anby/platform-sdk 0.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/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/cjs/apps/publish.d.ts +73 -0
- package/dist/cjs/apps/publish.d.ts.map +1 -0
- package/dist/cjs/apps/publish.js +166 -0
- package/dist/cjs/apps/publish.js.map +1 -0
- package/dist/cjs/auth/index.d.ts +22 -0
- package/dist/cjs/auth/index.d.ts.map +1 -0
- package/dist/cjs/auth/index.js +101 -0
- package/dist/cjs/auth/index.js.map +1 -0
- package/dist/cjs/config/index.d.ts +8 -0
- package/dist/cjs/config/index.d.ts.map +1 -0
- package/dist/cjs/config/index.js +14 -0
- package/dist/cjs/config/index.js.map +1 -0
- package/dist/cjs/entities/cache.d.ts +31 -0
- package/dist/cjs/entities/cache.d.ts.map +1 -0
- package/dist/cjs/entities/cache.js +84 -0
- package/dist/cjs/entities/cache.js.map +1 -0
- package/dist/cjs/entities/client.d.ts +32 -0
- package/dist/cjs/entities/client.d.ts.map +1 -0
- package/dist/cjs/entities/client.js +130 -0
- package/dist/cjs/entities/client.js.map +1 -0
- package/dist/cjs/entities/errors.d.ts +35 -0
- package/dist/cjs/entities/errors.d.ts.map +1 -0
- package/dist/cjs/entities/errors.js +68 -0
- package/dist/cjs/entities/errors.js.map +1 -0
- package/dist/cjs/entities/handler.d.ts +89 -0
- package/dist/cjs/entities/handler.d.ts.map +1 -0
- package/dist/cjs/entities/handler.js +332 -0
- package/dist/cjs/entities/handler.js.map +1 -0
- package/dist/cjs/entities/identity.d.ts +90 -0
- package/dist/cjs/entities/identity.d.ts.map +1 -0
- package/dist/cjs/entities/identity.js +180 -0
- package/dist/cjs/entities/identity.js.map +1 -0
- package/dist/cjs/entities/index.d.ts +12 -0
- package/dist/cjs/entities/index.d.ts.map +1 -0
- package/dist/cjs/entities/index.js +64 -0
- package/dist/cjs/entities/index.js.map +1 -0
- package/dist/cjs/entities/redis.d.ts +128 -0
- package/dist/cjs/entities/redis.d.ts.map +1 -0
- package/dist/cjs/entities/redis.js +354 -0
- package/dist/cjs/entities/redis.js.map +1 -0
- package/dist/cjs/entities/resolver.d.ts +25 -0
- package/dist/cjs/entities/resolver.d.ts.map +1 -0
- package/dist/cjs/entities/resolver.js +128 -0
- package/dist/cjs/entities/resolver.js.map +1 -0
- package/dist/cjs/entities/schema.d.ts +15 -0
- package/dist/cjs/entities/schema.d.ts.map +1 -0
- package/dist/cjs/entities/schema.js +140 -0
- package/dist/cjs/entities/schema.js.map +1 -0
- package/dist/cjs/entities/scopedDb.d.ts +92 -0
- package/dist/cjs/entities/scopedDb.d.ts.map +1 -0
- package/dist/cjs/entities/scopedDb.js +96 -0
- package/dist/cjs/entities/scopedDb.js.map +1 -0
- package/dist/cjs/entities/token.d.ts +18 -0
- package/dist/cjs/entities/token.d.ts.map +1 -0
- package/dist/cjs/entities/token.js +87 -0
- package/dist/cjs/entities/token.js.map +1 -0
- package/dist/cjs/entities/types.d.ts +90 -0
- package/dist/cjs/entities/types.d.ts.map +1 -0
- package/dist/cjs/entities/types.js +33 -0
- package/dist/cjs/entities/types.js.map +1 -0
- package/dist/cjs/events/index.d.ts +39 -0
- package/dist/cjs/events/index.d.ts.map +1 -0
- package/dist/cjs/events/index.js +112 -0
- package/dist/cjs/events/index.js.map +1 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +44 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/preview.d.ts +28 -0
- package/dist/cjs/preview.d.ts.map +1 -0
- package/dist/cjs/preview.js +49 -0
- package/dist/cjs/preview.js.map +1 -0
- package/dist/esm/apps/publish.js +162 -0
- package/dist/esm/apps/publish.js.map +1 -0
- package/dist/esm/auth/index.js +90 -0
- package/dist/esm/auth/index.js.map +1 -0
- package/dist/esm/config/index.js +10 -0
- package/dist/esm/config/index.js.map +1 -0
- package/dist/esm/entities/cache.js +74 -0
- package/dist/esm/entities/cache.js.map +1 -0
- package/dist/esm/entities/client.js +127 -0
- package/dist/esm/entities/client.js.map +1 -0
- package/dist/esm/entities/errors.js +60 -0
- package/dist/esm/entities/errors.js.map +1 -0
- package/dist/esm/entities/handler.js +320 -0
- package/dist/esm/entities/handler.js.map +1 -0
- package/dist/esm/entities/identity.js +167 -0
- package/dist/esm/entities/identity.js.map +1 -0
- package/dist/esm/entities/index.js +14 -0
- package/dist/esm/entities/index.js.map +1 -0
- package/dist/esm/entities/redis.js +310 -0
- package/dist/esm/entities/redis.js.map +1 -0
- package/dist/esm/entities/resolver.js +121 -0
- package/dist/esm/entities/resolver.js.map +1 -0
- package/dist/esm/entities/schema.js +98 -0
- package/dist/esm/entities/schema.js.map +1 -0
- package/dist/esm/entities/scopedDb.js +92 -0
- package/dist/esm/entities/scopedDb.js.map +1 -0
- package/dist/esm/entities/token.js +82 -0
- package/dist/esm/entities/token.js.map +1 -0
- package/dist/esm/entities/types.js +29 -0
- package/dist/esm/entities/types.js.map +1 -0
- package/dist/esm/events/index.js +69 -0
- package/dist/esm/events/index.js.map +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/preview.js +45 -0
- package/dist/esm/preview.js.map +1 -0
- package/package.json +62 -0
- package/src/apps/publish.test.ts +178 -0
- package/src/apps/publish.ts +251 -0
- package/src/auth/index.ts +114 -0
- package/src/config/index.ts +16 -0
- package/src/entities/cache.ts +103 -0
- package/src/entities/client.ts +180 -0
- package/src/entities/entities.test.ts +611 -0
- package/src/entities/errors.ts +66 -0
- package/src/entities/handler.ts +408 -0
- package/src/entities/identity.ts +222 -0
- package/src/entities/index.ts +108 -0
- package/src/entities/redis.test.ts +192 -0
- package/src/entities/redis.ts +454 -0
- package/src/entities/resolver.ts +163 -0
- package/src/entities/schema.ts +130 -0
- package/src/entities/scopedDb.ts +165 -0
- package/src/entities/token.ts +106 -0
- package/src/entities/types.ts +108 -0
- package/src/events/index.ts +94 -0
- package/src/index.ts +43 -0
- package/src/preview.ts +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ANBY
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @anby/platform-sdk
|
|
2
|
+
|
|
3
|
+
SDK runtime mà mọi service Anby (và mọi app được cài thêm) dùng để cắm vào platform. Package này gói gọn ba concern xuyên suốt mà nếu không có nó thì mỗi service sẽ phải tự viết lại:
|
|
4
|
+
|
|
5
|
+
1. **Auth** — verify JWT đến từ `anby-auth-service` và verify các request service-to-service ký bằng HMAC.
|
|
6
|
+
2. **Events** — publish / subscribe event bus của platform qua transport có thể thay thế.
|
|
7
|
+
3. **Config** — một entry point `configurePlatform()` duy nhất để các service boot đồng nhất.
|
|
8
|
+
|
|
9
|
+
Phụ thuộc vào [`@anby/contracts`](../contracts) để dùng envelope sự kiện đã được type sẵn.
|
|
10
|
+
|
|
11
|
+
## Cài đặt
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@anby/platform-sdk": "file:../../packages/platform-sdk",
|
|
17
|
+
"@anby/contracts": "file:../../packages/contracts"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Cách dùng
|
|
23
|
+
|
|
24
|
+
### Bootstrap
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { configurePlatform, configureAuth, configureEventTransport, PostgresEventTransport } from '@anby/platform-sdk';
|
|
28
|
+
|
|
29
|
+
configurePlatform({ serviceName: 'org-chart', tenantResolver });
|
|
30
|
+
configureAuth({ jwtPublicKey: process.env.AUTH_PUBLIC_KEY!, hmacSecret: process.env.SVC_HMAC_SECRET! });
|
|
31
|
+
configureEventTransport(new PostgresEventTransport(process.env.DATABASE_URL!));
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Xác thực request
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { requireAuth, type AuthUser } from '@anby/platform-sdk';
|
|
38
|
+
|
|
39
|
+
app.get('/me', requireAuth(), (req, res) => {
|
|
40
|
+
const user = (req as any).user as AuthUser;
|
|
41
|
+
res.json(user);
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- `verifyJwt(token)` — verify token của end-user.
|
|
46
|
+
- `verifyHmac(req)` — verify chữ ký service-to-service.
|
|
47
|
+
- `authenticateRequest(req)` — thử JWT trước, fallback sang HMAC.
|
|
48
|
+
- `requireAuth()` — middleware kiểu Express/Remix, trả 401 nếu fail.
|
|
49
|
+
|
|
50
|
+
### Publish một event
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { createEvent, publishEvent } from '@anby/platform-sdk';
|
|
54
|
+
|
|
55
|
+
await publishEvent(createEvent({
|
|
56
|
+
type: 'org.node.created',
|
|
57
|
+
tenantId,
|
|
58
|
+
actor: { userId, email },
|
|
59
|
+
data: { nodeId, parentId },
|
|
60
|
+
}));
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Các transport có sẵn:
|
|
64
|
+
- **`InMemoryTransport`** — dùng cho test và local dev.
|
|
65
|
+
- **`PostgresEventTransport`** — ghi vào bảng outbox để `anby-event-router` tiêu thụ.
|
|
66
|
+
|
|
67
|
+
## Cấu trúc
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
src/
|
|
71
|
+
├── auth/ Verify JWT + HMAC, middleware auth
|
|
72
|
+
├── events/ Builder envelope sự kiện + transport có thể thay thế
|
|
73
|
+
├── config/ configurePlatform / getPlatformConfig
|
|
74
|
+
└── index.ts Public API — chỉ import từ đây
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Scripts
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm run build # tsc
|
|
81
|
+
npm run test # vitest
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Độ ổn định
|
|
85
|
+
|
|
86
|
+
Chưa đạt 1.0. Public API là tất cả những gì được re-export từ `src/index.ts`; mọi thứ khác đều là nội bộ và có thể thay đổi mà không báo trước.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App publish helper for self-hosted Anby services.
|
|
3
|
+
*
|
|
4
|
+
* Single code path used by:
|
|
5
|
+
* - Service startup (`publishAppFromManifest()` inside entry.server.tsx / main.ts)
|
|
6
|
+
* - The `anby app publish` CLI
|
|
7
|
+
* - The shell's Marketplace "Submit app" server action
|
|
8
|
+
*
|
|
9
|
+
* All three converge on `POST /registry/apps` with a platform HMAC signature,
|
|
10
|
+
* which the registry verifies via `HmacGuard` and then persists via the same
|
|
11
|
+
* `registry.service.publishApp()`.
|
|
12
|
+
*/
|
|
13
|
+
export interface PublishAppOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Path to the manifest file. Defaults to `./anby-app.manifest.json` in the
|
|
16
|
+
* current working directory, which is where every Anby service keeps it.
|
|
17
|
+
*/
|
|
18
|
+
manifestPath?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Registry base URL — defaults to REGISTRY_URL env or http://localhost:3003.
|
|
21
|
+
*/
|
|
22
|
+
registryUrl?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Public URL where this service is reachable. Overrides APP_PUBLIC_URL env.
|
|
25
|
+
* When neither is set, the helper derives `http://localhost:<manifest.runtime.port>`.
|
|
26
|
+
*/
|
|
27
|
+
publicUrl?: string;
|
|
28
|
+
/**
|
|
29
|
+
* HMAC secret used to authenticate the call. Defaults to INTERNAL_API_SECRET
|
|
30
|
+
* env. Must match the secret the registry is running with.
|
|
31
|
+
*/
|
|
32
|
+
internalApiSecret?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Identifier sent in `x-internal-user` header. Defaults to the manifest id
|
|
35
|
+
* so audit logs show which service published.
|
|
36
|
+
*/
|
|
37
|
+
submittedBy?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Marks the app as "featured" so it shows up in the setup-wizard
|
|
40
|
+
* recommendation list. Defaults to false.
|
|
41
|
+
*/
|
|
42
|
+
featured?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Optional changelog string attached to this version.
|
|
45
|
+
*/
|
|
46
|
+
changelog?: string;
|
|
47
|
+
/**
|
|
48
|
+
* If true, swallow network/registry errors and return null instead of
|
|
49
|
+
* throwing. Used by `autoPublishOnBoot` so a flaky registry doesn't
|
|
50
|
+
* crash the service startup.
|
|
51
|
+
*/
|
|
52
|
+
silent?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface PublishAppResult {
|
|
55
|
+
app: {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
publicUrl: string | null;
|
|
59
|
+
status: string;
|
|
60
|
+
};
|
|
61
|
+
version: {
|
|
62
|
+
appId: string;
|
|
63
|
+
version: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export declare function publishAppFromManifest(opts?: PublishAppOptions): Promise<PublishAppResult | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Fire-and-forget wrapper for use inside service entrypoints. Logs on both
|
|
69
|
+
* success and failure but never throws, so a flaky registry at boot time
|
|
70
|
+
* doesn't crash the service.
|
|
71
|
+
*/
|
|
72
|
+
export declare function autoPublishOnBoot(opts?: PublishAppOptions): void;
|
|
73
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/apps/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE;QACH,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAyFD,wBAAsB,sBAAsB,CAC1C,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA6ElC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,iBAAsB,GAAG,IAAI,CAMpE"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* App publish helper for self-hosted Anby services.
|
|
4
|
+
*
|
|
5
|
+
* Single code path used by:
|
|
6
|
+
* - Service startup (`publishAppFromManifest()` inside entry.server.tsx / main.ts)
|
|
7
|
+
* - The `anby app publish` CLI
|
|
8
|
+
* - The shell's Marketplace "Submit app" server action
|
|
9
|
+
*
|
|
10
|
+
* All three converge on `POST /registry/apps` with a platform HMAC signature,
|
|
11
|
+
* which the registry verifies via `HmacGuard` and then persists via the same
|
|
12
|
+
* `registry.service.publishApp()`.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.publishAppFromManifest = publishAppFromManifest;
|
|
16
|
+
exports.autoPublishOnBoot = autoPublishOnBoot;
|
|
17
|
+
const promises_1 = require("node:fs/promises");
|
|
18
|
+
const node_path_1 = require("node:path");
|
|
19
|
+
const manifest_schema_1 = require("@anby/manifest-schema");
|
|
20
|
+
const index_js_1 = require("../auth/index.js");
|
|
21
|
+
const schema_js_1 = require("../entities/schema.js");
|
|
22
|
+
async function loadManifest(path) {
|
|
23
|
+
const raw = await (0, promises_1.readFile)(path, 'utf-8');
|
|
24
|
+
const parsed = JSON.parse(raw);
|
|
25
|
+
const { valid, errors } = (0, manifest_schema_1.validateManifest)(parsed);
|
|
26
|
+
if (!valid) {
|
|
27
|
+
throw new Error(`Manifest at ${path} is invalid:\n - ${errors.join('\n - ')}`);
|
|
28
|
+
}
|
|
29
|
+
return parsed;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Entity schema inliner (CR-4).
|
|
33
|
+
*
|
|
34
|
+
* The manifest-on-disk references schemas by relative path for
|
|
35
|
+
* developer ergonomics. At publish time we MUST inline the actual JSON
|
|
36
|
+
* content — the registry has no access to the publisher's filesystem
|
|
37
|
+
* and explicitly rejects string schema paths in publish payloads.
|
|
38
|
+
*
|
|
39
|
+
* We also compute a sha256 checksum over the schema content so the
|
|
40
|
+
* registry can detect drift in follow-up publishes.
|
|
41
|
+
*/
|
|
42
|
+
async function inlineEntitySchemas(manifest, manifestPath) {
|
|
43
|
+
const entities = manifest.provides?.entities;
|
|
44
|
+
if (!entities || entities.length === 0)
|
|
45
|
+
return manifest;
|
|
46
|
+
const manifestDir = (0, node_path_1.dirname)(manifestPath);
|
|
47
|
+
const resolved = await Promise.all(entities.map(async (entry) => {
|
|
48
|
+
// String form — legacy. Coerce to object with no schema.
|
|
49
|
+
if (typeof entry === 'string') {
|
|
50
|
+
return { name: entry, version: 'v1' };
|
|
51
|
+
}
|
|
52
|
+
// Object form without a schema field — nothing to inline.
|
|
53
|
+
if (!entry.schema)
|
|
54
|
+
return entry;
|
|
55
|
+
// Already inlined (object content, not a path) — pass through and
|
|
56
|
+
// compute checksum if the caller didn't.
|
|
57
|
+
if (typeof entry.schema === 'object') {
|
|
58
|
+
return {
|
|
59
|
+
...entry,
|
|
60
|
+
schemaChecksum: entry.schemaChecksum ?? (0, schema_js_1.schemaChecksum)(entry.schema),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Schema is a string path — resolve relative to the manifest,
|
|
64
|
+
// read, parse, inline.
|
|
65
|
+
const schemaPath = (0, node_path_1.isAbsolute)(entry.schema)
|
|
66
|
+
? entry.schema
|
|
67
|
+
: (0, node_path_1.resolve)(manifestDir, entry.schema);
|
|
68
|
+
let rawSchema;
|
|
69
|
+
try {
|
|
70
|
+
rawSchema = await (0, promises_1.readFile)(schemaPath, 'utf-8');
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
throw new Error(`Entity "${entry.name}": unable to read schema file at ${schemaPath} ` +
|
|
74
|
+
`(${err.message})`);
|
|
75
|
+
}
|
|
76
|
+
let parsed;
|
|
77
|
+
try {
|
|
78
|
+
parsed = JSON.parse(rawSchema);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
throw new Error(`Entity "${entry.name}": schema file at ${schemaPath} is not valid JSON: ${err.message}`);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
name: entry.name,
|
|
85
|
+
version: entry.version,
|
|
86
|
+
schema: parsed,
|
|
87
|
+
schemaChecksum: (0, schema_js_1.schemaChecksum)(parsed),
|
|
88
|
+
};
|
|
89
|
+
}));
|
|
90
|
+
return {
|
|
91
|
+
...manifest,
|
|
92
|
+
provides: {
|
|
93
|
+
...manifest.provides,
|
|
94
|
+
entities: resolved,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function publishAppFromManifest(opts = {}) {
|
|
99
|
+
try {
|
|
100
|
+
const manifestPath = (0, node_path_1.resolve)(opts.manifestPath ?? (0, node_path_1.join)(process.cwd(), 'anby-app.manifest.json'));
|
|
101
|
+
const rawManifest = await loadManifest(manifestPath);
|
|
102
|
+
// CR-4: inline schema content before sending. Manifest on disk uses
|
|
103
|
+
// relative paths for DX; wire format sends the actual JSON object.
|
|
104
|
+
const manifest = await inlineEntitySchemas(rawManifest, manifestPath);
|
|
105
|
+
const publicUrl = opts.publicUrl ??
|
|
106
|
+
process.env.APP_PUBLIC_URL ??
|
|
107
|
+
`http://localhost:${manifest.runtime.port}`;
|
|
108
|
+
const registryUrl = opts.registryUrl ??
|
|
109
|
+
process.env.REGISTRY_URL ??
|
|
110
|
+
'http://localhost:3003';
|
|
111
|
+
const internalApiSecret = opts.internalApiSecret ?? process.env.INTERNAL_API_SECRET ?? '';
|
|
112
|
+
if (!internalApiSecret) {
|
|
113
|
+
throw new Error('INTERNAL_API_SECRET is not set — cannot sign publish request');
|
|
114
|
+
}
|
|
115
|
+
const submittedBy = opts.submittedBy ?? manifest.id;
|
|
116
|
+
const signature = (0, index_js_1.signHmac)(submittedBy, internalApiSecret);
|
|
117
|
+
const body = {
|
|
118
|
+
id: manifest.id,
|
|
119
|
+
name: manifest.name,
|
|
120
|
+
description: manifest.description,
|
|
121
|
+
icon: manifest.icon,
|
|
122
|
+
color: manifest.color,
|
|
123
|
+
publisherId: manifest.id.split('.').slice(0, 2).join('.'),
|
|
124
|
+
version: manifest.version,
|
|
125
|
+
publicUrl,
|
|
126
|
+
submittedBy,
|
|
127
|
+
featured: opts.featured,
|
|
128
|
+
changelog: opts.changelog,
|
|
129
|
+
manifest,
|
|
130
|
+
};
|
|
131
|
+
const res = await fetch(`${registryUrl}/registry/apps`, {
|
|
132
|
+
method: 'POST',
|
|
133
|
+
headers: {
|
|
134
|
+
'Content-Type': 'application/json',
|
|
135
|
+
'x-internal-user': submittedBy,
|
|
136
|
+
'x-internal-signature': signature,
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify(body),
|
|
139
|
+
});
|
|
140
|
+
if (!res.ok) {
|
|
141
|
+
const errBody = await res.text();
|
|
142
|
+
throw new Error(`Registry rejected publish (${res.status}): ${errBody}`);
|
|
143
|
+
}
|
|
144
|
+
const result = (await res.json());
|
|
145
|
+
console.log(`[platform-sdk] Published ${manifest.id}@${manifest.version} to ${registryUrl} (publicUrl=${publicUrl})`);
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
if (opts.silent) {
|
|
150
|
+
console.warn(`[platform-sdk] publishAppFromManifest failed (silent): ${err.message}`);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Fire-and-forget wrapper for use inside service entrypoints. Logs on both
|
|
158
|
+
* success and failure but never throws, so a flaky registry at boot time
|
|
159
|
+
* doesn't crash the service.
|
|
160
|
+
*/
|
|
161
|
+
function autoPublishOnBoot(opts = {}) {
|
|
162
|
+
publishAppFromManifest({ ...opts, silent: true }).catch((err) => {
|
|
163
|
+
console.warn(`[platform-sdk] autoPublishOnBoot unexpected error: ${err.message}`);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/apps/publish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface AuthUser {
|
|
2
|
+
id: string;
|
|
3
|
+
email: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
tenantId: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AuthConfig {
|
|
8
|
+
jwtSecret: string;
|
|
9
|
+
internalApiSecret: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function configureAuth(config: AuthConfig): void;
|
|
12
|
+
export declare function verifyJwt(token: string): AuthUser;
|
|
13
|
+
export declare function verifyHmac(userValue: string, signature: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Compute an HMAC signature for service-to-service calls. Pair the returned
|
|
16
|
+
* value with the matching `userValue` sent in the `x-internal-user` header;
|
|
17
|
+
* the receiving side calls `verifyHmac` with the same pair.
|
|
18
|
+
*/
|
|
19
|
+
export declare function signHmac(userValue: string, secret?: string): string;
|
|
20
|
+
export declare function authenticateRequest(request: Request): AuthUser | null;
|
|
21
|
+
export declare function requireAuth(request: Request): AuthUser;
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAID,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAEtD;AAOD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAcjD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAOxE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAMnE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAsCrE;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAStD"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.configureAuth = configureAuth;
|
|
7
|
+
exports.verifyJwt = verifyJwt;
|
|
8
|
+
exports.verifyHmac = verifyHmac;
|
|
9
|
+
exports.signHmac = signHmac;
|
|
10
|
+
exports.authenticateRequest = authenticateRequest;
|
|
11
|
+
exports.requireAuth = requireAuth;
|
|
12
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
13
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
14
|
+
let _config = null;
|
|
15
|
+
function configureAuth(config) {
|
|
16
|
+
_config = config;
|
|
17
|
+
}
|
|
18
|
+
function getConfig() {
|
|
19
|
+
if (!_config)
|
|
20
|
+
throw new Error('Auth not configured. Call configureAuth() first.');
|
|
21
|
+
return _config;
|
|
22
|
+
}
|
|
23
|
+
function verifyJwt(token) {
|
|
24
|
+
const config = getConfig();
|
|
25
|
+
const payload = jsonwebtoken_1.default.verify(token, config.jwtSecret);
|
|
26
|
+
return {
|
|
27
|
+
id: payload.sub,
|
|
28
|
+
email: payload.email,
|
|
29
|
+
name: payload.name,
|
|
30
|
+
tenantId: payload.tenantId || 'default',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function verifyHmac(userValue, signature) {
|
|
34
|
+
const config = getConfig();
|
|
35
|
+
const expected = crypto_1.default
|
|
36
|
+
.createHmac('sha256', config.internalApiSecret)
|
|
37
|
+
.update(userValue)
|
|
38
|
+
.digest('hex');
|
|
39
|
+
return crypto_1.default.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Compute an HMAC signature for service-to-service calls. Pair the returned
|
|
43
|
+
* value with the matching `userValue` sent in the `x-internal-user` header;
|
|
44
|
+
* the receiving side calls `verifyHmac` with the same pair.
|
|
45
|
+
*/
|
|
46
|
+
function signHmac(userValue, secret) {
|
|
47
|
+
const internalApiSecret = secret ?? getConfig().internalApiSecret;
|
|
48
|
+
return crypto_1.default
|
|
49
|
+
.createHmac('sha256', internalApiSecret)
|
|
50
|
+
.update(userValue)
|
|
51
|
+
.digest('hex');
|
|
52
|
+
}
|
|
53
|
+
function authenticateRequest(request) {
|
|
54
|
+
// Try JWT from Authorization header
|
|
55
|
+
const authHeader = request.headers.get('authorization');
|
|
56
|
+
if (authHeader?.startsWith('Bearer ')) {
|
|
57
|
+
try {
|
|
58
|
+
return verifyJwt(authHeader.slice(7));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Try JWT from cookie
|
|
65
|
+
const cookies = request.headers.get('cookie') || '';
|
|
66
|
+
const authCookie = cookies.split(';').find(c => c.trim().startsWith('auth-token='));
|
|
67
|
+
if (authCookie) {
|
|
68
|
+
const token = authCookie.split('=')[1]?.trim();
|
|
69
|
+
if (token) {
|
|
70
|
+
try {
|
|
71
|
+
return verifyJwt(token);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Try HMAC (service-to-service)
|
|
79
|
+
const internalUser = request.headers.get('x-internal-user');
|
|
80
|
+
const internalSig = request.headers.get('x-internal-signature');
|
|
81
|
+
if (internalUser && internalSig && verifyHmac(internalUser, internalSig)) {
|
|
82
|
+
return {
|
|
83
|
+
id: 'internal',
|
|
84
|
+
email: internalUser,
|
|
85
|
+
name: 'Internal Service',
|
|
86
|
+
tenantId: request.headers.get('x-tenant-id') || 'default',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
function requireAuth(request) {
|
|
92
|
+
const user = authenticateRequest(request);
|
|
93
|
+
if (!user) {
|
|
94
|
+
throw new Response(JSON.stringify({ error: 'Unauthorized' }), {
|
|
95
|
+
status: 401,
|
|
96
|
+
headers: { 'Content-Type': 'application/json' },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return user;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface PlatformConfig {
|
|
2
|
+
registryUrl: string;
|
|
3
|
+
appId: string;
|
|
4
|
+
tenantId?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function configurePlatform(config: PlatformConfig): void;
|
|
7
|
+
export declare function getPlatformConfig(): PlatformConfig;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAE9D;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAGlD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configurePlatform = configurePlatform;
|
|
4
|
+
exports.getPlatformConfig = getPlatformConfig;
|
|
5
|
+
let _platformConfig = null;
|
|
6
|
+
function configurePlatform(config) {
|
|
7
|
+
_platformConfig = config;
|
|
8
|
+
}
|
|
9
|
+
function getPlatformConfig() {
|
|
10
|
+
if (!_platformConfig)
|
|
11
|
+
throw new Error('Platform not configured. Call configurePlatform() first.');
|
|
12
|
+
return _platformConfig;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":";;AAQA,8CAEC;AAED,8CAGC;AATD,IAAI,eAAe,GAA0B,IAAI,CAAC;AAElD,SAAgB,iBAAiB,CAAC,MAAsB;IACtD,eAAe,GAAG,MAAM,CAAC;AAC3B,CAAC;AAED,SAAgB,iBAAiB;IAC/B,IAAI,CAAC,eAAe;QAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAClG,OAAO,eAAe,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity response cache (Phase 1 = in-memory LRU).
|
|
3
|
+
*
|
|
4
|
+
* Interface is pluggable so Phase 2 can swap to Redis + pub/sub invalidation
|
|
5
|
+
* without touching callers. Key format: "{tenantId}:{entity}@{version}:{pathHash}".
|
|
6
|
+
*/
|
|
7
|
+
export interface EntityCache {
|
|
8
|
+
get(key: string): unknown | undefined;
|
|
9
|
+
set(key: string, value: unknown, ttlMs?: number): void;
|
|
10
|
+
del(key: string): void;
|
|
11
|
+
delPattern(prefix: string): void;
|
|
12
|
+
clear(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare class InMemoryEntityCache implements EntityCache {
|
|
15
|
+
private readonly store;
|
|
16
|
+
private readonly maxEntries;
|
|
17
|
+
private readonly defaultTtlMs;
|
|
18
|
+
constructor(opts?: {
|
|
19
|
+
maxEntries?: number;
|
|
20
|
+
defaultTtlMs?: number;
|
|
21
|
+
});
|
|
22
|
+
get(key: string): unknown | undefined;
|
|
23
|
+
set(key: string, value: unknown, ttlMs?: number): void;
|
|
24
|
+
del(key: string): void;
|
|
25
|
+
delPattern(prefix: string): void;
|
|
26
|
+
clear(): void;
|
|
27
|
+
}
|
|
28
|
+
export declare function configureEntityCache(cache: EntityCache): void;
|
|
29
|
+
export declare function getEntityCache(): EntityCache;
|
|
30
|
+
export declare function entityCacheKey(tenantId: string, entityName: string, version: string, path: string, query?: Record<string, unknown>): string;
|
|
31
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/entities/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACtC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,KAAK,IAAI,IAAI,CAAC;CACf;AAOD,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,IAAI,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAO;IAKrE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAarC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAWtD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAItB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAMhC,KAAK,IAAI,IAAI;CAGd;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAE7D;AAED,wBAAgB,cAAc,IAAI,WAAW,CAE5C;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAClC,MAAM,CAeR"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Entity response cache (Phase 1 = in-memory LRU).
|
|
4
|
+
*
|
|
5
|
+
* Interface is pluggable so Phase 2 can swap to Redis + pub/sub invalidation
|
|
6
|
+
* without touching callers. Key format: "{tenantId}:{entity}@{version}:{pathHash}".
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.InMemoryEntityCache = void 0;
|
|
13
|
+
exports.configureEntityCache = configureEntityCache;
|
|
14
|
+
exports.getEntityCache = getEntityCache;
|
|
15
|
+
exports.entityCacheKey = entityCacheKey;
|
|
16
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
17
|
+
class InMemoryEntityCache {
|
|
18
|
+
store = new Map();
|
|
19
|
+
maxEntries;
|
|
20
|
+
defaultTtlMs;
|
|
21
|
+
constructor(opts = {}) {
|
|
22
|
+
this.maxEntries = opts.maxEntries ?? 1000;
|
|
23
|
+
this.defaultTtlMs = opts.defaultTtlMs ?? 30_000;
|
|
24
|
+
}
|
|
25
|
+
get(key) {
|
|
26
|
+
const entry = this.store.get(key);
|
|
27
|
+
if (!entry)
|
|
28
|
+
return undefined;
|
|
29
|
+
if (entry.expiresAt <= Date.now()) {
|
|
30
|
+
this.store.delete(key);
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
// Refresh insertion order for LRU.
|
|
34
|
+
this.store.delete(key);
|
|
35
|
+
this.store.set(key, entry);
|
|
36
|
+
return entry.value;
|
|
37
|
+
}
|
|
38
|
+
set(key, value, ttlMs) {
|
|
39
|
+
this.store.set(key, {
|
|
40
|
+
value,
|
|
41
|
+
expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs),
|
|
42
|
+
});
|
|
43
|
+
if (this.store.size > this.maxEntries) {
|
|
44
|
+
const oldest = this.store.keys().next().value;
|
|
45
|
+
if (oldest !== undefined)
|
|
46
|
+
this.store.delete(oldest);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
del(key) {
|
|
50
|
+
this.store.delete(key);
|
|
51
|
+
}
|
|
52
|
+
delPattern(prefix) {
|
|
53
|
+
for (const key of this.store.keys()) {
|
|
54
|
+
if (key.startsWith(prefix))
|
|
55
|
+
this.store.delete(key);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
clear() {
|
|
59
|
+
this.store.clear();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.InMemoryEntityCache = InMemoryEntityCache;
|
|
63
|
+
let _cache = new InMemoryEntityCache();
|
|
64
|
+
function configureEntityCache(cache) {
|
|
65
|
+
_cache = cache;
|
|
66
|
+
}
|
|
67
|
+
function getEntityCache() {
|
|
68
|
+
return _cache;
|
|
69
|
+
}
|
|
70
|
+
function entityCacheKey(tenantId, entityName, version, path, query = {}) {
|
|
71
|
+
const sortedQuery = JSON.stringify(Object.keys(query)
|
|
72
|
+
.sort()
|
|
73
|
+
.reduce((acc, k) => {
|
|
74
|
+
acc[k] = query[k];
|
|
75
|
+
return acc;
|
|
76
|
+
}, {}));
|
|
77
|
+
const hash = crypto_1.default
|
|
78
|
+
.createHash('sha256')
|
|
79
|
+
.update(path + '|' + sortedQuery)
|
|
80
|
+
.digest('hex')
|
|
81
|
+
.slice(0, 16);
|
|
82
|
+
return `${tenantId}:${entityName}@${version}:${hash}`;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/entities/cache.ts"],"names":[],"mappings":"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"}
|