@backmatter/core 0.0.6 → 0.0.9
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/package.json +1 -1
- package/src/config.ts +46 -8
- package/src/index.ts +12 -1
- package/src/node/cli.ts +3 -1
- package/src/preview-session.ts +12 -1
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -15,9 +15,9 @@ export type BackmatterDirs = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export type BackmatterConfig = {
|
|
18
|
-
/**
|
|
18
|
+
/** Workspace id (`ws_…`), not the dashboard slug. Config first; env BACKMATTER_WORKSPACE_ID overrides gap. */
|
|
19
19
|
workspaceId?: string;
|
|
20
|
-
/**
|
|
20
|
+
/** CMS API origin. Config / BACKMATTER_API_URL, else cloud API on a deployed host when workspaceId is set. */
|
|
21
21
|
apiUrl?: string;
|
|
22
22
|
/** Env: BACKMATTER_CONTENT_TOKEN. Required only to read non-default branches. */
|
|
23
23
|
contentToken?: string;
|
|
@@ -53,6 +53,7 @@ export const DEFAULT_DIRS: Required<BackmatterDirs> = {
|
|
|
53
53
|
layouts: "layouts",
|
|
54
54
|
};
|
|
55
55
|
export const DEFAULT_LOCALE = "en";
|
|
56
|
+
export const CLOUD_API_URL = "https://api.backmatter.app";
|
|
56
57
|
|
|
57
58
|
function withHttps(url: string): string {
|
|
58
59
|
if (url.startsWith("http://") || url.startsWith("https://")) return url;
|
|
@@ -63,6 +64,46 @@ function stripTrailingSlash(url: string): string {
|
|
|
63
64
|
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
function envOf(): Record<string, string | undefined> {
|
|
68
|
+
return typeof process === "undefined" ? {} : process.env;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Vercel, Netlify, Cloudflare Pages, Railway, or NODE_ENV=production. */
|
|
72
|
+
export function isDeployedHost(env: Record<string, string | undefined>): boolean {
|
|
73
|
+
return Boolean(
|
|
74
|
+
env.VERCEL ||
|
|
75
|
+
env.NETLIFY ||
|
|
76
|
+
env.CF_PAGES ||
|
|
77
|
+
env.RAILWAY_ENVIRONMENT ||
|
|
78
|
+
env.NODE_ENV === "production",
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** DevBar /me origin: explicit, else env, else cloud API on a deployed host. */
|
|
83
|
+
export function resolveDevBarApiUrl(
|
|
84
|
+
explicit: string | undefined,
|
|
85
|
+
env: Record<string, string | undefined> = envOf(),
|
|
86
|
+
): string {
|
|
87
|
+
const fromProp = explicit?.trim();
|
|
88
|
+
if (fromProp) return stripTrailingSlash(fromProp);
|
|
89
|
+
const fromEnv = env.BACKMATTER_API_URL?.trim();
|
|
90
|
+
if (fromEnv) return stripTrailingSlash(fromEnv);
|
|
91
|
+
if (isDeployedHost(env)) return CLOUD_API_URL;
|
|
92
|
+
return "";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function detectApiUrl(
|
|
96
|
+
config: BackmatterConfig,
|
|
97
|
+
env: Record<string, string | undefined>,
|
|
98
|
+
workspaceId: string | undefined,
|
|
99
|
+
): string | undefined {
|
|
100
|
+
const explicit = config.apiUrl !== undefined ? config.apiUrl : env.BACKMATTER_API_URL;
|
|
101
|
+
const trimmed = explicit?.trim();
|
|
102
|
+
if (trimmed) return stripTrailingSlash(trimmed);
|
|
103
|
+
if (workspaceId && isDeployedHost(env)) return CLOUD_API_URL;
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
66
107
|
/** Public origin of the host that should receive `content.committed`. */
|
|
67
108
|
export function detectSiteUrl(
|
|
68
109
|
config: { siteUrl?: string } = {},
|
|
@@ -90,10 +131,6 @@ export function defineConfig(config: BackmatterConfig): BackmatterConfig {
|
|
|
90
131
|
return config;
|
|
91
132
|
}
|
|
92
133
|
|
|
93
|
-
function envOf(): Record<string, string | undefined> {
|
|
94
|
-
return typeof process === "undefined" ? {} : process.env;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
134
|
/** Explicit config wins; env vars fill the gaps; folder defaults last. */
|
|
98
135
|
export function resolveConfig(
|
|
99
136
|
config: BackmatterConfig = {},
|
|
@@ -104,9 +141,10 @@ export function resolveConfig(
|
|
|
104
141
|
const fromEnv = env[key]?.trim();
|
|
105
142
|
return fromEnv ? fromEnv : undefined;
|
|
106
143
|
};
|
|
144
|
+
const workspaceId = pick(config.workspaceId, "BACKMATTER_WORKSPACE_ID");
|
|
107
145
|
return {
|
|
108
|
-
workspaceId
|
|
109
|
-
apiUrl:
|
|
146
|
+
workspaceId,
|
|
147
|
+
apiUrl: detectApiUrl(config, env, workspaceId),
|
|
110
148
|
contentToken: pick(config.contentToken, "BACKMATTER_CONTENT_TOKEN"),
|
|
111
149
|
previewToken: pick(config.previewToken, "BACKMATTER_PREVIEW_TOKEN"),
|
|
112
150
|
hostToken: pick(config.hostToken, "BACKMATTER_HOST_TOKEN"),
|
package/src/index.ts
CHANGED
|
@@ -42,7 +42,16 @@ export type { DocFormat } from "./doc-format";
|
|
|
42
42
|
export { modelFormat, parseDoc, serializeDoc } from "./doc-format";
|
|
43
43
|
|
|
44
44
|
export type { BackmatterConfig, BackmatterDirs, ResolvedConfig } from "./config";
|
|
45
|
-
export {
|
|
45
|
+
export {
|
|
46
|
+
defineConfig,
|
|
47
|
+
resolveConfig,
|
|
48
|
+
detectSiteUrl,
|
|
49
|
+
isDeployedHost,
|
|
50
|
+
resolveDevBarApiUrl,
|
|
51
|
+
DEFAULT_DIRS,
|
|
52
|
+
DEFAULT_LOCALE,
|
|
53
|
+
CLOUD_API_URL,
|
|
54
|
+
} from "./config";
|
|
46
55
|
|
|
47
56
|
export type { RouteMatch, RouteModel, MatchRouteOptions } from "./routes";
|
|
48
57
|
export {
|
|
@@ -106,6 +115,8 @@ export {
|
|
|
106
115
|
PREVIEW_COOKIE,
|
|
107
116
|
PREVIEW_ENABLE_PATH,
|
|
108
117
|
PREVIEW_QUERY,
|
|
118
|
+
PREVIEW_CHECKOUT_QUERY,
|
|
119
|
+
previewLocationWithCheckout,
|
|
109
120
|
isSafeRedirectPath,
|
|
110
121
|
mintPreviewTicket,
|
|
111
122
|
previewMiddlewareDecision,
|
package/src/node/cli.ts
CHANGED
|
@@ -249,8 +249,10 @@ import { defineConfig } from "${from}";
|
|
|
249
249
|
// General settings only. Models live in models/*.ts, composer blocks in
|
|
250
250
|
// blocks/*.tsx, MDX tags in mdx/*.tsx, and content in
|
|
251
251
|
// content/{locale}/{type}/{slug}.{mdx,json} — all discovered automatically.
|
|
252
|
-
// workspaceId
|
|
252
|
+
// Set workspaceId from General settings (not an env var).
|
|
253
|
+
// API URL defaults to https://api.backmatter.app in production; tokens stay env.
|
|
253
254
|
export default defineConfig({
|
|
255
|
+
// workspaceId: "ws_…",
|
|
254
256
|
defaultLocale: "en",
|
|
255
257
|
});
|
|
256
258
|
`;
|
package/src/preview-session.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { signPayload, verifyPayload } from "./signed-token";
|
|
|
3
3
|
|
|
4
4
|
export const PREVIEW_COOKIE = "backmatter_preview";
|
|
5
5
|
export const PREVIEW_QUERY = "backmatter_preview";
|
|
6
|
+
export const PREVIEW_CHECKOUT_QUERY = "backmatter_checkout";
|
|
6
7
|
export const PREVIEW_ENABLE_PATH = "/api/backmatter/preview";
|
|
7
8
|
export const PREVIEW_TICKET_TTL_MS = 10 * 60 * 1000;
|
|
8
9
|
export const PREVIEW_COOKIE_TTL_MS = 12 * 60 * 60 * 1000;
|
|
@@ -80,6 +81,16 @@ export async function readPreviewTicket(secret: string, token: string): Promise<
|
|
|
80
81
|
return asTicket(await verifyPayload(secret, token));
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
export function previewLocationWithCheckout(
|
|
85
|
+
origin: string,
|
|
86
|
+
redirect: string,
|
|
87
|
+
checkout: string,
|
|
88
|
+
): string {
|
|
89
|
+
const location = new URL(redirect, origin);
|
|
90
|
+
location.searchParams.set(PREVIEW_CHECKOUT_QUERY, checkout);
|
|
91
|
+
return location.toString();
|
|
92
|
+
}
|
|
93
|
+
|
|
83
94
|
export async function writePreviewCookie(
|
|
84
95
|
secret: string,
|
|
85
96
|
input: PreviewCheckout & { exp: number },
|
|
@@ -124,7 +135,7 @@ export function previewMiddlewareDecision(url: URL, draftEnabled: boolean): Prev
|
|
|
124
135
|
if (ticket) {
|
|
125
136
|
return { type: "redirect", location: `${PREVIEW_ENABLE_PATH}?ticket=${encodeURIComponent(ticket)}` };
|
|
126
137
|
}
|
|
127
|
-
if (draftEnabled) {
|
|
138
|
+
if (draftEnabled || url.searchParams.get(PREVIEW_CHECKOUT_QUERY)?.trim()) {
|
|
128
139
|
return { type: "headers", headers: { ...PREVIEW_CACHE_HEADERS } };
|
|
129
140
|
}
|
|
130
141
|
return { type: "next" };
|