diff --git a/package.json b/package.json index e517b37..18046f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@techniker-me/pcast-api", - "version": "2025.0.8", + "version": "2025.0.9", "type": "module", "scripts": { "ci-build": "bun run build:node && bun run build:browser && bun run build:types", diff --git a/src/PCastApi.ts b/src/PCastApi.ts index c05b0ab..24812dc 100644 --- a/src/PCastApi.ts +++ b/src/PCastApi.ts @@ -8,25 +8,27 @@ export class PCastApi { private readonly _streams: Streams; private readonly _reporting: Reporting; - constructor(pcastUri: string, applicationCredentials: ApplicationCredentials) { + private constructor(pcastUri: string, applicationCredentials: ApplicationCredentials, channels: Channels) { const normalized = pcastUri.replace(/\/+$/, ''); this._pcastUri = normalized.endsWith('/pcast') ? normalized : `${normalized}/pcast`; this._applicationCredentials = applicationCredentials; this._pcastHttpRequests = new PCastHttpRequests(this._pcastUri, this._applicationCredentials); - this._channels = new Channels(this._pcastHttpRequests); + this._channels = channels; this._streams = new Streams(this._pcastHttpRequests); this._reporting = new Reporting(this._pcastHttpRequests); } + public static async create(pcastUri: string, applicationCredentials: ApplicationCredentials): Promise { + const pcastHttpRequests = new PCastHttpRequests(pcastUri.replace(/\/+$/, '').endsWith('/pcast') ? pcastUri : `${pcastUri}/pcast`, applicationCredentials); + const channels = await Channels.create(pcastHttpRequests); + return new PCastApi(pcastUri, applicationCredentials, channels); + } + get pcastUri(): string { return this._pcastUri; } - - get applicationCredentials(): ApplicationCredentials { - return this._applicationCredentials; - } - + get channels(): Channels { return this._channels; } diff --git a/src/index.ts b/src/index.ts index bf2fa86..e184b53 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,22 @@ import {PCastApi} from './PCastApi'; -import {ReportKind} from './pcast/ReportKind'; -import {ViewingReportKind} from './pcast/ViewingReportKind'; +import type {Channels, Streams, Reporting, ReportKind, ViewingReportKind} from './pcast'; + +import type {ChannelId, Channel, ChannelAlias, Member, ChannelError} from './pcast/Channels'; +import type {HttpMethod} from './net/http/HttpMethod'; +import type {HttpRequestError} from './net/http/HttpRequests'; +import type {ChannelResponse, ChannelsResponse, MembersResponse} from './pcast/IResponse'; +import type {ApplicationCredentials} from './pcast/PCastRequests'; +import type {PublishingReportOptions, ViewingReportOptions} from './pcast/Reporting'; +import type {ReportKindType} from './pcast/ReportKind'; +import type {ViewingReportKindType} from './pcast/ViewingReportKind'; + +export type {Channels, Streams, Reporting, ReportKind, ViewingReportKind}; +export type {ChannelId, Channel, ChannelAlias, Member, ChannelError}; +export type {HttpMethod, HttpRequestError}; +export type {ChannelResponse, ChannelsResponse, MembersResponse}; +export type {ApplicationCredentials}; +export type {PublishingReportOptions, ViewingReportOptions}; +export type {ReportKindType, ViewingReportKindType}; -export type {ReportKind, ViewingReportKind}; export {PCastApi}; export default PCastApi; diff --git a/src/pcast/Channels.ts b/src/pcast/Channels.ts index 31bf540..6806849 100644 --- a/src/pcast/Channels.ts +++ b/src/pcast/Channels.ts @@ -49,11 +49,16 @@ export class ChannelError extends Error { export class Channels { private readonly _httpRequests: PCastHttpRequests; private readonly _channelsByAlias: Map = new Map(); - private _initialized = false; + private _initialized: Promise | boolean = false; - constructor(pcastHttpRequests: PCastHttpRequests) { + private constructor(pcastHttpRequests: PCastHttpRequests) { this._httpRequests = pcastHttpRequests; - this.initialize(); + } + + public static async create(pcastHttpRequests: PCastHttpRequests): Promise { + const instance = new Channels(pcastHttpRequests); + await instance.initialize(); + return instance; } public async createChannel(name: string, description: string, channelOptions: string[] = []): Promise { @@ -107,6 +112,10 @@ export class Channels { return response.channels; } + public async refreshCache(): Promise { + await this.list(); // This clears and repopulates the cache + } + public async getChannelInfoByAlias(alias: string): Promise { return this.get({alias}); } @@ -116,12 +125,20 @@ export class Channels { throw new ChannelError('Either alias or channelId must be provided', 'MISSING_PARAMETER'); } + if (this._initialized === false) { + await this.initialize(); + } else if (this._initialized instanceof Promise) { + await this._initialized; + } + if (alias) { // Check cache first if (this._channelsByAlias.has(alias)) { return this._channelsByAlias.get(alias); } + // Instead of fetching full list, try to fetch single channel if possible + // Assuming API has /channel/{alias}, but based on code, it doesn't; fallback to list const channelList = await this.list(); // Update cache @@ -129,6 +146,7 @@ export class Channels { } if (channelId) { + // Similar fallback const channelList = await this.list(); return channelList.find(channel => channel.channelId === channelId); @@ -191,7 +209,7 @@ export class Channels { // Cache management methods public isInitialized(): boolean { - return this._initialized; + return this._initialized !== false && !(this._initialized instanceof Promise); } public clearCache(): void { @@ -203,21 +221,26 @@ export class Channels { return this._channelsByAlias.size; } - private async initialize() { - try { - const channelsList = await this.list(); - if (!channelsList) { - console.warn('[Channels] Failed to initialize cache - no channels returned'); - return; - } + private async initialize(): Promise { + this._initialized = (async () => { + try { + const channelsList = await this.list(); + if (!channelsList) { + console.warn('[Channels] Failed to initialize cache - no channels returned'); + return; + } - for (const channel of channelsList) { - this._channelsByAlias.set(channel.alias, channel); - } + for (const channel of channelsList) { + this._channelsByAlias.set(channel.alias, channel); + } - this._initialized = true; - } catch (error) { - console.error('[Channels] Failed to initialize cache:', error); - } + this._initialized = true; + } catch (error) { + console.error('[Channels] Failed to initialize cache:', error); + this._initialized = true; // Mark as initialized even on error to avoid repeated attempts + } + })(); + + await this._initialized; } } diff --git a/src/pcast/index.ts b/src/pcast/index.ts index a5a2109..677cf58 100644 --- a/src/pcast/index.ts +++ b/src/pcast/index.ts @@ -2,3 +2,5 @@ export * from './Channels'; export * from './Reporting'; export * from './PCastRequests'; export * from './Stream'; +export * from './ReportKind'; +export * from './ViewingReportKind'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 9ef9612..563bea4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { // Environment setup & latest features - "lib": ["ESNext"], + "lib": ["ESNext", "DOM"], "target": "ESNext", "module": "Preserve", "moduleDetection": "force",