@open-kingdom/shared-backend-integration-test-doubles 0.0.2-17 → 0.0.2-18
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 +75 -5
- package/dist/gcs/gcs-error-mode.d.ts +161 -0
- package/dist/gcs/gcs-error-mode.d.ts.map +1 -0
- package/dist/gcs/gcs-error-mode.js +256 -0
- package/dist/gcs/gcs-error-mode.js.map +1 -0
- package/dist/gcs/gcs-error-simulation.interceptor.d.ts +21 -0
- package/dist/gcs/gcs-error-simulation.interceptor.d.ts.map +1 -0
- package/dist/gcs/gcs-error-simulation.interceptor.js +40 -0
- package/dist/gcs/gcs-error-simulation.interceptor.js.map +1 -0
- package/dist/gcs/gcs-twin.d.ts +1 -0
- package/dist/gcs/gcs-twin.d.ts.map +1 -1
- package/dist/gcs/gcs-twin.js +19 -1
- package/dist/gcs/gcs-twin.js.map +1 -1
- package/dist/gcs/index.d.ts +3 -0
- package/dist/gcs/index.d.ts.map +1 -1
- package/dist/gcs/index.js +2 -0
- package/dist/gcs/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/interceptor/http-helper.d.ts +37 -0
- package/dist/interceptor/http-helper.d.ts.map +1 -0
- package/dist/interceptor/http-helper.js +109 -0
- package/dist/interceptor/http-helper.js.map +1 -0
- package/dist/interceptor/index.d.ts +4 -0
- package/dist/interceptor/index.d.ts.map +1 -0
- package/dist/interceptor/index.js +5 -0
- package/dist/interceptor/index.js.map +1 -0
- package/dist/interceptor/node-interceptor.d.ts +40 -0
- package/dist/interceptor/node-interceptor.d.ts.map +1 -0
- package/dist/interceptor/node-interceptor.js +188 -0
- package/dist/interceptor/node-interceptor.js.map +1 -0
- package/dist/interceptor/routing-table.config.d.ts +3 -0
- package/dist/interceptor/routing-table.config.d.ts.map +1 -0
- package/dist/interceptor/routing-table.config.js +25 -0
- package/dist/interceptor/routing-table.config.js.map +1 -0
- package/dist/interceptor/routing-table.d.ts +15 -0
- package/dist/interceptor/routing-table.d.ts.map +1 -0
- package/dist/interceptor/routing-table.js +44 -0
- package/dist/interceptor/routing-table.js.map +1 -0
- package/dist/shared/constants.d.ts +4 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +3 -1
- package/dist/shared/constants.js.map +1 -1
- package/dist/youtube/index.d.ts +15 -0
- package/dist/youtube/index.d.ts.map +1 -0
- package/dist/youtube/index.js +11 -0
- package/dist/youtube/index.js.map +1 -0
- package/dist/youtube/msw-handlers.d.ts +40 -0
- package/dist/youtube/msw-handlers.d.ts.map +1 -0
- package/dist/youtube/msw-handlers.js +45 -0
- package/dist/youtube/msw-handlers.js.map +1 -0
- package/dist/youtube/player-shim.d.ts +3 -0
- package/dist/youtube/player-shim.d.ts.map +1 -0
- package/dist/youtube/player-shim.js +296 -0
- package/dist/youtube/player-shim.js.map +1 -0
- package/dist/youtube/search-fixtures.d.ts +29 -0
- package/dist/youtube/search-fixtures.d.ts.map +1 -0
- package/dist/youtube/search-fixtures.js +392 -0
- package/dist/youtube/search-fixtures.js.map +1 -0
- package/dist/youtube/search-response.d.ts +51 -0
- package/dist/youtube/search-response.d.ts.map +1 -0
- package/dist/youtube/search-response.js +53 -0
- package/dist/youtube/search-response.js.map +1 -0
- package/dist/youtube/youtube-error-mode.d.ts +36 -0
- package/dist/youtube/youtube-error-mode.d.ts.map +1 -0
- package/dist/youtube/youtube-error-mode.js +87 -0
- package/dist/youtube/youtube-error-mode.js.map +1 -0
- package/dist/youtube/youtube-twin.config.d.ts +13 -0
- package/dist/youtube/youtube-twin.config.d.ts.map +1 -0
- package/dist/youtube/youtube-twin.config.js +32 -0
- package/dist/youtube/youtube-twin.config.js.map +1 -0
- package/dist/youtube/youtube-twin.d.ts +14 -0
- package/dist/youtube/youtube-twin.d.ts.map +1 -0
- package/dist/youtube/youtube-twin.js +162 -0
- package/dist/youtube/youtube-twin.js.map +1 -0
- package/package.json +15 -2
- package/test-assets/youtube/sample.mp4 +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-01.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-02.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-03.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-04.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-05.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-06.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-07.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-08.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-09.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-10.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-11.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-12.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-13.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-14.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-15.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-16.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-17.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-18.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-19.jpg +0 -0
- package/test-assets/youtube/thumbnails/thumbnail-20.jpg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/youtube/youtube-error-mode.ts"],"sourcesContent":["/**\n * YouTube error mode simulation — pure state management.\n *\n * Design follows GcsErrorModeManager conventions:\n * - Single-mode constraint: only one mode active at a time.\n * - setMode() replaces any existing mode.\n * - reset() and clearMode() clear state to prevent leakage between tests.\n */\n\n// ─── Type Definitions ────────────────────────────────────────────────\n\nexport type YoutubeApiErrorModeType =\n | 'daily-limit-exceeded'\n | 'invalid-api-key'\n | 'empty-results';\n\nexport type YoutubePlayerErrorCode = 2 | 5 | 100 | 101 | 150;\n\nexport type YoutubeErrorModeType =\n | YoutubeApiErrorModeType\n | `player-error-${YoutubePlayerErrorCode}`;\n\nexport interface YoutubeErrorModeConfig {\n type: YoutubeErrorModeType;\n}\n\nexport interface YoutubeErrorSimulationResult {\n status: number;\n body: Record<string, unknown>;\n}\n\n// ─── Error Response Factories ─────────────────────────────────────────\n\nfunction youtubeApiError(\n status: number,\n message: string,\n reason: string,\n domain = 'usageLimits'\n): YoutubeErrorSimulationResult {\n return {\n status,\n body: {\n error: {\n code: status,\n message,\n errors: [{ domain, reason, message }],\n },\n },\n };\n}\n\nfunction emptySearchResponse(): YoutubeErrorSimulationResult {\n return {\n status: 200,\n body: {\n kind: 'youtube#searchListResponse',\n etag: 'empty-etag',\n regionCode: 'US',\n pageInfo: { totalResults: 0, resultsPerPage: 0 },\n items: [],\n },\n };\n}\n\n// ─── Manager ──────────────────────────────────────────────────────────\n\nexport class YoutubeErrorModeManager {\n private activeMode: YoutubeErrorModeConfig | null = null;\n\n setMode(config: YoutubeErrorModeConfig): void {\n this.activeMode = config;\n }\n\n clearMode(): void {\n this.activeMode = null;\n }\n\n getMode(): YoutubeErrorModeConfig | null {\n return this.activeMode;\n }\n\n /**\n * Check if the current mode is a player error mode.\n * Returns the numeric error code, or null if not a player error.\n */\n getPlayerErrorCode(): number | null {\n if (!this.activeMode) return null;\n const match = this.activeMode.type.match(/^player-error-(\\d+)$/);\n return match ? parseInt(match[1], 10) : null;\n }\n\n /**\n * Match a search request against the active API error mode.\n * Returns null for pass-through (no error, or player-only mode).\n */\n matchSearchRequest(): YoutubeErrorSimulationResult | null {\n if (!this.activeMode) return null;\n\n switch (this.activeMode.type) {\n case 'daily-limit-exceeded':\n return youtubeApiError(\n 403,\n 'Daily Limit Exceeded',\n 'dailyLimitExceeded'\n );\n case 'invalid-api-key':\n return youtubeApiError(400, 'API key not valid', 'keyInvalid');\n case 'empty-results':\n return emptySearchResponse();\n default:\n // Player error modes don't affect the search endpoint\n return null;\n }\n }\n\n reset(): void {\n this.activeMode = null;\n }\n}\n"],"names":["youtubeApiError","status","message","reason","domain","body","error","code","errors","emptySearchResponse","kind","etag","regionCode","pageInfo","totalResults","resultsPerPage","items","YoutubeErrorModeManager","setMode","config","activeMode","clearMode","getMode","getPlayerErrorCode","match","type","parseInt","matchSearchRequest","reset"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;;;CAOC,GAED,wEAAwE;AAsBxE,yEAAyE;AAEzE,SAASA,gBACPC,MAAc,EACdC,OAAe,EACfC,MAAc,EACdC,SAAS,aAAa;IAEtB,OAAO;QACLH;QACAI,MAAM;YACJC,OAAO;gBACLC,MAAMN;gBACNC;gBACAM,QAAQ;oBAAC;wBAAEJ;wBAAQD;wBAAQD;oBAAQ;iBAAE;YACvC;QACF;IACF;AACF;AAEA,SAASO;IACP,OAAO;QACLR,QAAQ;QACRI,MAAM;YACJK,MAAM;YACNC,MAAM;YACNC,YAAY;YACZC,UAAU;gBAAEC,cAAc;gBAAGC,gBAAgB;YAAE;YAC/CC,OAAO,EAAE;QACX;IACF;AACF;AAEA,yEAAyE;AAEzE,OAAO,MAAMC;IAGXC,QAAQC,MAA8B,EAAQ;QAC5C,IAAI,CAACC,UAAU,GAAGD;IACpB;IAEAE,YAAkB;QAChB,IAAI,CAACD,UAAU,GAAG;IACpB;IAEAE,UAAyC;QACvC,OAAO,IAAI,CAACF,UAAU;IACxB;IAEA;;;GAGC,GACDG,qBAAoC;QAClC,IAAI,CAAC,IAAI,CAACH,UAAU,EAAE,OAAO;QAC7B,MAAMI,QAAQ,IAAI,CAACJ,UAAU,CAACK,IAAI,CAACD,KAAK,CAAC;QACzC,OAAOA,QAAQE,SAASF,KAAK,CAAC,EAAE,EAAE,MAAM;IAC1C;IAEA;;;GAGC,GACDG,qBAA0D;QACxD,IAAI,CAAC,IAAI,CAACP,UAAU,EAAE,OAAO;QAE7B,OAAQ,IAAI,CAACA,UAAU,CAACK,IAAI;YAC1B,KAAK;gBACH,OAAOzB,gBACL,KACA,wBACA;YAEJ,KAAK;gBACH,OAAOA,gBAAgB,KAAK,qBAAqB;YACnD,KAAK;gBACH,OAAOS;YACT;gBACE,sDAAsD;gBACtD,OAAO;QACX;IACF;IAEAmB,QAAc;QACZ,IAAI,CAACR,UAAU,GAAG;IACpB;;aAlDQA,aAA4C;;AAmDtD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface YoutubeTwinConfig {
|
|
2
|
+
/** Port the YouTube twin Express server listens on */
|
|
3
|
+
port: number;
|
|
4
|
+
/** External URL consumers use to reach the twin */
|
|
5
|
+
externalUrl: string;
|
|
6
|
+
/** Path to the sample video file */
|
|
7
|
+
sampleVideoPath: string;
|
|
8
|
+
/** Path to the thumbnails directory */
|
|
9
|
+
thumbnailDir: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const defaultYoutubeConfig: YoutubeTwinConfig;
|
|
12
|
+
export declare function createYoutubeConfig(overrides?: Partial<YoutubeTwinConfig>): YoutubeTwinConfig;
|
|
13
|
+
//# sourceMappingURL=youtube-twin.config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtube-twin.config.d.ts","sourceRoot":"","sources":["../../src/youtube/youtube-twin.config.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,oBAAoB,EAAE,iBAKlC,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,iBAAiB,CAAM,GACzC,iBAAiB,CA8BnB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { ConfigService, nodeEnvAdapter } from '@open-kingdom/shared-poly-util-env-config';
|
|
5
|
+
import { DEFAULT_PORTS, ENV_VARS, PORT_RANGE } from '../shared/constants.js';
|
|
6
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
// Resolved relative to dist/youtube/youtube-twin.config.js when packaged
|
|
8
|
+
const defaultAssetDir = path.resolve(currentDir, '../../test-assets/youtube');
|
|
9
|
+
export const defaultYoutubeConfig = {
|
|
10
|
+
port: DEFAULT_PORTS.YOUTUBE,
|
|
11
|
+
externalUrl: `http://localhost:${DEFAULT_PORTS.YOUTUBE}`,
|
|
12
|
+
sampleVideoPath: path.join(defaultAssetDir, 'sample.mp4'),
|
|
13
|
+
thumbnailDir: path.join(defaultAssetDir, 'thumbnails')
|
|
14
|
+
};
|
|
15
|
+
export function createYoutubeConfig(overrides = {}) {
|
|
16
|
+
const env = new ConfigService(nodeEnvAdapter);
|
|
17
|
+
const envPortVal = env.get(ENV_VARS.YOUTUBE_TWIN_PORT);
|
|
18
|
+
const envPort = envPortVal ? Number.parseInt(envPortVal, 10) : undefined;
|
|
19
|
+
const baseConfig = _extends({}, defaultYoutubeConfig, envPort !== undefined && !Number.isNaN(envPort) && {
|
|
20
|
+
port: envPort
|
|
21
|
+
});
|
|
22
|
+
const finalConfig = _extends({}, baseConfig, overrides);
|
|
23
|
+
if (finalConfig.port < PORT_RANGE.min || finalConfig.port > PORT_RANGE.max) {
|
|
24
|
+
throw new Error(`YouTube twin port ${finalConfig.port} is outside the reserved range ` + `${PORT_RANGE.min}–${PORT_RANGE.max}.`);
|
|
25
|
+
}
|
|
26
|
+
if (!overrides.externalUrl && finalConfig.externalUrl === defaultYoutubeConfig.externalUrl) {
|
|
27
|
+
finalConfig.externalUrl = `http://localhost:${finalConfig.port}`;
|
|
28
|
+
}
|
|
29
|
+
return finalConfig;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=youtube-twin.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/youtube/youtube-twin.config.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport {\n ConfigService,\n nodeEnvAdapter,\n} from '@open-kingdom/shared-poly-util-env-config';\nimport { DEFAULT_PORTS, ENV_VARS, PORT_RANGE } from '../shared/constants.js';\n\nconst currentDir = path.dirname(fileURLToPath(import.meta.url));\n\n// Resolved relative to dist/youtube/youtube-twin.config.js when packaged\nconst defaultAssetDir = path.resolve(currentDir, '../../test-assets/youtube');\n\nexport interface YoutubeTwinConfig {\n /** Port the YouTube twin Express server listens on */\n port: number;\n /** External URL consumers use to reach the twin */\n externalUrl: string;\n /** Path to the sample video file */\n sampleVideoPath: string;\n /** Path to the thumbnails directory */\n thumbnailDir: string;\n}\n\nexport const defaultYoutubeConfig: YoutubeTwinConfig = {\n port: DEFAULT_PORTS.YOUTUBE,\n externalUrl: `http://localhost:${DEFAULT_PORTS.YOUTUBE}`,\n sampleVideoPath: path.join(defaultAssetDir, 'sample.mp4'),\n thumbnailDir: path.join(defaultAssetDir, 'thumbnails'),\n};\n\nexport function createYoutubeConfig(\n overrides: Partial<YoutubeTwinConfig> = {}\n): YoutubeTwinConfig {\n const env = new ConfigService(nodeEnvAdapter);\n const envPortVal = env.get(ENV_VARS.YOUTUBE_TWIN_PORT);\n const envPort = envPortVal ? Number.parseInt(envPortVal, 10) : undefined;\n\n const baseConfig: YoutubeTwinConfig = {\n ...defaultYoutubeConfig,\n ...(envPort !== undefined && !Number.isNaN(envPort) && { port: envPort }),\n };\n\n const finalConfig: YoutubeTwinConfig = {\n ...baseConfig,\n ...overrides,\n };\n\n if (finalConfig.port < PORT_RANGE.min || finalConfig.port > PORT_RANGE.max) {\n throw new Error(\n `YouTube twin port ${finalConfig.port} is outside the reserved range ` +\n `${PORT_RANGE.min}–${PORT_RANGE.max}.`\n );\n }\n\n if (\n !overrides.externalUrl &&\n finalConfig.externalUrl === defaultYoutubeConfig.externalUrl\n ) {\n finalConfig.externalUrl = `http://localhost:${finalConfig.port}`;\n }\n\n return finalConfig;\n}\n"],"names":["fileURLToPath","path","ConfigService","nodeEnvAdapter","DEFAULT_PORTS","ENV_VARS","PORT_RANGE","currentDir","dirname","url","defaultAssetDir","resolve","defaultYoutubeConfig","port","YOUTUBE","externalUrl","sampleVideoPath","join","thumbnailDir","createYoutubeConfig","overrides","env","envPortVal","get","YOUTUBE_TWIN_PORT","envPort","Number","parseInt","undefined","baseConfig","isNaN","finalConfig","min","max","Error"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";AAAA,SAASA,aAAa,QAAQ,WAAW;AACzC,OAAOC,UAAU,YAAY;AAC7B,SACEC,aAAa,EACbC,cAAc,QACT,4CAA4C;AACnD,SAASC,aAAa,EAAEC,QAAQ,EAAEC,UAAU,QAAQ,yBAAyB;AAE7E,MAAMC,aAAaN,KAAKO,OAAO,CAACR,cAAc,YAAYS,GAAG;AAE7D,yEAAyE;AACzE,MAAMC,kBAAkBT,KAAKU,OAAO,CAACJ,YAAY;AAajD,OAAO,MAAMK,uBAA0C;IACrDC,MAAMT,cAAcU,OAAO;IAC3BC,aAAa,CAAC,iBAAiB,EAAEX,cAAcU,OAAO,CAAC,CAAC;IACxDE,iBAAiBf,KAAKgB,IAAI,CAACP,iBAAiB;IAC5CQ,cAAcjB,KAAKgB,IAAI,CAACP,iBAAiB;AAC3C,EAAE;AAEF,OAAO,SAASS,oBACdC,YAAwC,CAAC,CAAC;IAE1C,MAAMC,MAAM,IAAInB,cAAcC;IAC9B,MAAMmB,aAAaD,IAAIE,GAAG,CAAClB,SAASmB,iBAAiB;IACrD,MAAMC,UAAUH,aAAaI,OAAOC,QAAQ,CAACL,YAAY,MAAMM;IAE/D,MAAMC,aAAgC,aACjCjB,sBACCa,YAAYG,aAAa,CAACF,OAAOI,KAAK,CAACL,YAAY;QAAEZ,MAAMY;IAAQ;IAGzE,MAAMM,cAAiC,aAClCF,YACAT;IAGL,IAAIW,YAAYlB,IAAI,GAAGP,WAAW0B,GAAG,IAAID,YAAYlB,IAAI,GAAGP,WAAW2B,GAAG,EAAE;QAC1E,MAAM,IAAIC,MACR,CAAC,kBAAkB,EAAEH,YAAYlB,IAAI,CAAC,+BAA+B,CAAC,GACpE,CAAC,EAAEP,WAAW0B,GAAG,CAAC,CAAC,EAAE1B,WAAW2B,GAAG,CAAC,CAAC,CAAC;IAE5C;IAEA,IACE,CAACb,UAAUL,WAAW,IACtBgB,YAAYhB,WAAW,KAAKH,qBAAqBG,WAAW,EAC5D;QACAgB,YAAYhB,WAAW,GAAG,CAAC,iBAAiB,EAAEgB,YAAYlB,IAAI,CAAC,CAAC;IAClE;IAEA,OAAOkB;AACT"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { YoutubeTwinConfig } from './youtube-twin.config.js';
|
|
2
|
+
export declare class YoutubeTwin {
|
|
3
|
+
private readonly config;
|
|
4
|
+
private server;
|
|
5
|
+
private currentFixtures;
|
|
6
|
+
private readonly errorModeManager;
|
|
7
|
+
constructor(overrides?: Partial<YoutubeTwinConfig>);
|
|
8
|
+
start(): Promise<void>;
|
|
9
|
+
stop(): Promise<void>;
|
|
10
|
+
reset(): Promise<void>;
|
|
11
|
+
isHealthy(): Promise<boolean>;
|
|
12
|
+
getEmulatorHost(): string;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=youtube-twin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtube-twin.d.ts","sourceRoot":"","sources":["../../src/youtube/youtube-twin.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAUlC,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiC;gBAEtD,SAAS,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAK5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkHtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAarB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAenC,eAAe,IAAI,MAAM;CAG1B"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import cors from 'cors';
|
|
4
|
+
import { createYoutubeConfig } from './youtube-twin.config.js';
|
|
5
|
+
import { videoFixtures, searchFixtures } from './search-fixtures.js';
|
|
6
|
+
import { formatSearchResponse } from './search-response.js';
|
|
7
|
+
import { generatePlayerShim } from './player-shim.js';
|
|
8
|
+
import { YoutubeErrorModeManager } from './youtube-error-mode.js';
|
|
9
|
+
export class YoutubeTwin {
|
|
10
|
+
async start() {
|
|
11
|
+
if (this.server) return; // Already started
|
|
12
|
+
const app = express();
|
|
13
|
+
app.use(cors());
|
|
14
|
+
app.use(express.json());
|
|
15
|
+
// Serve static test assets (sample video and thumbnails)
|
|
16
|
+
const assetsDir = path.resolve(this.config.thumbnailDir, '..');
|
|
17
|
+
app.use('/test-assets', express.static(assetsDir));
|
|
18
|
+
// YouTube Data API — Search
|
|
19
|
+
app.get('/youtube/v3/search', (req, res)=>{
|
|
20
|
+
const errorResult = this.errorModeManager.matchSearchRequest();
|
|
21
|
+
if (errorResult) {
|
|
22
|
+
return res.status(errorResult.status).json(errorResult.body);
|
|
23
|
+
}
|
|
24
|
+
const { q = '', maxResults = '10', key } = req.query;
|
|
25
|
+
if (!key) {
|
|
26
|
+
return res.status(400).json({
|
|
27
|
+
error: {
|
|
28
|
+
code: 400,
|
|
29
|
+
message: 'API key not valid. Please pass a valid API key.',
|
|
30
|
+
errors: [
|
|
31
|
+
{
|
|
32
|
+
domain: 'usageLimits',
|
|
33
|
+
reason: 'keyInvalid',
|
|
34
|
+
message: 'API key not valid.'
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const limit = Number.parseInt(maxResults, 10);
|
|
41
|
+
const results = searchFixtures(q, Number.isNaN(limit) ? 10 : limit, this.currentFixtures);
|
|
42
|
+
const response = formatSearchResponse(results, this.config.externalUrl, results.length);
|
|
43
|
+
return res.json(response);
|
|
44
|
+
});
|
|
45
|
+
// Test control: override fixtures at runtime
|
|
46
|
+
app.put('/test/youtube/fixtures', (req, res)=>{
|
|
47
|
+
var _req_body;
|
|
48
|
+
var _req_body_fixtures;
|
|
49
|
+
this.currentFixtures = (_req_body_fixtures = (_req_body = req.body) == null ? void 0 : _req_body.fixtures) != null ? _req_body_fixtures : [
|
|
50
|
+
...videoFixtures
|
|
51
|
+
];
|
|
52
|
+
res.json({
|
|
53
|
+
success: true,
|
|
54
|
+
count: this.currentFixtures.length
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
// Health check endpoint
|
|
58
|
+
app.get('/test/youtube/health', (_req, res)=>{
|
|
59
|
+
res.json({
|
|
60
|
+
status: 'ok'
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
// Reset endpoint
|
|
64
|
+
app.post('/test/youtube/reset', async (_req, res)=>{
|
|
65
|
+
await this.reset();
|
|
66
|
+
res.json({
|
|
67
|
+
success: true
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// Error mode control endpoints
|
|
71
|
+
app.post('/test/youtube/error-mode', (req, res)=>{
|
|
72
|
+
const { mode } = req.body;
|
|
73
|
+
if (!mode) {
|
|
74
|
+
return res.status(400).json({
|
|
75
|
+
error: 'Missing "mode" field'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
this.errorModeManager.setMode({
|
|
79
|
+
type: mode
|
|
80
|
+
});
|
|
81
|
+
return res.json({
|
|
82
|
+
success: true,
|
|
83
|
+
mode
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
app.delete('/test/youtube/error-mode', (_req, res)=>{
|
|
87
|
+
this.errorModeManager.clearMode();
|
|
88
|
+
return res.json({
|
|
89
|
+
success: true,
|
|
90
|
+
mode: null
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
app.get('/test/youtube/error-mode', (_req, res)=>{
|
|
94
|
+
const mode = this.errorModeManager.getMode();
|
|
95
|
+
var _mode_type;
|
|
96
|
+
return res.json({
|
|
97
|
+
active: mode !== null,
|
|
98
|
+
mode: (_mode_type = mode == null ? void 0 : mode.type) != null ? _mode_type : null
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
// Serve YouTube IFrame Player API Shim JS
|
|
102
|
+
const shimJs = generatePlayerShim(this.config.externalUrl);
|
|
103
|
+
app.get('/iframe_api', (_req, res)=>{
|
|
104
|
+
res.type('application/javascript').send(shimJs);
|
|
105
|
+
});
|
|
106
|
+
app.get('/shim/youtube-player.js', (_req, res)=>{
|
|
107
|
+
res.type('application/javascript').send(shimJs);
|
|
108
|
+
});
|
|
109
|
+
return new Promise((resolve, reject)=>{
|
|
110
|
+
this.server = app.listen(this.config.port, ()=>{
|
|
111
|
+
console.log(`[YoutubeTwin] Express server listening on port ${this.config.port}`);
|
|
112
|
+
resolve();
|
|
113
|
+
});
|
|
114
|
+
this.server.on('error', reject);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async stop() {
|
|
118
|
+
const server = this.server;
|
|
119
|
+
if (!server) return;
|
|
120
|
+
return new Promise((resolve, reject)=>{
|
|
121
|
+
server.close((err)=>{
|
|
122
|
+
if (err) return reject(err);
|
|
123
|
+
this.server = null;
|
|
124
|
+
console.log('[YoutubeTwin] Express server stopped');
|
|
125
|
+
resolve();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async reset() {
|
|
130
|
+
this.errorModeManager.reset();
|
|
131
|
+
this.currentFixtures = [
|
|
132
|
+
...videoFixtures
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
async isHealthy() {
|
|
136
|
+
try {
|
|
137
|
+
const res = await fetch(`${this.config.externalUrl}/test/youtube/health`, {
|
|
138
|
+
headers: {
|
|
139
|
+
Connection: 'close'
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
await res.text(); // Consume body to release socket
|
|
143
|
+
return res.ok;
|
|
144
|
+
} catch (e) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
getEmulatorHost() {
|
|
149
|
+
return this.config.externalUrl;
|
|
150
|
+
}
|
|
151
|
+
constructor(overrides){
|
|
152
|
+
this.server = null;
|
|
153
|
+
this.currentFixtures = [];
|
|
154
|
+
this.errorModeManager = new YoutubeErrorModeManager();
|
|
155
|
+
this.config = createYoutubeConfig(overrides);
|
|
156
|
+
this.currentFixtures = [
|
|
157
|
+
...videoFixtures
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=youtube-twin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/youtube/youtube-twin.ts"],"sourcesContent":["import http from 'node:http';\nimport path from 'node:path';\nimport express, { Request, Response } from 'express';\nimport cors from 'cors';\nimport {\n createYoutubeConfig,\n YoutubeTwinConfig,\n} from './youtube-twin.config.js';\nimport {\n VideoFixture,\n videoFixtures,\n searchFixtures,\n} from './search-fixtures.js';\nimport { formatSearchResponse } from './search-response.js';\nimport { generatePlayerShim } from './player-shim.js';\nimport { YoutubeErrorModeManager } from './youtube-error-mode.js';\n\nexport class YoutubeTwin {\n private readonly config: YoutubeTwinConfig;\n private server: http.Server | null = null;\n private currentFixtures: VideoFixture[] = [];\n private readonly errorModeManager = new YoutubeErrorModeManager();\n\n constructor(overrides?: Partial<YoutubeTwinConfig>) {\n this.config = createYoutubeConfig(overrides);\n this.currentFixtures = [...videoFixtures];\n }\n\n async start(): Promise<void> {\n if (this.server) return; // Already started\n\n const app = express();\n app.use(cors());\n app.use(express.json());\n\n // Serve static test assets (sample video and thumbnails)\n const assetsDir = path.resolve(this.config.thumbnailDir, '..');\n app.use('/test-assets', express.static(assetsDir));\n\n // YouTube Data API — Search\n app.get('/youtube/v3/search', (req: Request, res: Response) => {\n const errorResult = this.errorModeManager.matchSearchRequest();\n if (errorResult) {\n return res.status(errorResult.status).json(errorResult.body);\n }\n\n const {\n q = '',\n maxResults = '10',\n key,\n } = req.query as Record<string, string>;\n\n if (!key) {\n return res.status(400).json({\n error: {\n code: 400,\n message: 'API key not valid. Please pass a valid API key.',\n errors: [\n {\n domain: 'usageLimits',\n reason: 'keyInvalid',\n message: 'API key not valid.',\n },\n ],\n },\n });\n }\n\n const limit = Number.parseInt(maxResults, 10);\n const results = searchFixtures(\n q,\n Number.isNaN(limit) ? 10 : limit,\n this.currentFixtures\n );\n const response = formatSearchResponse(\n results,\n this.config.externalUrl,\n results.length\n );\n\n return res.json(response);\n });\n\n // Test control: override fixtures at runtime\n app.put('/test/youtube/fixtures', (req: Request, res: Response) => {\n this.currentFixtures = req.body?.fixtures ?? [...videoFixtures];\n res.json({ success: true, count: this.currentFixtures.length });\n });\n\n // Health check endpoint\n app.get('/test/youtube/health', (_req: Request, res: Response) => {\n res.json({ status: 'ok' });\n });\n\n // Reset endpoint\n app.post('/test/youtube/reset', async (_req: Request, res: Response) => {\n await this.reset();\n res.json({ success: true });\n });\n\n // Error mode control endpoints\n app.post('/test/youtube/error-mode', (req: Request, res: Response) => {\n const { mode } = req.body;\n if (!mode) {\n return res.status(400).json({ error: 'Missing \"mode\" field' });\n }\n this.errorModeManager.setMode({ type: mode });\n return res.json({ success: true, mode });\n });\n\n app.delete('/test/youtube/error-mode', (_req: Request, res: Response) => {\n this.errorModeManager.clearMode();\n return res.json({ success: true, mode: null });\n });\n\n app.get('/test/youtube/error-mode', (_req: Request, res: Response) => {\n const mode = this.errorModeManager.getMode();\n return res.json({ active: mode !== null, mode: mode?.type ?? null });\n });\n\n // Serve YouTube IFrame Player API Shim JS\n const shimJs = generatePlayerShim(this.config.externalUrl);\n\n app.get('/iframe_api', (_req: Request, res: Response) => {\n res.type('application/javascript').send(shimJs);\n });\n\n app.get('/shim/youtube-player.js', (_req: Request, res: Response) => {\n res.type('application/javascript').send(shimJs);\n });\n\n return new Promise<void>((resolve, reject) => {\n this.server = app.listen(this.config.port, () => {\n console.log(\n `[YoutubeTwin] Express server listening on port ${this.config.port}`\n );\n resolve();\n });\n this.server.on('error', reject);\n });\n }\n\n async stop(): Promise<void> {\n const server = this.server;\n if (!server) return;\n return new Promise<void>((resolve, reject) => {\n server.close((err) => {\n if (err) return reject(err);\n this.server = null;\n console.log('[YoutubeTwin] Express server stopped');\n resolve();\n });\n });\n }\n\n async reset(): Promise<void> {\n this.errorModeManager.reset();\n this.currentFixtures = [...videoFixtures];\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n const res = await fetch(\n `${this.config.externalUrl}/test/youtube/health`,\n {\n headers: { Connection: 'close' },\n }\n );\n await res.text(); // Consume body to release socket\n return res.ok;\n } catch {\n return false;\n }\n }\n\n getEmulatorHost(): string {\n return this.config.externalUrl;\n }\n}\n"],"names":["path","express","cors","createYoutubeConfig","videoFixtures","searchFixtures","formatSearchResponse","generatePlayerShim","YoutubeErrorModeManager","YoutubeTwin","start","server","app","use","json","assetsDir","resolve","config","thumbnailDir","static","get","req","res","errorResult","errorModeManager","matchSearchRequest","status","body","q","maxResults","key","query","error","code","message","errors","domain","reason","limit","Number","parseInt","results","isNaN","currentFixtures","response","externalUrl","length","put","fixtures","success","count","_req","post","reset","mode","setMode","type","delete","clearMode","getMode","active","shimJs","send","Promise","reject","listen","port","console","log","on","stop","close","err","isHealthy","fetch","headers","Connection","text","ok","getEmulatorHost","constructor","overrides"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,OAAOA,UAAU,YAAY;AAC7B,OAAOC,aAAoC,UAAU;AACrD,OAAOC,UAAU,OAAO;AACxB,SACEC,mBAAmB,QAEd,2BAA2B;AAClC,SAEEC,aAAa,EACbC,cAAc,QACT,uBAAuB;AAC9B,SAASC,oBAAoB,QAAQ,uBAAuB;AAC5D,SAASC,kBAAkB,QAAQ,mBAAmB;AACtD,SAASC,uBAAuB,QAAQ,0BAA0B;AAElE,OAAO,MAAMC;IAWX,MAAMC,QAAuB;QAC3B,IAAI,IAAI,CAACC,MAAM,EAAE,QAAQ,kBAAkB;QAE3C,MAAMC,MAAMX;QACZW,IAAIC,GAAG,CAACX;QACRU,IAAIC,GAAG,CAACZ,QAAQa,IAAI;QAEpB,yDAAyD;QACzD,MAAMC,YAAYf,KAAKgB,OAAO,CAAC,IAAI,CAACC,MAAM,CAACC,YAAY,EAAE;QACzDN,IAAIC,GAAG,CAAC,gBAAgBZ,QAAQkB,MAAM,CAACJ;QAEvC,4BAA4B;QAC5BH,IAAIQ,GAAG,CAAC,sBAAsB,CAACC,KAAcC;YAC3C,MAAMC,cAAc,IAAI,CAACC,gBAAgB,CAACC,kBAAkB;YAC5D,IAAIF,aAAa;gBACf,OAAOD,IAAII,MAAM,CAACH,YAAYG,MAAM,EAAEZ,IAAI,CAACS,YAAYI,IAAI;YAC7D;YAEA,MAAM,EACJC,IAAI,EAAE,EACNC,aAAa,IAAI,EACjBC,GAAG,EACJ,GAAGT,IAAIU,KAAK;YAEb,IAAI,CAACD,KAAK;gBACR,OAAOR,IAAII,MAAM,CAAC,KAAKZ,IAAI,CAAC;oBAC1BkB,OAAO;wBACLC,MAAM;wBACNC,SAAS;wBACTC,QAAQ;4BACN;gCACEC,QAAQ;gCACRC,QAAQ;gCACRH,SAAS;4BACX;yBACD;oBACH;gBACF;YACF;YAEA,MAAMI,QAAQC,OAAOC,QAAQ,CAACX,YAAY;YAC1C,MAAMY,UAAUpC,eACduB,GACAW,OAAOG,KAAK,CAACJ,SAAS,KAAKA,OAC3B,IAAI,CAACK,eAAe;YAEtB,MAAMC,WAAWtC,qBACfmC,SACA,IAAI,CAACxB,MAAM,CAAC4B,WAAW,EACvBJ,QAAQK,MAAM;YAGhB,OAAOxB,IAAIR,IAAI,CAAC8B;QAClB;QAEA,6CAA6C;QAC7ChC,IAAImC,GAAG,CAAC,0BAA0B,CAAC1B,KAAcC;gBACxBD;gBAAAA;YAAvB,IAAI,CAACsB,eAAe,GAAGtB,CAAAA,sBAAAA,YAAAA,IAAIM,IAAI,qBAARN,UAAU2B,QAAQ,YAAlB3B,qBAAsB;mBAAIjB;aAAc;YAC/DkB,IAAIR,IAAI,CAAC;gBAAEmC,SAAS;gBAAMC,OAAO,IAAI,CAACP,eAAe,CAACG,MAAM;YAAC;QAC/D;QAEA,wBAAwB;QACxBlC,IAAIQ,GAAG,CAAC,wBAAwB,CAAC+B,MAAe7B;YAC9CA,IAAIR,IAAI,CAAC;gBAAEY,QAAQ;YAAK;QAC1B;QAEA,iBAAiB;QACjBd,IAAIwC,IAAI,CAAC,uBAAuB,OAAOD,MAAe7B;YACpD,MAAM,IAAI,CAAC+B,KAAK;YAChB/B,IAAIR,IAAI,CAAC;gBAAEmC,SAAS;YAAK;QAC3B;QAEA,+BAA+B;QAC/BrC,IAAIwC,IAAI,CAAC,4BAA4B,CAAC/B,KAAcC;YAClD,MAAM,EAAEgC,IAAI,EAAE,GAAGjC,IAAIM,IAAI;YACzB,IAAI,CAAC2B,MAAM;gBACT,OAAOhC,IAAII,MAAM,CAAC,KAAKZ,IAAI,CAAC;oBAAEkB,OAAO;gBAAuB;YAC9D;YACA,IAAI,CAACR,gBAAgB,CAAC+B,OAAO,CAAC;gBAAEC,MAAMF;YAAK;YAC3C,OAAOhC,IAAIR,IAAI,CAAC;gBAAEmC,SAAS;gBAAMK;YAAK;QACxC;QAEA1C,IAAI6C,MAAM,CAAC,4BAA4B,CAACN,MAAe7B;YACrD,IAAI,CAACE,gBAAgB,CAACkC,SAAS;YAC/B,OAAOpC,IAAIR,IAAI,CAAC;gBAAEmC,SAAS;gBAAMK,MAAM;YAAK;QAC9C;QAEA1C,IAAIQ,GAAG,CAAC,4BAA4B,CAAC+B,MAAe7B;YAClD,MAAMgC,OAAO,IAAI,CAAC9B,gBAAgB,CAACmC,OAAO;gBACKL;YAA/C,OAAOhC,IAAIR,IAAI,CAAC;gBAAE8C,QAAQN,SAAS;gBAAMA,MAAMA,CAAAA,aAAAA,wBAAAA,KAAME,IAAI,YAAVF,aAAc;YAAK;QACpE;QAEA,0CAA0C;QAC1C,MAAMO,SAAStD,mBAAmB,IAAI,CAACU,MAAM,CAAC4B,WAAW;QAEzDjC,IAAIQ,GAAG,CAAC,eAAe,CAAC+B,MAAe7B;YACrCA,IAAIkC,IAAI,CAAC,0BAA0BM,IAAI,CAACD;QAC1C;QAEAjD,IAAIQ,GAAG,CAAC,2BAA2B,CAAC+B,MAAe7B;YACjDA,IAAIkC,IAAI,CAAC,0BAA0BM,IAAI,CAACD;QAC1C;QAEA,OAAO,IAAIE,QAAc,CAAC/C,SAASgD;YACjC,IAAI,CAACrD,MAAM,GAAGC,IAAIqD,MAAM,CAAC,IAAI,CAAChD,MAAM,CAACiD,IAAI,EAAE;gBACzCC,QAAQC,GAAG,CACT,CAAC,+CAA+C,EAAE,IAAI,CAACnD,MAAM,CAACiD,IAAI,CAAC,CAAC;gBAEtElD;YACF;YACA,IAAI,CAACL,MAAM,CAAC0D,EAAE,CAAC,SAASL;QAC1B;IACF;IAEA,MAAMM,OAAsB;QAC1B,MAAM3D,SAAS,IAAI,CAACA,MAAM;QAC1B,IAAI,CAACA,QAAQ;QACb,OAAO,IAAIoD,QAAc,CAAC/C,SAASgD;YACjCrD,OAAO4D,KAAK,CAAC,CAACC;gBACZ,IAAIA,KAAK,OAAOR,OAAOQ;gBACvB,IAAI,CAAC7D,MAAM,GAAG;gBACdwD,QAAQC,GAAG,CAAC;gBACZpD;YACF;QACF;IACF;IAEA,MAAMqC,QAAuB;QAC3B,IAAI,CAAC7B,gBAAgB,CAAC6B,KAAK;QAC3B,IAAI,CAACV,eAAe,GAAG;eAAIvC;SAAc;IAC3C;IAEA,MAAMqE,YAA8B;QAClC,IAAI;YACF,MAAMnD,MAAM,MAAMoD,MAChB,CAAC,EAAE,IAAI,CAACzD,MAAM,CAAC4B,WAAW,CAAC,oBAAoB,CAAC,EAChD;gBACE8B,SAAS;oBAAEC,YAAY;gBAAQ;YACjC;YAEF,MAAMtD,IAAIuD,IAAI,IAAI,iCAAiC;YACnD,OAAOvD,IAAIwD,EAAE;QACf,EAAE,UAAM;YACN,OAAO;QACT;IACF;IAEAC,kBAA0B;QACxB,OAAO,IAAI,CAAC9D,MAAM,CAAC4B,WAAW;IAChC;IA1JAmC,YAAYC,SAAsC,CAAE;aAJ5CtE,SAA6B;aAC7BgC,kBAAkC,EAAE;aAC3BnB,mBAAmB,IAAIhB;QAGtC,IAAI,CAACS,MAAM,GAAGd,oBAAoB8E;QAClC,IAAI,CAACtC,eAAe,GAAG;eAAIvC;SAAc;IAC3C;AAwJF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-kingdom/shared-backend-integration-test-doubles",
|
|
3
|
-
"version": "0.0.2-
|
|
3
|
+
"version": "0.0.2-18",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"files": [
|
|
21
21
|
"README.md",
|
|
22
22
|
"dist",
|
|
23
|
+
"test-assets",
|
|
23
24
|
"!**/*.tsbuildinfo"
|
|
24
25
|
],
|
|
25
26
|
"nx": {
|
|
@@ -49,12 +50,24 @@
|
|
|
49
50
|
"dependsOn": [
|
|
50
51
|
"^build"
|
|
51
52
|
]
|
|
53
|
+
},
|
|
54
|
+
"start:youtube-twin": {
|
|
55
|
+
"command": "npx tsx libs/shared/backend/integration-test-doubles/scripts/start-youtube-twin.ts",
|
|
56
|
+
"dependsOn": [
|
|
57
|
+
"^build"
|
|
58
|
+
]
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
},
|
|
55
62
|
"dependencies": {
|
|
56
|
-
"@open-kingdom/shared-poly-util-env-config": "0.0.2-
|
|
63
|
+
"@open-kingdom/shared-poly-util-env-config": "0.0.2-18",
|
|
64
|
+
"cors": "^2.8.5",
|
|
57
65
|
"dockerode": "^4.0.6",
|
|
66
|
+
"express": "^5.1.0",
|
|
58
67
|
"tslib": "^2.3.0"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@types/cors": "^2.8.17",
|
|
71
|
+
"@types/express": "^5.0.0"
|
|
59
72
|
}
|
|
60
73
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|