@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.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -0
  3. package/dist/cjs/apps/publish.d.ts +73 -0
  4. package/dist/cjs/apps/publish.d.ts.map +1 -0
  5. package/dist/cjs/apps/publish.js +166 -0
  6. package/dist/cjs/apps/publish.js.map +1 -0
  7. package/dist/cjs/auth/index.d.ts +22 -0
  8. package/dist/cjs/auth/index.d.ts.map +1 -0
  9. package/dist/cjs/auth/index.js +101 -0
  10. package/dist/cjs/auth/index.js.map +1 -0
  11. package/dist/cjs/config/index.d.ts +8 -0
  12. package/dist/cjs/config/index.d.ts.map +1 -0
  13. package/dist/cjs/config/index.js +14 -0
  14. package/dist/cjs/config/index.js.map +1 -0
  15. package/dist/cjs/entities/cache.d.ts +31 -0
  16. package/dist/cjs/entities/cache.d.ts.map +1 -0
  17. package/dist/cjs/entities/cache.js +84 -0
  18. package/dist/cjs/entities/cache.js.map +1 -0
  19. package/dist/cjs/entities/client.d.ts +32 -0
  20. package/dist/cjs/entities/client.d.ts.map +1 -0
  21. package/dist/cjs/entities/client.js +130 -0
  22. package/dist/cjs/entities/client.js.map +1 -0
  23. package/dist/cjs/entities/errors.d.ts +35 -0
  24. package/dist/cjs/entities/errors.d.ts.map +1 -0
  25. package/dist/cjs/entities/errors.js +68 -0
  26. package/dist/cjs/entities/errors.js.map +1 -0
  27. package/dist/cjs/entities/handler.d.ts +89 -0
  28. package/dist/cjs/entities/handler.d.ts.map +1 -0
  29. package/dist/cjs/entities/handler.js +332 -0
  30. package/dist/cjs/entities/handler.js.map +1 -0
  31. package/dist/cjs/entities/identity.d.ts +90 -0
  32. package/dist/cjs/entities/identity.d.ts.map +1 -0
  33. package/dist/cjs/entities/identity.js +180 -0
  34. package/dist/cjs/entities/identity.js.map +1 -0
  35. package/dist/cjs/entities/index.d.ts +12 -0
  36. package/dist/cjs/entities/index.d.ts.map +1 -0
  37. package/dist/cjs/entities/index.js +64 -0
  38. package/dist/cjs/entities/index.js.map +1 -0
  39. package/dist/cjs/entities/redis.d.ts +128 -0
  40. package/dist/cjs/entities/redis.d.ts.map +1 -0
  41. package/dist/cjs/entities/redis.js +354 -0
  42. package/dist/cjs/entities/redis.js.map +1 -0
  43. package/dist/cjs/entities/resolver.d.ts +25 -0
  44. package/dist/cjs/entities/resolver.d.ts.map +1 -0
  45. package/dist/cjs/entities/resolver.js +128 -0
  46. package/dist/cjs/entities/resolver.js.map +1 -0
  47. package/dist/cjs/entities/schema.d.ts +15 -0
  48. package/dist/cjs/entities/schema.d.ts.map +1 -0
  49. package/dist/cjs/entities/schema.js +140 -0
  50. package/dist/cjs/entities/schema.js.map +1 -0
  51. package/dist/cjs/entities/scopedDb.d.ts +92 -0
  52. package/dist/cjs/entities/scopedDb.d.ts.map +1 -0
  53. package/dist/cjs/entities/scopedDb.js +96 -0
  54. package/dist/cjs/entities/scopedDb.js.map +1 -0
  55. package/dist/cjs/entities/token.d.ts +18 -0
  56. package/dist/cjs/entities/token.d.ts.map +1 -0
  57. package/dist/cjs/entities/token.js +87 -0
  58. package/dist/cjs/entities/token.js.map +1 -0
  59. package/dist/cjs/entities/types.d.ts +90 -0
  60. package/dist/cjs/entities/types.d.ts.map +1 -0
  61. package/dist/cjs/entities/types.js +33 -0
  62. package/dist/cjs/entities/types.js.map +1 -0
  63. package/dist/cjs/events/index.d.ts +39 -0
  64. package/dist/cjs/events/index.d.ts.map +1 -0
  65. package/dist/cjs/events/index.js +112 -0
  66. package/dist/cjs/events/index.js.map +1 -0
  67. package/dist/cjs/index.d.ts +7 -0
  68. package/dist/cjs/index.d.ts.map +1 -0
  69. package/dist/cjs/index.js +44 -0
  70. package/dist/cjs/index.js.map +1 -0
  71. package/dist/cjs/preview.d.ts +28 -0
  72. package/dist/cjs/preview.d.ts.map +1 -0
  73. package/dist/cjs/preview.js +49 -0
  74. package/dist/cjs/preview.js.map +1 -0
  75. package/dist/esm/apps/publish.js +162 -0
  76. package/dist/esm/apps/publish.js.map +1 -0
  77. package/dist/esm/auth/index.js +90 -0
  78. package/dist/esm/auth/index.js.map +1 -0
  79. package/dist/esm/config/index.js +10 -0
  80. package/dist/esm/config/index.js.map +1 -0
  81. package/dist/esm/entities/cache.js +74 -0
  82. package/dist/esm/entities/cache.js.map +1 -0
  83. package/dist/esm/entities/client.js +127 -0
  84. package/dist/esm/entities/client.js.map +1 -0
  85. package/dist/esm/entities/errors.js +60 -0
  86. package/dist/esm/entities/errors.js.map +1 -0
  87. package/dist/esm/entities/handler.js +320 -0
  88. package/dist/esm/entities/handler.js.map +1 -0
  89. package/dist/esm/entities/identity.js +167 -0
  90. package/dist/esm/entities/identity.js.map +1 -0
  91. package/dist/esm/entities/index.js +14 -0
  92. package/dist/esm/entities/index.js.map +1 -0
  93. package/dist/esm/entities/redis.js +310 -0
  94. package/dist/esm/entities/redis.js.map +1 -0
  95. package/dist/esm/entities/resolver.js +121 -0
  96. package/dist/esm/entities/resolver.js.map +1 -0
  97. package/dist/esm/entities/schema.js +98 -0
  98. package/dist/esm/entities/schema.js.map +1 -0
  99. package/dist/esm/entities/scopedDb.js +92 -0
  100. package/dist/esm/entities/scopedDb.js.map +1 -0
  101. package/dist/esm/entities/token.js +82 -0
  102. package/dist/esm/entities/token.js.map +1 -0
  103. package/dist/esm/entities/types.js +29 -0
  104. package/dist/esm/entities/types.js.map +1 -0
  105. package/dist/esm/events/index.js +69 -0
  106. package/dist/esm/events/index.js.map +1 -0
  107. package/dist/esm/index.js +10 -0
  108. package/dist/esm/index.js.map +1 -0
  109. package/dist/esm/preview.js +45 -0
  110. package/dist/esm/preview.js.map +1 -0
  111. package/package.json +62 -0
  112. package/src/apps/publish.test.ts +178 -0
  113. package/src/apps/publish.ts +251 -0
  114. package/src/auth/index.ts +114 -0
  115. package/src/config/index.ts +16 -0
  116. package/src/entities/cache.ts +103 -0
  117. package/src/entities/client.ts +180 -0
  118. package/src/entities/entities.test.ts +611 -0
  119. package/src/entities/errors.ts +66 -0
  120. package/src/entities/handler.ts +408 -0
  121. package/src/entities/identity.ts +222 -0
  122. package/src/entities/index.ts +108 -0
  123. package/src/entities/redis.test.ts +192 -0
  124. package/src/entities/redis.ts +454 -0
  125. package/src/entities/resolver.ts +163 -0
  126. package/src/entities/schema.ts +130 -0
  127. package/src/entities/scopedDb.ts +165 -0
  128. package/src/entities/token.ts +106 -0
  129. package/src/entities/types.ts +108 -0
  130. package/src/events/index.ts +94 -0
  131. package/src/index.ts +43 -0
  132. 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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"}