Skip to content

Commit

Permalink
feat(project): merge with use passport branch
Browse files Browse the repository at this point in the history
  • Loading branch information
kiremitrov123 committed Sep 19, 2024
2 parents cd8a277 + ac1a09e commit ab6b59d
Show file tree
Hide file tree
Showing 50 changed files with 826 additions and 615 deletions.
82 changes: 16 additions & 66 deletions .syncpackrc.json
Original file line number Diff line number Diff line change
@@ -1,88 +1,38 @@
{
"$schema": "https://unpkg.com/[email protected]/dist/schema.json",
"sortFirst": [
"name",
"description",
"version",
"private",
"license",
"repository",
"author",
"main",
"exports",
"engines",
"workspaces",
"scripts"
],
"sortFirst": ["name", "description", "version", "private", "license", "repository", "author", "main", "exports", "engines", "workspaces", "scripts"],
"semverGroups": [
{
"dependencies": [
"codeceptjs",
"codeceptjs**",
"react-router",
"react-router-dom",
"typescript"
],
"packages": [
"**"
],
"dependencies": ["codeceptjs", "codeceptjs**", "react-router", "react-router-dom", "typescript"],
"packages": ["**"],
"isIgnored": true
},
{
"range": "^",
"dependencies": [
"**"
],
"packages": [
"**"
],
"dependencyTypes": [
"prod",
"dev",
"peer"
]
"dependencies": ["**"],
"packages": ["**"],
"dependencyTypes": ["prod", "dev", "peer"]
}
],
"versionGroups": [
{
"label": "Ensure semver ranges for locally developed packages satisfy the local version",
"dependencies": [
"@jwp/**",
"**-config-jwp"
],
"dependencyTypes": [
"peer"
],
"packages": [
"**"
],
"dependencies": ["@jwp/**", "**-config-jwp"],
"dependencyTypes": ["dev", "prod", "peer"],
"packages": ["**"],
"pinVersion": "*"
},
{
"label": "Ensure local packages are installed as peerDependency",
"dependencies": [
"@jwp/**",
"**-config-jwp"
],
"dependencyTypes": [
"dev",
"prod"
],
"packages": [
"**"
],
"label": "Ensure local packages are installed as dev or prod dependency",
"dependencies": ["@jwp/**", "**-config-jwp"],
"dependencyTypes": ["peer"],
"packages": ["**"],
"isBanned": true
},
{
"dependencies": [
"@types/**"
],
"dependencyTypes": [
"!dev"
],
"packages": [
"**"
],
"dependencies": ["@types/**"],
"dependencyTypes": ["!dev"],
"packages": ["**"],
"isBanned": true,
"label": "@types packages should only be under devDependencies"
}
Expand Down
2 changes: 1 addition & 1 deletion configs/eslint-config-jwp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"@typescript-eslint/parser": "^7.13.1",
"confusing-browser-globals": "^1.0.11",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react": "^7.34.3",
"eslint-plugin-react-hooks": "^4.6.2"
}
}
14 changes: 6 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
"devDependencies": {
"@commitlint/cli": "^17.8.1",
"@commitlint/config-conventional": "^17.8.1",
"@types/node": "^18.19.36",
"@types/node": "^18.19.37",
"csv-parse": "^5.5.6",
"eslint": "^8.57.0",
"husky": "^6.0.0",
"i18next-parser-workspaces": "^0.2.0",
"knip": "^5.21.1",
"lint-staged": "^15.2.7",
"knip": "^5.30.1",
"lint-staged": "^15.2.10",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.8",
"read": "^2.1.0",
Expand All @@ -56,10 +56,8 @@
"eslint-config-jwp": "*"
},
"resolutions": {
"codeceptjs/**/ansi-regex": "^4.1.1",
"codeceptjs/**/minimatch": "^3.0.5",
"flat": "^5.0.1",
"glob-parent": "^5.1.2",
"json5": "^2.2.2"
"codeceptjs/**/fast-xml-parser": "^4.5.0",
"micromatch": ">=4.0.8",
"ws": ">=5.2.4"
}
}
6 changes: 3 additions & 3 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
},
"dependencies": {
"broadcast-channel": "^7.0.0",
"date-fns": "^2.30.0",
"fast-xml-parser": "^4.4.0",
"date-fns": "^3.6.0",
"fast-xml-parser": "^4.5.0",
"i18next": "^22.5.1",
"ini": "^3.0.1",
"inversify": "^6.0.2",
Expand All @@ -20,7 +20,7 @@
"react-i18next": "^12.3.1",
"reflect-metadata": "^0.2.2",
"yup": "^0.32.11",
"zustand": "^3.7.2"
"zustand": "^4.5.5"
},
"devDependencies": {
"@types/ini": "^1.3.34",
Expand Down
3 changes: 2 additions & 1 deletion packages/common/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ export const EPG_TYPE = {
viewNexa: 'viewnexa',
} as const;

export const PLAYLIST_TYPE = {
export const APP_CONFIG_ITEM_TYPE = {
playlist: 'playlist',
continue_watching: 'continue_watching',
favorites: 'favorites',
content_list: 'content_list',
media: 'media',
} as const;
65 changes: 56 additions & 9 deletions packages/common/src/controllers/AccessController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import { INTEGRATION_TYPE } from '../modules/types';
import { getNamedModule } from '../modules/container';
import StorageService from '../services/StorageService';
import type { AccessTokens } from '../../types/access';
import { useAccessStore } from '../stores/AccessStore';
import JWPEntitlementService from '../services/JWPEntitlementService';

const ACCESS_TOKENS = 'access_tokens';

@injectable()
export default class AccessController {
private readonly entitlementService: JWPEntitlementService;
private readonly accessService: AccessService;
private readonly accountService: AccountService;
private readonly storageService: StorageService;
Expand All @@ -21,9 +24,11 @@ export default class AccessController {

constructor(
@inject(INTEGRATION_TYPE) integrationType: IntegrationType,
@inject(JWPEntitlementService) entitlementService: JWPEntitlementService,
@inject(StorageService) storageService: StorageService,
@inject(AccessService) accessService: AccessService,
) {
this.entitlementService = entitlementService;
this.accessService = accessService;
this.storageService = storageService;
this.accountService = getNamedModule(AccountService, integrationType);
Expand All @@ -41,19 +46,40 @@ export default class AccessController {
// Not awaiting to avoid blocking the loading process,
// as the access tokens can be stored asynchronously without affecting the app's performance
void this.generateOrRefreshAccessTokens();

// Fetches the entitled plans for the viewer and stores them into the access store.
await this.fetchAndStoreEntitledPlans();
};

generateOrRefreshAccessTokens = async () => {
const existing = await this.getAccessTokens();
if (existing) {
// do nothing if passport exists
getMediaById = async () => {};

fetchAndStoreEntitledPlans = async () => {
if (!this.siteId) {
return;
}
// Note: Without a valid plan ID, requests for media metadata cannot be made.
// TODO: Support for multiple plans should be added. Revisit this logic once the dependency on plan_id is changed.
const response = await this.entitlementService.getEntitledPlans({ siteId: this.siteId });
if (response?.plans?.length) {
// Find the SVOD plan or fallback to the first available plan
const entitledPlan = response.plans.find((plan) => plan.metadata.access_model === 'svod') || response.plans[0];
useAccessStore.setState({ entitledPlan });
}
};

generateOrRefreshAccessTokens = async () => {
const existingAccessTokens = await this.getAccessTokens();
const shouldRefresh = existingAccessTokens && Date.now() > existingAccessTokens.expires;

if (!existingAccessTokens) {
await this.generateAccessTokens();
}

// TODO: the next PR will address the refreshment
// https://jwplayer.atlassian.net/browse/IDM-173
if (shouldRefresh) {
return await this.refreshAccessTokens();
}

await this.generateAccessTokens();
return;
};

generateAccessTokens = async () => {
Expand All @@ -69,18 +95,39 @@ export default class AccessController {
}
};

refreshAccessTokens = async () => {
const existingAccessTokens = await this.getAccessTokens();
// there is no access tokens stored, nothing to refresh
if (!existingAccessTokens) {
return;
}

const accessTokens = await this.accessService.refreshAccessTokens(this.siteId, existingAccessTokens.refresh_token);
if (accessTokens) {
await this.setAccessTokens(accessTokens);
}
};

setAccessTokens = async (accessTokens: AccessTokens) => {
useAccessStore.setState({ passport: accessTokens.passport });

// Since the actual valid time for a passport token is 1 hour, set the expires to one hour from now.
// The expires field here is used as a helper to manage the passport's validity and refresh process.
const expires = new Date(Date.now() + 3600 * 1000).getTime();
return await this.storageService.setItem(ACCESS_TOKENS, JSON.stringify({ ...accessTokens, expires }), true);
};

getAccessTokens = async (): Promise<(AccessTokens & { expires: string }) | null> => {
return await this.storageService.getItem(ACCESS_TOKENS, true, true);
getAccessTokens = async (): Promise<(AccessTokens & { expires: number }) | null> => {
const accessTokens = await this.storageService.getItem<AccessTokens & { expires: number }>(ACCESS_TOKENS, true, true);
if (accessTokens) {
useAccessStore.setState({ passport: accessTokens.passport });
}

return accessTokens;
};

removeAccessTokens = async () => {
useAccessStore.setState({ passport: null });
return await this.storageService.removeItem(ACCESS_TOKENS);
};
}
1 change: 1 addition & 0 deletions packages/common/src/controllers/AccountController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export default class AccountController {

if (response) {
void this.accessController?.generateAccessTokens();
void this.accessController?.fetchAndStoreEntitledPlans();
await this.afterLogin(response.user, response.customerConsents);
return;
}
Expand Down
12 changes: 4 additions & 8 deletions packages/common/src/controllers/AppController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,15 @@ export default class AppController {
}

// Store the logo right away and set css variables so the error page will be branded
const banner = config.assets.banner;

useConfigStore.setState((s) => {
s.config.assets.banner = banner;
});
useConfigStore.setState((state) => merge({}, state, { config: { assets: { banner: config.assets.banner } } }));

config = await this.configService.validateConfig(config);
config = merge({}, defaultConfig, config);

return config;
};

initializeApp = async (url: string, refreshEntitlements?: () => Promise<void>) => {
initializeApp = async (url: string, language: string, refreshEntitlements?: () => Promise<void>) => {
logDebug('AppController', 'Initializing app', { url });

const settings = await this.settingsService.initialize();
Expand Down Expand Up @@ -93,11 +89,11 @@ export default class AppController {
}

if (config.features?.continueWatchingList && config.content.some((el) => el.type === PersonalShelf.ContinueWatching)) {
await getModule(WatchHistoryController).initialize();
await getModule(WatchHistoryController).initialize(language);
}

if (config.features?.favoritesList && config.content.some((el) => el.type === PersonalShelf.Favorites)) {
await getModule(FavoritesController).initialize();
await getModule(FavoritesController).initialize(language);
}

return { config, settings, configSource };
Expand Down
8 changes: 4 additions & 4 deletions packages/common/src/controllers/FavoritesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ export default class FavoritesController {
this.favoritesService = favoritesService;
}

initialize = async () => {
await this.restoreFavorites();
initialize = async (language: string) => {
await this.restoreFavorites(language);
};

restoreFavorites = async () => {
restoreFavorites = async (language?: string) => {
const { user } = useAccountStore.getState();
const favoritesList = useConfigStore.getState().config.features?.favoritesList;

if (!favoritesList) {
return;
}

const favorites = await this.favoritesService.getFavorites(user, favoritesList);
const favorites = await this.favoritesService.getFavorites(user, favoritesList, language);

useFavoritesStore.setState({ favorites, favoritesPlaylistId: favoritesList });
};
Expand Down
8 changes: 4 additions & 4 deletions packages/common/src/controllers/WatchHistoryController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ export default class WatchHistoryController {
this.watchHistoryService = watchHistoryService;
}

initialize = async () => {
await this.restoreWatchHistory();
initialize = async (language: string) => {
await this.restoreWatchHistory(language);
};

restoreWatchHistory = async () => {
restoreWatchHistory = async (language?: string) => {
const { user } = useAccountStore.getState();
const continueWatchingList = useConfigStore.getState().config.features?.continueWatchingList;

if (!continueWatchingList) {
return;
}

const watchHistory = await this.watchHistoryService.getWatchHistory(user, continueWatchingList);
const watchHistory = await this.watchHistoryService.getWatchHistory(user, continueWatchingList, language);

useWatchHistoryStore.setState({
watchHistory: watchHistory.filter((item): item is WatchHistoryItem => !!item?.mediaid),
Expand Down
Loading

0 comments on commit ab6b59d

Please sign in to comment.