@betterportal/plugin-bsb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/lib/bootstrapState.d.ts +34 -0
- package/lib/bootstrapState.d.ts.map +1 -0
- package/lib/bootstrapState.js +100 -0
- package/lib/bootstrapState.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +148 -0
- package/lib/index.js.map +1 -0
- package/lib/scopedConfigCache.d.ts +21 -0
- package/lib/scopedConfigCache.d.ts.map +1 -0
- package/lib/scopedConfigCache.js +32 -0
- package/lib/scopedConfigCache.js.map +1 -0
- package/lib/service.d.ts +199 -0
- package/lib/service.d.ts.map +1 -0
- package/lib/service.js +1308 -0
- package/lib/service.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent state held by each BPService instance:
|
|
3
|
+
* - apiKey: control-plane API key (delivered via setup)
|
|
4
|
+
* - cpUrl: control-plane URL (delivered via setup)
|
|
5
|
+
* - tenantLock: first-tenant lock for auto-single-tenant default
|
|
6
|
+
*
|
|
7
|
+
* Stored encrypted on disk at the configured path. Encryption key derived from
|
|
8
|
+
* `configEncryptionKey` (same as service config store).
|
|
9
|
+
*/
|
|
10
|
+
export interface BootstrapStateFile {
|
|
11
|
+
version: 1;
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
cpUrl?: string;
|
|
14
|
+
cpId?: string;
|
|
15
|
+
cpJwksUri?: string;
|
|
16
|
+
configEncryptionKey?: string;
|
|
17
|
+
tenantLock?: string;
|
|
18
|
+
installedAt?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BootstrapStateOptions {
|
|
21
|
+
filePath: string;
|
|
22
|
+
encryptionKey?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class BootstrapStateStore {
|
|
25
|
+
private cache;
|
|
26
|
+
private readonly filePath;
|
|
27
|
+
private readonly key;
|
|
28
|
+
constructor(options: BootstrapStateOptions);
|
|
29
|
+
read(): BootstrapStateFile;
|
|
30
|
+
write(patch: Partial<BootstrapStateFile>): BootstrapStateFile;
|
|
31
|
+
clear(): void;
|
|
32
|
+
hasApiKey(): boolean;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=bootstrapState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrapState.d.ts","sourceRoot":"","sources":["../src/bootstrapState.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAOD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEjB,OAAO,EAAE,qBAAqB;IAK1C,IAAI,IAAI,kBAAkB;IAiB1B,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,kBAAkB;IAU7D,KAAK,IAAI,IAAI;IAOb,SAAS,IAAI,OAAO;CAKrB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node:crypto";
|
|
4
|
+
const ALGO = "aes-256-gcm";
|
|
5
|
+
const IV_LENGTH = 12;
|
|
6
|
+
const AUTH_TAG_LENGTH = 16;
|
|
7
|
+
const SALT = Buffer.from("bp-bootstrap-state-v1", "utf8");
|
|
8
|
+
export class BootstrapStateStore {
|
|
9
|
+
cache = null;
|
|
10
|
+
filePath;
|
|
11
|
+
key;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.filePath = resolve(options.filePath);
|
|
14
|
+
this.key = deriveKey(options.encryptionKey ?? loadOrCreateLocalKey(`${this.filePath}.key`));
|
|
15
|
+
}
|
|
16
|
+
read() {
|
|
17
|
+
if (this.cache)
|
|
18
|
+
return this.cache;
|
|
19
|
+
if (!existsSync(this.filePath)) {
|
|
20
|
+
this.cache = { version: 1 };
|
|
21
|
+
return this.cache;
|
|
22
|
+
}
|
|
23
|
+
const raw = readFileSync(this.filePath, "utf8");
|
|
24
|
+
try {
|
|
25
|
+
this.cache = decrypt(raw, this.key);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
const parsed = JSON.parse(raw);
|
|
29
|
+
if (parsed.version !== 1)
|
|
30
|
+
throw new Error(`Bootstrap state ${this.filePath} version mismatch`);
|
|
31
|
+
this.cache = parsed;
|
|
32
|
+
}
|
|
33
|
+
return this.cache;
|
|
34
|
+
}
|
|
35
|
+
write(patch) {
|
|
36
|
+
const current = this.read();
|
|
37
|
+
const next = { ...current, ...patch, version: 1 };
|
|
38
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
39
|
+
const payload = encrypt(next, this.key);
|
|
40
|
+
writeFileSync(this.filePath, payload, { mode: 0o600 });
|
|
41
|
+
this.cache = next;
|
|
42
|
+
return next;
|
|
43
|
+
}
|
|
44
|
+
clear() {
|
|
45
|
+
this.cache = { version: 1 };
|
|
46
|
+
if (existsSync(this.filePath)) {
|
|
47
|
+
writeFileSync(this.filePath, encrypt(this.cache, this.key), { mode: 0o600 });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
hasApiKey() {
|
|
51
|
+
const s = this.read();
|
|
52
|
+
return typeof s.apiKey === "string" && s.apiKey.length > 0
|
|
53
|
+
&& typeof s.cpUrl === "string" && s.cpUrl.length > 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function deriveKey(passphrase) {
|
|
57
|
+
return scryptSync(passphrase, SALT, 32);
|
|
58
|
+
}
|
|
59
|
+
function loadOrCreateLocalKey(filePath) {
|
|
60
|
+
if (existsSync(filePath)) {
|
|
61
|
+
const key = readFileSync(filePath, "utf8").trim();
|
|
62
|
+
if (key.length >= 16)
|
|
63
|
+
return key;
|
|
64
|
+
}
|
|
65
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
66
|
+
const key = `bp_bsk_${randomBytes(32).toString("base64url")}`;
|
|
67
|
+
writeFileSync(filePath, key, { mode: 0o600 });
|
|
68
|
+
return key;
|
|
69
|
+
}
|
|
70
|
+
function encrypt(state, key) {
|
|
71
|
+
const iv = randomBytes(IV_LENGTH);
|
|
72
|
+
const cipher = createCipheriv(ALGO, key, iv);
|
|
73
|
+
const plaintext = Buffer.from(JSON.stringify(state), "utf8");
|
|
74
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
75
|
+
const tag = cipher.getAuthTag();
|
|
76
|
+
return JSON.stringify({
|
|
77
|
+
v: 1,
|
|
78
|
+
iv: iv.toString("base64"),
|
|
79
|
+
tag: tag.toString("base64"),
|
|
80
|
+
ct: encrypted.toString("base64")
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function decrypt(payload, key) {
|
|
84
|
+
const envelope = JSON.parse(payload);
|
|
85
|
+
if (envelope.v !== 1)
|
|
86
|
+
throw new Error("Bootstrap state envelope version mismatch");
|
|
87
|
+
const iv = Buffer.from(envelope.iv, "base64");
|
|
88
|
+
const tag = Buffer.from(envelope.tag, "base64");
|
|
89
|
+
if (tag.length !== AUTH_TAG_LENGTH)
|
|
90
|
+
throw new Error("Bootstrap state auth tag invalid");
|
|
91
|
+
const ct = Buffer.from(envelope.ct, "base64");
|
|
92
|
+
const decipher = createDecipheriv(ALGO, key, iv);
|
|
93
|
+
decipher.setAuthTag(tag);
|
|
94
|
+
const plaintext = Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
|
|
95
|
+
const parsed = JSON.parse(plaintext);
|
|
96
|
+
if (parsed.version !== 1)
|
|
97
|
+
throw new Error("Bootstrap state version mismatch");
|
|
98
|
+
return parsed;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=bootstrapState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrapState.js","sourceRoot":"","sources":["../src/bootstrapState.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Observable } from "@bsb/base";
|
|
2
|
+
import type { BetterPortalLogger, BetterPortalObservability } from "@betterportal/framework";
|
|
3
|
+
export declare function createBsbObservability(observable: Observable): BetterPortalObservability;
|
|
4
|
+
export declare function createBsbLogger(observable: Observable): BetterPortalLogger;
|
|
5
|
+
export { BPService, BetterPortalConfigSchema, type BetterPortalConfig, type BPServiceConfig, type BPServiceDefinition } from "./service.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAIV,kBAAkB,EAElB,yBAAyB,EAK1B,MAAM,yBAAyB,CAAC;AAwMjC,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,UAAU,GAAG,yBAAyB,CAExF;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,kBAAkB,CAE1E;AAED,OAAO,EACL,SAAS,EACT,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
function mergeAttributes(current, next) {
|
|
2
|
+
return {
|
|
3
|
+
...current,
|
|
4
|
+
...next
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
function toResource(observable) {
|
|
8
|
+
return {
|
|
9
|
+
serviceName: observable.resource["service.name"],
|
|
10
|
+
serviceVersion: observable.resource["service.version"],
|
|
11
|
+
serviceInstanceId: observable.resource["service.instance.id"],
|
|
12
|
+
environment: observable.resource["deployment.environment"],
|
|
13
|
+
...(observable.resource["deployment.region"] ? { region: observable.resource["deployment.region"] } : {})
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
class BsbCounterAdapter {
|
|
17
|
+
counter;
|
|
18
|
+
constructor(counter) {
|
|
19
|
+
this.counter = counter;
|
|
20
|
+
}
|
|
21
|
+
increment(value, labels) {
|
|
22
|
+
this.counter.increment(value, labels);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
class BsbGaugeAdapter {
|
|
26
|
+
gauge;
|
|
27
|
+
constructor(gauge) {
|
|
28
|
+
this.gauge = gauge;
|
|
29
|
+
}
|
|
30
|
+
set(value, labels) {
|
|
31
|
+
this.gauge.set(value, labels);
|
|
32
|
+
}
|
|
33
|
+
increment(value, labels) {
|
|
34
|
+
this.gauge.increment(value, labels);
|
|
35
|
+
}
|
|
36
|
+
decrement(value, labels) {
|
|
37
|
+
this.gauge.decrement(value, labels);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
class BsbHistogramAdapter {
|
|
41
|
+
histogram;
|
|
42
|
+
constructor(histogram) {
|
|
43
|
+
this.histogram = histogram;
|
|
44
|
+
}
|
|
45
|
+
observe(value, labels) {
|
|
46
|
+
this.histogram.record(value, labels);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
class BsbTimerAdapter {
|
|
50
|
+
timer;
|
|
51
|
+
constructor(timer) {
|
|
52
|
+
this.timer = timer;
|
|
53
|
+
}
|
|
54
|
+
stop() {
|
|
55
|
+
return this.timer.stop();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
class BsbMetricsAdapter {
|
|
59
|
+
observable;
|
|
60
|
+
constructor(observable) {
|
|
61
|
+
this.observable = observable;
|
|
62
|
+
}
|
|
63
|
+
counter(name, description, help, labels) {
|
|
64
|
+
return new BsbCounterAdapter(this.observable.metrics.counter(name, description, help, labels ? [...labels] : undefined));
|
|
65
|
+
}
|
|
66
|
+
gauge(name, description, help, labels) {
|
|
67
|
+
return new BsbGaugeAdapter(this.observable.metrics.gauge(name, description, help, labels ? [...labels] : undefined));
|
|
68
|
+
}
|
|
69
|
+
histogram(name, description, help, boundaries, labels) {
|
|
70
|
+
return new BsbHistogramAdapter(this.observable.metrics.histogram(name, description, help, boundaries ? [...boundaries] : undefined, labels ? [...labels] : undefined));
|
|
71
|
+
}
|
|
72
|
+
timer() {
|
|
73
|
+
return new BsbTimerAdapter(this.observable.metrics.timer());
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
class BsbLoggerAdapter {
|
|
77
|
+
observable;
|
|
78
|
+
constructor(observable) {
|
|
79
|
+
this.observable = observable;
|
|
80
|
+
}
|
|
81
|
+
meta(attributes) {
|
|
82
|
+
if (attributes === undefined || Object.keys(attributes).length === 0) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
return [attributes];
|
|
86
|
+
}
|
|
87
|
+
debug(message, attributes) {
|
|
88
|
+
this.observable.log.debug(message, ...this.meta(attributes));
|
|
89
|
+
}
|
|
90
|
+
info(message, attributes) {
|
|
91
|
+
this.observable.log.info(message, ...this.meta(attributes));
|
|
92
|
+
}
|
|
93
|
+
warn(message, attributes) {
|
|
94
|
+
this.observable.log.warn(message, ...this.meta(attributes));
|
|
95
|
+
}
|
|
96
|
+
error(message, attributes) {
|
|
97
|
+
this.observable.log.error(message, ...this.meta(attributes));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
class BsbObservabilityAdapter {
|
|
101
|
+
observable;
|
|
102
|
+
attributes;
|
|
103
|
+
trace;
|
|
104
|
+
traceId;
|
|
105
|
+
spanId;
|
|
106
|
+
resource;
|
|
107
|
+
logger;
|
|
108
|
+
metrics;
|
|
109
|
+
constructor(observable, attributes = {}) {
|
|
110
|
+
this.observable = observable;
|
|
111
|
+
this.attributes = attributes;
|
|
112
|
+
this.trace = {
|
|
113
|
+
traceId: this.observable.traceId,
|
|
114
|
+
spanId: this.observable.spanId
|
|
115
|
+
};
|
|
116
|
+
this.traceId = this.observable.traceId;
|
|
117
|
+
this.spanId = this.observable.spanId;
|
|
118
|
+
this.resource = toResource(this.observable);
|
|
119
|
+
this.logger = new BsbLoggerAdapter(this.observable);
|
|
120
|
+
this.metrics = new BsbMetricsAdapter(this.observable);
|
|
121
|
+
}
|
|
122
|
+
startSpan(name, attributes = {}) {
|
|
123
|
+
return new BsbObservabilityAdapter(this.observable.startSpan(name, attributes), mergeAttributes(this.attributes, attributes));
|
|
124
|
+
}
|
|
125
|
+
setAttribute(key, value) {
|
|
126
|
+
return new BsbObservabilityAdapter(this.observable.setAttribute(key, value), {
|
|
127
|
+
...this.attributes,
|
|
128
|
+
[key]: value
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
setAttributes(attributes) {
|
|
132
|
+
return new BsbObservabilityAdapter(this.observable.setAttributes(attributes), mergeAttributes(this.attributes, attributes));
|
|
133
|
+
}
|
|
134
|
+
end(attributes) {
|
|
135
|
+
this.observable.end(attributes);
|
|
136
|
+
}
|
|
137
|
+
error(error, attributes) {
|
|
138
|
+
this.observable.error(error, attributes);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export function createBsbObservability(observable) {
|
|
142
|
+
return new BsbObservabilityAdapter(observable, observable.attributes);
|
|
143
|
+
}
|
|
144
|
+
export function createBsbLogger(observable) {
|
|
145
|
+
return new BsbLoggerAdapter(observable);
|
|
146
|
+
}
|
|
147
|
+
export { BPService, BetterPortalConfigSchema } from "./service.js";
|
|
148
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local cache for the scoped platform config that a BPService receives from
|
|
3
|
+
* its control plane (CM). Lets the service serve requests on restart before
|
|
4
|
+
* the first sync completes, and means BP services NEVER share CM's bp-config.yaml
|
|
5
|
+
* - they hold their own cached projection of just the slice the CP sent them.
|
|
6
|
+
*
|
|
7
|
+
* Default file backend; will become pluggable (redis/psql) - keep this surface
|
|
8
|
+
* narrow so other backends slot in with `read()` / `write()`.
|
|
9
|
+
*/
|
|
10
|
+
export interface ScopedConfigCacheOptions {
|
|
11
|
+
filePath: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class ScopedConfigCache {
|
|
14
|
+
private cache;
|
|
15
|
+
private readonly filePath;
|
|
16
|
+
constructor(options: ScopedConfigCacheOptions);
|
|
17
|
+
read(): unknown | null;
|
|
18
|
+
write(scopedConfig: unknown): void;
|
|
19
|
+
clear(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=scopedConfigCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopedConfigCache.d.ts","sourceRoot":"","sources":["../src/scopedConfigCache.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,EAAE,wBAAwB;IAI7C,IAAI,IAAI,OAAO,GAAG,IAAI;IAYtB,KAAK,CAAC,YAAY,EAAE,OAAO,GAAG,IAAI;IAMlC,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
export class ScopedConfigCache {
|
|
4
|
+
cache = null;
|
|
5
|
+
filePath;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.filePath = resolve(options.filePath);
|
|
8
|
+
}
|
|
9
|
+
read() {
|
|
10
|
+
if (this.cache !== null)
|
|
11
|
+
return this.cache;
|
|
12
|
+
if (!existsSync(this.filePath))
|
|
13
|
+
return null;
|
|
14
|
+
try {
|
|
15
|
+
const raw = readFileSync(this.filePath, "utf8");
|
|
16
|
+
this.cache = JSON.parse(raw);
|
|
17
|
+
return this.cache;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
write(scopedConfig) {
|
|
24
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
25
|
+
writeFileSync(this.filePath, JSON.stringify(scopedConfig, null, 2), { mode: 0o600 });
|
|
26
|
+
this.cache = scopedConfig;
|
|
27
|
+
}
|
|
28
|
+
clear() {
|
|
29
|
+
this.cache = null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=scopedConfigCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopedConfigCache.js","sourceRoot":"","sources":["../src/scopedConfigCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAe7C,MAAM,OAAO,iBAAiB;IACpB,KAAK,GAAY,IAAI,CAAC;IACb,QAAQ,CAAS;IAElC,YAAY,OAAiC;QAC3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QAC3C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAChD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAqB;QACzB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACrF,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC;IAC5B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;CACF"}
|
package/lib/service.d.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { BSBService, type BSBServiceConstructor, type BSBEventSchemas, type BSBPluginConfig, type BSBReferencePluginConfigType, type Observable } from "@bsb/base";
|
|
2
|
+
import * as av from "anyvali";
|
|
3
|
+
import { type Server } from "node:http";
|
|
4
|
+
import { type AppAuthConfig, type BetterPortalResolvedRequestContext, type BetterPortalObservability, type BetterPortalRegistry, type JwtVerifier, type ManifestBaseFields, type PluginManifest, type BetterPortalConfig as PlatformConfig, type ServiceConfigAction, type ServiceConfigStore, type ServiceConfigTicketClaims, type RouteHandlerContext, type TenantAppValidation } from "@betterportal/framework";
|
|
5
|
+
import { BootstrapStateStore } from "./bootstrapState.js";
|
|
6
|
+
import { type BetterPortalEvent, type BetterPortalH3App } from "@betterportal/framework/lib/runtime/h3.js";
|
|
7
|
+
export interface BPServiceConfig {
|
|
8
|
+
host: string;
|
|
9
|
+
port: number;
|
|
10
|
+
betterportal?: BetterPortalConfig;
|
|
11
|
+
bpConfigPath?: string;
|
|
12
|
+
configApiToken?: string;
|
|
13
|
+
configEncryptionKey?: string;
|
|
14
|
+
controlPlaneUrl?: string;
|
|
15
|
+
serviceApiKey?: string;
|
|
16
|
+
bootstrapStatePath?: string;
|
|
17
|
+
trustedProxyHeaders?: boolean;
|
|
18
|
+
cfProxy?: boolean;
|
|
19
|
+
trustedProxyIps?: string[];
|
|
20
|
+
}
|
|
21
|
+
type BPServicePluginConfig = BSBPluginConfig<av.BaseSchema<unknown, BPServiceConfig>>;
|
|
22
|
+
export interface BetterPortalConfig {
|
|
23
|
+
bpConfigPath?: string;
|
|
24
|
+
configApiToken?: string;
|
|
25
|
+
configEncryptionKey?: string;
|
|
26
|
+
controlPlaneUrl?: string;
|
|
27
|
+
serviceApiKey?: string;
|
|
28
|
+
bootstrapStatePath?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Local cache of the scoped platform config delivered by the CP. Persisted
|
|
31
|
+
* on each sync so the service can serve requests immediately on restart,
|
|
32
|
+
* without sharing CM's source-of-truth bp-config.yaml. Default is per-service.
|
|
33
|
+
*/
|
|
34
|
+
scopedConfigCachePath?: string;
|
|
35
|
+
trustedProxyHeaders?: boolean;
|
|
36
|
+
cfProxy?: boolean;
|
|
37
|
+
trustedProxyIps?: string[];
|
|
38
|
+
}
|
|
39
|
+
export declare const BetterPortalConfigSchema: av.OptionalSchema<av.ObjectSchema<{
|
|
40
|
+
bpConfigPath: av.OptionalSchema<av.StringSchema>;
|
|
41
|
+
configApiToken: av.OptionalSchema<av.StringSchema>;
|
|
42
|
+
configEncryptionKey: av.OptionalSchema<av.StringSchema>;
|
|
43
|
+
controlPlaneUrl: av.OptionalSchema<av.StringSchema>;
|
|
44
|
+
serviceApiKey: av.OptionalSchema<av.StringSchema>;
|
|
45
|
+
bootstrapStatePath: av.StringSchema;
|
|
46
|
+
scopedConfigCachePath: av.StringSchema;
|
|
47
|
+
trustedProxyHeaders: av.BoolSchema;
|
|
48
|
+
cfProxy: av.BoolSchema;
|
|
49
|
+
trustedProxyIps: av.ArraySchema<av.StringSchema>;
|
|
50
|
+
}>>;
|
|
51
|
+
export interface BPServiceDefinition {
|
|
52
|
+
manifest: ManifestBaseFields;
|
|
53
|
+
registry: BetterPortalRegistry;
|
|
54
|
+
}
|
|
55
|
+
export declare abstract class BPService<TConfig extends BSBReferencePluginConfigType & BPServicePluginConfig = BPServicePluginConfig, TEvents extends BSBEventSchemas = BSBEventSchemas> extends BSBService<TConfig, TEvents> {
|
|
56
|
+
private get service();
|
|
57
|
+
protected get bp(): BetterPortalConfig;
|
|
58
|
+
/**
|
|
59
|
+
* Resolve header-trust options for a request. Proxy-supplied host headers are
|
|
60
|
+
* only honoured when the request's direct socket peer IP is in the configured
|
|
61
|
+
* `trustedProxyIps` allowlist - otherwise an attacker connecting directly
|
|
62
|
+
* could spoof X-Forwarded-Host/Forwarded/CF-* to impersonate another tenant.
|
|
63
|
+
*/
|
|
64
|
+
protected headerTrustOptions(event: BetterPortalEvent): {
|
|
65
|
+
trustedProxyHeaders?: boolean;
|
|
66
|
+
cfProxy?: boolean;
|
|
67
|
+
};
|
|
68
|
+
readonly initBeforePlugins: string[];
|
|
69
|
+
readonly initAfterPlugins: string[];
|
|
70
|
+
readonly runBeforePlugins: string[];
|
|
71
|
+
readonly runAfterPlugins: string[];
|
|
72
|
+
protected readonly requireBetterPortalConfigSource: boolean;
|
|
73
|
+
protected app: BetterPortalH3App;
|
|
74
|
+
protected server: Server;
|
|
75
|
+
protected observability: BetterPortalObservability;
|
|
76
|
+
protected manifest: PluginManifest;
|
|
77
|
+
protected configStore: ServiceConfigStore;
|
|
78
|
+
private runtimeConfigEncryptionKey;
|
|
79
|
+
private configProvider;
|
|
80
|
+
private scopedConfig;
|
|
81
|
+
private scopedConfigCache;
|
|
82
|
+
private sseAbortController;
|
|
83
|
+
protected bootstrapState: BootstrapStateStore;
|
|
84
|
+
/**
|
|
85
|
+
* Synthesize a BetterPortalConfig-shaped view from the synced scoped config.
|
|
86
|
+
* Lets services that need the full-portal-config API (e.g. themes for
|
|
87
|
+
* `resolveThemeRequestContext` / `resolveServiceForTenant`) operate without
|
|
88
|
+
* sharing CM's bp-config.yaml. Returns null until the first sync completes.
|
|
89
|
+
*/
|
|
90
|
+
protected getPortalConfig(): PlatformConfig | null;
|
|
91
|
+
private resolvedApiKey;
|
|
92
|
+
private resolvedCpUrl;
|
|
93
|
+
private inSetupMode;
|
|
94
|
+
protected abstract definition(): BPServiceDefinition;
|
|
95
|
+
protected onRegistered?(registry: BetterPortalRegistry, obs: Observable): void | Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Override to provide a JWT verifier for incoming requests.
|
|
98
|
+
* Receives the resolved tenant/app context. Return undefined to skip auth for the request.
|
|
99
|
+
*/
|
|
100
|
+
protected getJwtVerifier(_tenantId: string, _appId: string): JwtVerifier | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Override to provide the app's resolved auth config (roles[], expectedIssuer, etc).
|
|
103
|
+
* Default: reads from scopedConfig synced from the control plane.
|
|
104
|
+
*/
|
|
105
|
+
protected getAppAuthConfig(tenantId: string, appId: string): AppAuthConfig | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Override to provide the service-instance-id -> pluginId alias map used by the
|
|
108
|
+
* permission check (role grants use instance ids, route auth uses pluginIds).
|
|
109
|
+
* Default: reads the tenant's service bindings from scopedConfig.
|
|
110
|
+
*/
|
|
111
|
+
protected getServiceIdAliases(tenantId: string): Record<string, string> | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Override to validate that a given (tenantId, appId) is allowed to consume this service.
|
|
114
|
+
*
|
|
115
|
+
* Default behavior: auto-single-tenant via lock. On first request from a tenant, the
|
|
116
|
+
* tenant is stored as the lock. Subsequent requests from other tenants are blocked
|
|
117
|
+
* with 426 Upgrade Required. Services wanting shared/multi-tenant behavior must override.
|
|
118
|
+
*/
|
|
119
|
+
protected validateTenantApp(tenantId: string, _appId: string): Promise<TenantAppValidation>;
|
|
120
|
+
/**
|
|
121
|
+
* Register this service as an auth provider by exposing a JWKS endpoint.
|
|
122
|
+
*
|
|
123
|
+
* Mounts `GET /.well-known/jwks.json` returning the supplied JWK set.
|
|
124
|
+
* Call this from `init()` AFTER `super.init()` so the H3 app exists.
|
|
125
|
+
*/
|
|
126
|
+
/** JWKS published by this service when it acts as an auth provider; sent
|
|
127
|
+
* to the CP at /redeem so verifiers can use static keys (no network fetch). */
|
|
128
|
+
private publishedJwks;
|
|
129
|
+
protected registerAsAuthProvider(input: {
|
|
130
|
+
jwks: {
|
|
131
|
+
keys: ReadonlyArray<Record<string, unknown>>;
|
|
132
|
+
};
|
|
133
|
+
cacheMaxAgeSeconds?: number;
|
|
134
|
+
}): void;
|
|
135
|
+
constructor(cfg: BSBServiceConstructor<TConfig, TEvents>);
|
|
136
|
+
init(obs: Observable): Promise<void>;
|
|
137
|
+
run(obs: Observable): Promise<void>;
|
|
138
|
+
dispose(): Promise<void>;
|
|
139
|
+
private connectToControlPlane;
|
|
140
|
+
private logScopedConfigDebug;
|
|
141
|
+
protected resolveCorsContext(event: BetterPortalEvent): Promise<BetterPortalResolvedRequestContext | null>;
|
|
142
|
+
private resolveAuthForRequest;
|
|
143
|
+
private handleWithCors;
|
|
144
|
+
private isPublicBpDiscoveryPath;
|
|
145
|
+
private isConfigManagementPath;
|
|
146
|
+
private managementOrigins;
|
|
147
|
+
private resolveFromScopedConfig;
|
|
148
|
+
protected applyRequestContext(event: BetterPortalEvent, context: BetterPortalResolvedRequestContext): void;
|
|
149
|
+
protected resolveHandlerContext(event: BetterPortalEvent): Partial<RouteHandlerContext>;
|
|
150
|
+
private emitWebhook;
|
|
151
|
+
private effectiveServiceConfig;
|
|
152
|
+
private internalConfigReadTicket;
|
|
153
|
+
protected describeCorsContextFailure(event: BetterPortalEvent): Promise<{
|
|
154
|
+
candidateHosts: string;
|
|
155
|
+
configuredAppHosts: string;
|
|
156
|
+
} | undefined>;
|
|
157
|
+
private logContextResolutionFailure;
|
|
158
|
+
/**
|
|
159
|
+
* Resolve API key + CP URL using the 3-layer chain:
|
|
160
|
+
* 1. Bootstrap state store (default)
|
|
161
|
+
* 2. sec-config (this.bp.serviceApiKey + this.bp.controlPlaneUrl)
|
|
162
|
+
* 3. Process env BP_SERVICE_API_KEY + BP_CONTROL_PLANE_URL (arg layer)
|
|
163
|
+
* If none yield credentials, enter setup mode.
|
|
164
|
+
*/
|
|
165
|
+
private resolveCredentials;
|
|
166
|
+
private validateBetterPortalConfig;
|
|
167
|
+
private requireTenantConfigSource;
|
|
168
|
+
private resolveConfigEncryptionKey;
|
|
169
|
+
private isPreSyncCorePath;
|
|
170
|
+
private renderHealth;
|
|
171
|
+
/**
|
|
172
|
+
* Mounts POST /.well-known/bp/install - the browser-driven service installer.
|
|
173
|
+
* Caller posts { setupToken, cpUrl }. Service fetches CP JWKS, verifies the
|
|
174
|
+
* setup token, then redeems it for the real apiKey via CP /services/redeem.
|
|
175
|
+
* Persists credentials and starts CP sync.
|
|
176
|
+
*/
|
|
177
|
+
private registerInstallEndpoint;
|
|
178
|
+
private serviceConfigStorePath;
|
|
179
|
+
private deriveOwnUrl;
|
|
180
|
+
private registerDefaultConfigRoutes;
|
|
181
|
+
protected validateConfigScope(tenantId: string, appId?: string): Promise<boolean>;
|
|
182
|
+
/**
|
|
183
|
+
* Validate a service-config ticket. Primary path: verify a CP-signed RS256
|
|
184
|
+
* ticket against the CP JWKS learned at install/redeem - there is no shared
|
|
185
|
+
* secret and only the CP can mint tickets. Before install (no cpJwksUri yet)
|
|
186
|
+
* the service fails closed: config endpoints reject every request until it has
|
|
187
|
+
* been provisioned.
|
|
188
|
+
*/
|
|
189
|
+
protected validateConfigTicket(ticketValue: string | null, event: BetterPortalEvent, action: ServiceConfigAction): Promise<ServiceConfigTicketClaims | null>;
|
|
190
|
+
/**
|
|
191
|
+
* Static shared-secret fallback for LOCAL DEVELOPMENT ONLY. Disabled unless
|
|
192
|
+
* BP_ALLOW_DEV_CONFIG_TOKEN=true AND configApiToken is explicitly set. It
|
|
193
|
+
* trusts the x-bp-tenant-id header to choose the tenant, so it must never be
|
|
194
|
+
* enabled in production.
|
|
195
|
+
*/
|
|
196
|
+
private validateDevConfigToken;
|
|
197
|
+
}
|
|
198
|
+
export {};
|
|
199
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|