strapi-nextgen-framework
Version:
Production-ready, type-safe framework bridging Strapi v4 CMS and Next.js 14+ App Router with automatic cache management, Error Boundaries, and SEO optimization
166 lines • 6.07 kB
JavaScript
;
/**
* Data Layer (SDK) - Phase 2 Implementation
* GraphQL-first SDK with automatic cache tagging for Next.js
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createStrapiSDK = void 0;
const graphql_request_1 = require("graphql-request");
const fetch_wrapper_1 = require("./fetch-wrapper");
const cache_tags_1 = require("./cache-tags");
const headers_1 = require("next/headers");
/**
* Creates a configured Strapi SDK instance
*
* @param config - SDK configuration options
* @returns Configured SDK instance
*
* @example
* ```typescript
* const strapiClient = createStrapiSDK({
* url: process.env.STRAPI_URL,
* token: process.env.STRAPI_TOKEN,
* });
* ```
*/
function createStrapiSDK(config) {
// Validate required configuration
if (!config.url) {
throw new Error('Strapi URL is required in SDK configuration');
}
// Create base headers
const baseHeaders = {};
if (config.token) {
baseHeaders.Authorization = `Bearer ${config.token}`;
}
// Create GraphQL client
const client = new graphql_request_1.GraphQLClient(config.url, {
headers: baseHeaders,
fetch: (0, fetch_wrapper_1.createCacheTaggedFetch)(config.logging),
});
// Check if draft mode is active (Next.js 14+)
const isDraftMode = () => {
try {
return (0, headers_1.draftMode)().isEnabled;
}
catch {
// Not in a request context or draft mode not available
return false;
}
};
// Helper to build GraphQL variables with locale and filters
const buildVariables = (options) => {
const variables = {};
if (options?.locale) {
variables.locale = options.locale;
}
if (options?.filters) {
variables.filters = options.filters;
}
if (options?.sort) {
variables.sort = options.sort;
}
if (options?.pagination) {
variables.pagination = options.pagination;
}
// Add publicationState for draft mode
if (isDraftMode()) {
variables.publicationState = 'PREVIEW';
}
return variables;
};
return {
/**
* Fetch a single page by slug
*/
async getPage(slug, options) {
const tag = (0, cache_tags_1.generateCacheTag)('page', slug, options?.locale);
if (config.logging?.queries) {
console.log(`[Strapi SDK] getPage: ${slug}`, { tag, options });
}
// This is a simplified query - in real usage, developers will use graphql-codegen
// to generate typed queries from their .graphql files
const query = `
query GetPage($slug: String!, $locale: String, $publicationState: PublicationState) {
pages(filters: { slug: { eq: $slug } }, locale: $locale, publicationState: $publicationState) {
data {
id
attributes
}
}
}
`;
const variables = { slug, ...buildVariables(options) };
// Note: Cache tags are handled by the custom fetch wrapper
// graphql-request doesn't support Next.js options directly
const data = await client.request(query, variables);
const firstPage = data.pages.data[0];
if (!firstPage) {
throw new Error(`Page not found: ${slug}`);
}
return firstPage;
},
/**
* Fetch a collection of items
*/
async getCollection(collection, options) {
const tag = (0, cache_tags_1.generateCacheTag)('collection', collection, options?.locale);
if (config.logging?.queries) {
console.log(`[Strapi SDK] getCollection: ${collection}`, { tag, options });
}
// Simplified query - real usage will use graphql-codegen
const query = `
query GetCollection($locale: String, $filters: JSON, $sort: [String], $pagination: PaginationArg, $publicationState: PublicationState) {
${collection}(locale: $locale, filters: $filters, sort: $sort, pagination: $pagination, publicationState: $publicationState) {
data {
id
attributes
}
}
}
`;
const variables = buildVariables(options);
const data = await client.request(query, variables);
const collectionData = data[collection];
return collectionData ? collectionData.data : [];
},
/**
* Fetch global/singleton data
*/
async getGlobal(identifier, options) {
const tag = (0, cache_tags_1.generateCacheTag)('global', identifier, options?.locale);
if (config.logging?.queries) {
console.log(`[Strapi SDK] getGlobal: ${identifier}`, { tag, options });
}
// Simplified query - real usage will use graphql-codegen
const query = `
query GetGlobal($locale: String, $publicationState: PublicationState) {
${identifier}(locale: $locale, publicationState: $publicationState) {
data {
id
attributes
}
}
}
`;
const variables = buildVariables(options);
const data = await client.request(query, variables);
const globalData = data[identifier];
if (!globalData) {
throw new Error(`Global not found: ${identifier}`);
}
return globalData.data;
},
/**
* Execute a raw GraphQL query (escape hatch)
*/
async rawQuery(query, variables) {
if (config.logging?.queries) {
console.log('[Strapi SDK] rawQuery', { query, variables });
}
return client.request(query, variables);
},
};
}
exports.createStrapiSDK = createStrapiSDK;
//# sourceMappingURL=index.js.map