@reproapp/node-sdk 0.0.42 → 0.0.44
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 +4 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +45 -0
- package/dist/privacy.d.ts +1 -0
- package/dist/privacy.js +7 -1
- package/package.json +2 -2
- package/src/index.ts +53 -0
- package/src/privacy.ts +8 -1
- package/test/privacy-service-scope.test.js +56 -0
- package/test/runtime-service-registration.test.js +80 -0
package/README.md
CHANGED
|
@@ -194,10 +194,11 @@ type ReproInitConfig = {
|
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
Important options:
|
|
197
|
-
- `tenantId`, `appId`, `appSecret`: Repro
|
|
198
|
-
- `appName`:
|
|
197
|
+
- `tenantId`, `appId`, `appSecret`: Repro application credentials.
|
|
198
|
+
- `appName`: Application label sent as `X-App-Name`.
|
|
199
199
|
- `serviceName`: Backend service label stored on request, trace, DB, queue, Redis,
|
|
200
|
-
and email events.
|
|
200
|
+
and email events. The SDK also registers this service with the application in
|
|
201
|
+
the background so admins can see its environments and privacy policy status.
|
|
201
202
|
- `apiBase`: Repro API base URL. Used by backend live sessions and privacy policy fetches.
|
|
202
203
|
- `captureHeaders`: Enables header capture. Sensitive headers are masked unless
|
|
203
204
|
explicitly unmasked.
|
package/dist/index.d.ts
CHANGED
|
@@ -292,6 +292,7 @@ type BackendLiveTimingConfig = {
|
|
|
292
292
|
segmentMaxDurationMs: number;
|
|
293
293
|
segmentIdleMs: number;
|
|
294
294
|
};
|
|
295
|
+
declare function registerRuntimeService(cfg: ReproMiddlewareConfig): Promise<void>;
|
|
295
296
|
declare function sanitizeTraceValueForPrivacy(value: any): any;
|
|
296
297
|
declare function sanitizeMaterializedTraceValue(value: any): any;
|
|
297
298
|
export declare function __materializePendingTraceEventsForWorker(payload: TraceMaterializationWorkerPayload): Promise<PendingTraceEventRecord[]>;
|
|
@@ -458,6 +459,7 @@ export declare const __reproTestHooks: {
|
|
|
458
459
|
}): void;
|
|
459
460
|
drainSdkBackgroundQueueForTest(): Promise<void>;
|
|
460
461
|
resetSdkBackgroundQueuesForTest(): void;
|
|
462
|
+
registerRuntimeServiceForTest: typeof registerRuntimeService;
|
|
461
463
|
setBackendLiveTimingForTest(override: Partial<BackendLiveTimingConfig> | null): void;
|
|
462
464
|
runWithRequestContextForTest<T>(ctx: Partial<Ctx>, fn: () => T): T;
|
|
463
465
|
getNativeMongoSuppressionCountForTest(): number;
|
package/dist/index.js
CHANGED
|
@@ -1813,6 +1813,47 @@ async function postLiveApiJson(cfg, liveMode, path, body) {
|
|
|
1813
1813
|
return null;
|
|
1814
1814
|
}
|
|
1815
1815
|
}
|
|
1816
|
+
async function registerRuntimeService(cfg) {
|
|
1817
|
+
const serviceName = typeof cfg.serviceName === 'string' ? cfg.serviceName.trim() : '';
|
|
1818
|
+
const apiBase = resolveLiveApiBase(cfg, normalizeLiveModeConfig(cfg));
|
|
1819
|
+
const fetchImpl = globalThis.fetch;
|
|
1820
|
+
if (!serviceName ||
|
|
1821
|
+
!apiBase ||
|
|
1822
|
+
!cfg.appId ||
|
|
1823
|
+
!cfg.appSecret ||
|
|
1824
|
+
typeof fetchImpl !== 'function') {
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
const controller = typeof AbortController === 'function' ? new AbortController() : null;
|
|
1828
|
+
const timeout = setTimeout(() => controller?.abort(), 2500);
|
|
1829
|
+
try {
|
|
1830
|
+
timeout.unref?.();
|
|
1831
|
+
}
|
|
1832
|
+
catch { }
|
|
1833
|
+
try {
|
|
1834
|
+
await fetchImpl(`${apiBase}/v1/sdk/runtime-services`, {
|
|
1835
|
+
method: 'POST',
|
|
1836
|
+
headers: liveApiHeaders(cfg),
|
|
1837
|
+
body: JSON.stringify({
|
|
1838
|
+
serviceName,
|
|
1839
|
+
environment: (0, privacy_1.normalizePrivacyEnvironment)(cfg.privacy?.environment),
|
|
1840
|
+
}),
|
|
1841
|
+
...(controller ? { signal: controller.signal } : {}),
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
catch {
|
|
1845
|
+
// Service discovery is best-effort and must never affect host startup.
|
|
1846
|
+
}
|
|
1847
|
+
finally {
|
|
1848
|
+
try {
|
|
1849
|
+
clearTimeout(timeout);
|
|
1850
|
+
}
|
|
1851
|
+
catch { }
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
function enqueueRuntimeServiceRegistration(cfg) {
|
|
1855
|
+
scheduleSdkBackgroundWork(() => registerRuntimeService(cfg));
|
|
1856
|
+
}
|
|
1816
1857
|
function enqueueLiveSessionStart(cfg, liveMode, payload) {
|
|
1817
1858
|
scheduleSdkBackgroundWork(() => postLiveApi(cfg, liveMode, '/v1/live-sessions', payload), { priority: 'high' });
|
|
1818
1859
|
}
|
|
@@ -3190,6 +3231,7 @@ async function ensureRuntimePrivacyPolicyLoaded(cfg) {
|
|
|
3190
3231
|
appId: cfg.appId,
|
|
3191
3232
|
appSecret: cfg.appSecret,
|
|
3192
3233
|
appName: cfg.appName,
|
|
3234
|
+
serviceName: cfg.serviceName,
|
|
3193
3235
|
apiBase,
|
|
3194
3236
|
environment: state.environment,
|
|
3195
3237
|
fetchTimeoutMs: privacy?.fetchTimeoutMs,
|
|
@@ -3231,6 +3273,7 @@ async function initializeRuntimePrivacyPolicyAtStartup(cfg) {
|
|
|
3231
3273
|
appId: cfg.appId,
|
|
3232
3274
|
appSecret: cfg.appSecret,
|
|
3233
3275
|
appName: cfg.appName,
|
|
3276
|
+
serviceName: cfg.serviceName,
|
|
3234
3277
|
apiBase,
|
|
3235
3278
|
environment: state.environment,
|
|
3236
3279
|
fetchTimeoutMs: privacy?.fetchTimeoutMs,
|
|
@@ -9835,6 +9878,7 @@ async function initRepro(cfg) {
|
|
|
9835
9878
|
await installMongoDbImportHook();
|
|
9836
9879
|
patchSendgridMail(integrationCfg);
|
|
9837
9880
|
patchMongooseIntegration(reproAutoMiddlewareConfig);
|
|
9881
|
+
enqueueRuntimeServiceRegistration(reproAutoMiddlewareConfig);
|
|
9838
9882
|
await initializeRuntimePrivacyPolicyAtStartup(reproAutoMiddlewareConfig);
|
|
9839
9883
|
}
|
|
9840
9884
|
exports.initRepro = initRepro;
|
|
@@ -9866,6 +9910,7 @@ exports.__reproTestHooks = {
|
|
|
9866
9910
|
lastClientActivityAt = 0;
|
|
9867
9911
|
sdkBackgroundQuietUntil = 0;
|
|
9868
9912
|
},
|
|
9913
|
+
registerRuntimeServiceForTest: registerRuntimeService,
|
|
9869
9914
|
setBackendLiveTimingForTest(override) {
|
|
9870
9915
|
backendLiveTimingOverrideForTest = override;
|
|
9871
9916
|
},
|
package/dist/privacy.d.ts
CHANGED
package/dist/privacy.js
CHANGED
|
@@ -104,7 +104,13 @@ async function fetchApprovedRuntimePrivacyPolicy(params) {
|
|
|
104
104
|
reason: !params.apiBase ? 'missing_config' : 'missing_credentials',
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
|
-
const
|
|
107
|
+
const query = new URLSearchParams({
|
|
108
|
+
environment: params.environment,
|
|
109
|
+
});
|
|
110
|
+
if (typeof params.serviceName === 'string' && params.serviceName.trim()) {
|
|
111
|
+
query.set('serviceName', params.serviceName.trim());
|
|
112
|
+
}
|
|
113
|
+
const url = `${params.apiBase}/v1/sdk/privacy-policy?${query.toString()}`;
|
|
108
114
|
const headers = {
|
|
109
115
|
accept: 'application/json',
|
|
110
116
|
'x-app-id': params.appId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reproapp/node-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.44",
|
|
4
4
|
"description": "Repro Nest SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"build": "tsc -p tsconfig.json",
|
|
13
13
|
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
|
|
14
14
|
"prepublishOnly": "npm run build",
|
|
15
|
-
"test": "npm run build && node test/unawaited.test.js && node test/integration-unawaited.js && node test/request-flush-timing.test.js && node test/request-capture-background.test.js && node test/init-auto-http-server.test.js && node test/backend-live-mode.test.js && node test/client-performance-regression.test.js && node test/request-manifest-priority.test.js && node test/runtime-no-double-invoke.test.js && node test/express-trace-http-args.test.js && node test/trace-batch-size.test.js && node test/sdk-background-priority.test.js && node test/ingest-queue-retention.test.js && node test/ingest-high-priority-retention.test.js && node test/ingest-critical-retention.test.js && node test/ingest-critical-retry-retention.test.js && node test/ingest-batching.test.js && node test/ingest-timeout.test.js && node -r ./tracer/register test/promise-map.test.js && node test/disable-subtree.test.js && node test/circular-capture.test.js && node test/wrap-plugin-arrow-args.test.js && node test/wrap-plugin-super-call.test.js && node test/function-arg-identity.test.js && node test/privacy-runtime-policy.test.js && node test/runtime-privacy-materialization.test.js && node test/kafka-runtime-privacy-policy.test.js && node test/amqplib-integration.test.js && node test/mongodb-integration.test.js && node test/mongodb-esm-import-hook.test.js && node test/mongodb-suppression-cleanup.test.js && node test/postgresql-integration.test.js",
|
|
15
|
+
"test": "npm run build && node test/unawaited.test.js && node test/integration-unawaited.js && node test/request-flush-timing.test.js && node test/request-capture-background.test.js && node test/init-auto-http-server.test.js && node test/backend-live-mode.test.js && node test/client-performance-regression.test.js && node test/request-manifest-priority.test.js && node test/runtime-no-double-invoke.test.js && node test/express-trace-http-args.test.js && node test/trace-batch-size.test.js && node test/sdk-background-priority.test.js && node test/runtime-service-registration.test.js && node test/ingest-queue-retention.test.js && node test/ingest-high-priority-retention.test.js && node test/ingest-critical-retention.test.js && node test/ingest-critical-retry-retention.test.js && node test/ingest-batching.test.js && node test/ingest-timeout.test.js && node -r ./tracer/register test/promise-map.test.js && node test/disable-subtree.test.js && node test/circular-capture.test.js && node test/wrap-plugin-arrow-args.test.js && node test/wrap-plugin-super-call.test.js && node test/function-arg-identity.test.js && node test/privacy-service-scope.test.js && node test/privacy-runtime-policy.test.js && node test/runtime-privacy-materialization.test.js && node test/kafka-runtime-privacy-policy.test.js && node test/amqplib-integration.test.js && node test/mongodb-integration.test.js && node test/mongodb-esm-import-hook.test.js && node test/mongodb-suppression-cleanup.test.js && node test/postgresql-integration.test.js",
|
|
16
16
|
"test:containers": "npm run build && node test/runtime-no-double-invoke.testcontainers.test.js && node test/wrap-plugin-super-call.testcontainers.test.js && node test/function-arg-identity.testcontainers.test.js && node test/mongodb-mongoose-native-suppression.testcontainers.test.js && node test/postgresql-integrations.testcontainers.test.js"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -2250,6 +2250,55 @@ async function postLiveApiJson<T = Record<string, any>>(
|
|
|
2250
2250
|
}
|
|
2251
2251
|
}
|
|
2252
2252
|
|
|
2253
|
+
async function registerRuntimeService(
|
|
2254
|
+
cfg: ReproMiddlewareConfig,
|
|
2255
|
+
): Promise<void> {
|
|
2256
|
+
const serviceName =
|
|
2257
|
+
typeof cfg.serviceName === 'string' ? cfg.serviceName.trim() : '';
|
|
2258
|
+
const apiBase = resolveLiveApiBase(cfg, normalizeLiveModeConfig(cfg));
|
|
2259
|
+
const fetchImpl = (globalThis as any).fetch;
|
|
2260
|
+
if (
|
|
2261
|
+
!serviceName ||
|
|
2262
|
+
!apiBase ||
|
|
2263
|
+
!cfg.appId ||
|
|
2264
|
+
!cfg.appSecret ||
|
|
2265
|
+
typeof fetchImpl !== 'function'
|
|
2266
|
+
) {
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
const controller =
|
|
2271
|
+
typeof AbortController === 'function' ? new AbortController() : null;
|
|
2272
|
+
const timeout = setTimeout(() => controller?.abort(), 2_500);
|
|
2273
|
+
try {
|
|
2274
|
+
timeout.unref?.();
|
|
2275
|
+
} catch {}
|
|
2276
|
+
|
|
2277
|
+
try {
|
|
2278
|
+
await fetchImpl(`${apiBase}/v1/sdk/runtime-services`, {
|
|
2279
|
+
method: 'POST',
|
|
2280
|
+
headers: liveApiHeaders(cfg),
|
|
2281
|
+
body: JSON.stringify({
|
|
2282
|
+
serviceName,
|
|
2283
|
+
environment: normalizePrivacyEnvironment(
|
|
2284
|
+
cfg.privacy?.environment,
|
|
2285
|
+
),
|
|
2286
|
+
}),
|
|
2287
|
+
...(controller ? { signal: controller.signal } : {}),
|
|
2288
|
+
});
|
|
2289
|
+
} catch {
|
|
2290
|
+
// Service discovery is best-effort and must never affect host startup.
|
|
2291
|
+
} finally {
|
|
2292
|
+
try {
|
|
2293
|
+
clearTimeout(timeout);
|
|
2294
|
+
} catch {}
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
function enqueueRuntimeServiceRegistration(cfg: ReproMiddlewareConfig): void {
|
|
2299
|
+
scheduleSdkBackgroundWork(() => registerRuntimeService(cfg));
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2253
2302
|
function enqueueLiveSessionStart(
|
|
2254
2303
|
cfg: ReproMiddlewareConfig,
|
|
2255
2304
|
liveMode: ReproLiveModeConfig | null,
|
|
@@ -3844,6 +3893,7 @@ async function ensureRuntimePrivacyPolicyLoaded(cfg: ReproMiddlewareConfig): Pro
|
|
|
3844
3893
|
appId: cfg.appId,
|
|
3845
3894
|
appSecret: cfg.appSecret,
|
|
3846
3895
|
appName: cfg.appName,
|
|
3896
|
+
serviceName: cfg.serviceName,
|
|
3847
3897
|
apiBase,
|
|
3848
3898
|
environment: state.environment,
|
|
3849
3899
|
fetchTimeoutMs: privacy?.fetchTimeoutMs,
|
|
@@ -3894,6 +3944,7 @@ async function initializeRuntimePrivacyPolicyAtStartup(cfg: ReproMiddlewareConfi
|
|
|
3894
3944
|
appId: cfg.appId,
|
|
3895
3945
|
appSecret: cfg.appSecret,
|
|
3896
3946
|
appName: cfg.appName,
|
|
3947
|
+
serviceName: cfg.serviceName,
|
|
3897
3948
|
apiBase,
|
|
3898
3949
|
environment: state.environment,
|
|
3899
3950
|
fetchTimeoutMs: privacy?.fetchTimeoutMs,
|
|
@@ -11365,6 +11416,7 @@ export async function initRepro(cfg: ReproInitConfig): Promise<void> {
|
|
|
11365
11416
|
patchSendgridMail(integrationCfg);
|
|
11366
11417
|
patchMongooseIntegration(reproAutoMiddlewareConfig);
|
|
11367
11418
|
|
|
11419
|
+
enqueueRuntimeServiceRegistration(reproAutoMiddlewareConfig);
|
|
11368
11420
|
await initializeRuntimePrivacyPolicyAtStartup(reproAutoMiddlewareConfig);
|
|
11369
11421
|
}
|
|
11370
11422
|
|
|
@@ -11396,6 +11448,7 @@ export const __reproTestHooks = {
|
|
|
11396
11448
|
lastClientActivityAt = 0;
|
|
11397
11449
|
sdkBackgroundQuietUntil = 0;
|
|
11398
11450
|
},
|
|
11451
|
+
registerRuntimeServiceForTest: registerRuntimeService,
|
|
11399
11452
|
setBackendLiveTimingForTest(override: Partial<BackendLiveTimingConfig> | null): void {
|
|
11400
11453
|
backendLiveTimingOverrideForTest = override;
|
|
11401
11454
|
},
|
package/src/privacy.ts
CHANGED
|
@@ -230,6 +230,7 @@ export async function fetchApprovedRuntimePrivacyPolicy(params: {
|
|
|
230
230
|
appId: string;
|
|
231
231
|
appSecret?: string;
|
|
232
232
|
appName?: string;
|
|
233
|
+
serviceName?: string;
|
|
233
234
|
apiBase: string;
|
|
234
235
|
environment: string;
|
|
235
236
|
fetchTimeoutMs?: number;
|
|
@@ -240,7 +241,13 @@ export async function fetchApprovedRuntimePrivacyPolicy(params: {
|
|
|
240
241
|
reason: !params.apiBase ? 'missing_config' : 'missing_credentials',
|
|
241
242
|
};
|
|
242
243
|
}
|
|
243
|
-
const
|
|
244
|
+
const query = new URLSearchParams({
|
|
245
|
+
environment: params.environment,
|
|
246
|
+
});
|
|
247
|
+
if (typeof params.serviceName === 'string' && params.serviceName.trim()) {
|
|
248
|
+
query.set('serviceName', params.serviceName.trim());
|
|
249
|
+
}
|
|
250
|
+
const url = `${params.apiBase}/v1/sdk/privacy-policy?${query.toString()}`;
|
|
244
251
|
const headers: Record<string, string> = {
|
|
245
252
|
accept: 'application/json',
|
|
246
253
|
'x-app-id': params.appId,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const assert = require('node:assert');
|
|
4
|
+
const {
|
|
5
|
+
fetchApprovedRuntimePrivacyPolicy,
|
|
6
|
+
} = require('../dist/privacy.js');
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
const originalFetch = global.fetch;
|
|
10
|
+
const calls = [];
|
|
11
|
+
global.fetch = async (url, init) => {
|
|
12
|
+
calls.push({ url: String(url), init });
|
|
13
|
+
return {
|
|
14
|
+
ok: true,
|
|
15
|
+
json: async () => ({ enabled: false }),
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
await fetchApprovedRuntimePrivacyPolicy({
|
|
21
|
+
appId: 'APP_shared',
|
|
22
|
+
appSecret: 'secret',
|
|
23
|
+
appName: 'Shared app',
|
|
24
|
+
serviceName: ' Orders API ',
|
|
25
|
+
apiBase: 'https://repro.example/api',
|
|
26
|
+
environment: 'prod',
|
|
27
|
+
});
|
|
28
|
+
await fetchApprovedRuntimePrivacyPolicy({
|
|
29
|
+
appId: 'APP_shared',
|
|
30
|
+
appSecret: 'secret',
|
|
31
|
+
apiBase: 'https://repro.example/api',
|
|
32
|
+
environment: 'dev',
|
|
33
|
+
});
|
|
34
|
+
} finally {
|
|
35
|
+
global.fetch = originalFetch;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
assert.strictEqual(calls.length, 2);
|
|
39
|
+
const serviceUrl = new URL(calls[0].url);
|
|
40
|
+
assert.strictEqual(serviceUrl.pathname, '/api/v1/sdk/privacy-policy');
|
|
41
|
+
assert.strictEqual(serviceUrl.searchParams.get('environment'), 'prod');
|
|
42
|
+
assert.strictEqual(serviceUrl.searchParams.get('serviceName'), 'Orders API');
|
|
43
|
+
assert.strictEqual(calls[0].init.headers['x-app-id'], 'APP_shared');
|
|
44
|
+
assert.strictEqual(calls[0].init.headers['x-app-secret'], 'secret');
|
|
45
|
+
|
|
46
|
+
const appWideUrl = new URL(calls[1].url);
|
|
47
|
+
assert.strictEqual(appWideUrl.searchParams.get('environment'), 'dev');
|
|
48
|
+
assert.strictEqual(appWideUrl.searchParams.has('serviceName'), false);
|
|
49
|
+
|
|
50
|
+
console.log('runtime privacy service scope OK');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
main().catch((error) => {
|
|
54
|
+
console.error(error);
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const assert = require('node:assert/strict');
|
|
4
|
+
|
|
5
|
+
const { __reproTestHooks } = require('../dist');
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
const originalFetch = global.fetch;
|
|
9
|
+
const calls = [];
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
global.fetch = async (url, options) => {
|
|
13
|
+
calls.push({ url: String(url), options });
|
|
14
|
+
return { ok: true };
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
await __reproTestHooks.registerRuntimeServiceForTest({
|
|
18
|
+
tenantId: 'TENANT_test',
|
|
19
|
+
appId: 'APP_test',
|
|
20
|
+
appSecret: 'secret',
|
|
21
|
+
appName: 'Acme',
|
|
22
|
+
serviceName: ' orders-api ',
|
|
23
|
+
apiBase: 'http://repro-api.test/api/',
|
|
24
|
+
privacy: {
|
|
25
|
+
environment: 'production',
|
|
26
|
+
captureRaw: true,
|
|
27
|
+
},
|
|
28
|
+
ingestBase: 'http://collector.test',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
assert.equal(calls.length, 1);
|
|
32
|
+
assert.equal(
|
|
33
|
+
calls[0].url,
|
|
34
|
+
'http://repro-api.test/api/v1/sdk/runtime-services',
|
|
35
|
+
);
|
|
36
|
+
assert.equal(calls[0].options.method, 'POST');
|
|
37
|
+
assert.deepEqual(calls[0].options.headers, {
|
|
38
|
+
'Content-Type': 'application/json',
|
|
39
|
+
'X-App-Id': 'APP_test',
|
|
40
|
+
'X-App-Secret': 'secret',
|
|
41
|
+
'X-App-Name': 'Acme',
|
|
42
|
+
});
|
|
43
|
+
assert.deepEqual(JSON.parse(calls[0].options.body), {
|
|
44
|
+
serviceName: 'orders-api',
|
|
45
|
+
environment: 'prod',
|
|
46
|
+
});
|
|
47
|
+
assert.ok(calls[0].options.signal);
|
|
48
|
+
|
|
49
|
+
await __reproTestHooks.registerRuntimeServiceForTest({
|
|
50
|
+
tenantId: 'TENANT_test',
|
|
51
|
+
appId: 'APP_test',
|
|
52
|
+
appSecret: 'secret',
|
|
53
|
+
appName: 'Acme',
|
|
54
|
+
apiBase: 'http://repro-api.test/api',
|
|
55
|
+
ingestBase: 'http://collector.test',
|
|
56
|
+
});
|
|
57
|
+
assert.equal(calls.length, 1);
|
|
58
|
+
|
|
59
|
+
global.fetch = async () => {
|
|
60
|
+
throw new Error('network down');
|
|
61
|
+
};
|
|
62
|
+
await __reproTestHooks.registerRuntimeServiceForTest({
|
|
63
|
+
tenantId: 'TENANT_test',
|
|
64
|
+
appId: 'APP_test',
|
|
65
|
+
appSecret: 'secret',
|
|
66
|
+
serviceName: 'billing-api',
|
|
67
|
+
apiBase: 'http://repro-api.test/api',
|
|
68
|
+
ingestBase: 'http://collector.test',
|
|
69
|
+
});
|
|
70
|
+
} finally {
|
|
71
|
+
global.fetch = originalFetch;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log('runtime service registration OK');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
main().catch((error) => {
|
|
78
|
+
console.error(error);
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
});
|