Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion gatsby-config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import type { GatsbyConfig } from "gatsby";
import { meta } from "./meta";
import { seoPlugins } from "./seo-plugins";
import { CacheVersion } from "api-4markdown-contracts";
import { SiteMetadata } from "core/models";

require(`dotenv`).config({
path: `.env.${process.env.NODE_ENV}`,
});

const siteMetadata: SiteMetadata = {
...meta,
buildStamp: new Date().toISOString() as CacheVersion,
};

const config: GatsbyConfig = {
siteMetadata: meta,
siteMetadata,
// More easily incorporate content into your pages through automatic TypeScript type generation and better GraphQL IntelliSense.
// If you use VSCode you can also use the GraphQL plugin
// Learn more at: https://gatsby.dev/graphql-typegen
Expand Down
6 changes: 5 additions & 1 deletion src/api-4markdown-contracts/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Prettify } from "development-kit/utility-types";
import { Brand, type Prettify } from "development-kit/utility-types";
import type { Base64, Date, Id, Url, UserProfileId } from "../atoms";
import type {
DocumentDto,
Expand Down Expand Up @@ -288,8 +288,11 @@ type API4MarkdownResult<TKey extends API4MarkdownContractKey> =
dto: API4MarkdownDto<TKey>;
};

type CacheVersion = Brand<string, "CacheVersion">;

type API4MarkdownCacheSignature<TKey extends API4MarkdownContractKey> = {
__expiry__: number;
__version__: CacheVersion;
value: API4MarkdownDto<TKey> | null;
};

Expand Down Expand Up @@ -368,4 +371,5 @@ export type {
KnownError,
NoInternetError,
ClientError,
CacheVersion,
};
13 changes: 11 additions & 2 deletions src/api-4markdown/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import type {
API4MarkdownContractKey,
API4MarkdownDto,
} from "api-4markdown-contracts";
import { getCacheVersion } from "./use-api";

const hasValidSignature = <TKey extends API4MarkdownContractKey>(
parsed: unknown,
): parsed is API4MarkdownCacheSignature<TKey> => {
return (
parsed !== null &&
typeof parsed === `object` &&
typeof (parsed as API4MarkdownCacheSignature<TKey>).__expiry__ === `number`
typeof (parsed as API4MarkdownCacheSignature<TKey>).__expiry__ ===
`number` &&
typeof (parsed as API4MarkdownCacheSignature<TKey>).__version__ === `string`
);
};

Expand All @@ -20,11 +23,13 @@ const setCache = <TKey extends API4MarkdownContractKey>(
ttlInMinutes = 960,
): void => {
try {
const version = getCacheVersion();
localStorage.setItem(
key,
JSON.stringify({
value: dto,
__expiry__: new Date().getTime() + ttlInMinutes * 60 * 1000,
__version__: version,
}),
);
} catch {}
Expand All @@ -40,6 +45,7 @@ const getCache = <TKey extends API4MarkdownContractKey>(
key: TKey,
): API4MarkdownDto<TKey> | null => {
try {
const version = getCacheVersion();
const raw = localStorage.getItem(key);

if (!raw) return null;
Expand All @@ -51,7 +57,10 @@ const getCache = <TKey extends API4MarkdownContractKey>(
return null;
}

if (parsed.__expiry__ < new Date().getTime()) {
if (
parsed.__expiry__ < new Date().getTime() ||
parsed.__version__ !== version
) {
removeCache(key);
return null;
}
Expand Down
11 changes: 0 additions & 11 deletions src/api-4markdown/guards.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/api-4markdown/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export { parseError } from "./parse-error";
export { observe, emit, unobserveAll } from "./observer";
export { initializeAPI, getAPI } from "./use-api";
export { initializeAPI, getAPI, type API4Markdown } from "./use-api";
export { getCache, removeCache, setCache } from "./cache";
export * from "./guards";
17 changes: 15 additions & 2 deletions src/api-4markdown/use-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {
API4MarkdownContractCall,
API4MarkdownContractKey,
API4MarkdownDto,
CacheVersion,
NoInternetError,
} from "api-4markdown-contracts";
import { type FirebaseOptions, initializeApp } from "firebase/app";
Expand Down Expand Up @@ -38,13 +39,16 @@ type API4Markdown = {

let instance: API4Markdown | null = null;
let functions: Functions | null = null;
let cacheVersion: CacheVersion | null = null;

const isOffline = (): boolean =>
typeof window !== `undefined` && !navigator?.onLine;

class NoInternetException extends Error {}

const initializeAPI = (): API4Markdown => {
const initializeAPI = (version: CacheVersion): API4Markdown => {
cacheVersion = version;

const config: FirebaseOptions = {
apiKey: process.env.GATSBY_API_KEY,
authDomain: process.env.GATSBY_AUTH_DOMAIN,
Expand Down Expand Up @@ -138,4 +142,13 @@ const getAPI = (): API4Markdown => {
return instance;
};

export { initializeAPI, getAPI };
const getCacheVersion = (): CacheVersion => {
if (!cacheVersion) {
throw Error(`Cache version is not initialized`);
}

return cacheVersion;
};

export type { API4Markdown };
export { initializeAPI, getAPI, getCacheVersion };
9 changes: 9 additions & 0 deletions src/core/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { type CacheVersion } from "api-4markdown-contracts";
import { type meta } from "../../meta";
import { type Prettify } from "development-kit/utility-types";

export type SiteMetadata = Prettify<
typeof meta & {
buildStamp: CacheVersion;
}
>;
25 changes: 22 additions & 3 deletions src/core/use-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,33 @@ import { authStoreActions } from "store/auth/auth.store";
import { docManagementStoreActions } from "store/doc-management/doc-management.store";
import { docStoreActions } from "store/doc/doc.store";
import { docsStoreActions } from "store/docs/docs.store";
import { initializeAPI } from "api-4markdown";
import { useYourUserProfileState } from "store/your-user-profile";
import { useMindmapCreatorState } from "store/mindmap-creator";
import { useYourAccountState } from "store/your-account";
import { initializeAPI } from "api-4markdown";
import { graphql, useStaticQuery } from "gatsby";
import { SiteMetadata } from "./models";

type SiteMetadataQuery = {
site: {
siteMetadata: Pick<SiteMetadata, "buildStamp">;
};
};

const useAuth = () => {
const [api] = React.useState(initializeAPI);
const data = useStaticQuery<SiteMetadataQuery>(graphql`
query BuildStampQuery {
site {
siteMetadata {
buildStamp
}
}
}
`);

const [api] = React.useState(() =>
initializeAPI(data.site.siteMetadata.buildStamp),
);

React.useEffect(() => {
const unsubscribe = api.onAuthChange((user) => {
Expand All @@ -35,7 +55,6 @@ const useAuth = () => {
return () => {
unsubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
};

Expand Down
9 changes: 8 additions & 1 deletion src/features/user-profile-preview/utils/get-profile-id.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { asUserProfileId } from "api-4markdown";
import { UserProfileId } from "api-4markdown-contracts";

const asUserProfileId = (value: unknown): UserProfileId => {
if (typeof value !== `string` || value.length === 0) {
throw new Error(`User profile ID must be a non-empty string`);
}

return value as UserProfileId;
};

const getProfileId = (): UserProfileId => {
const params = new URLSearchParams(window.location.search);
return asUserProfileId(params.get(`profileId`));
Expand Down
Loading