
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
@enonic/nextjs-adapter
Advanced tools
NextJS adapter with Guillotine support and basic views
npm i --save @enonic/nextjs-adapter
All functions and views are split into 4 categories by usage:
@enonic/nextjs-adapter
-- can be used both on server and client sides@enonic/nextjs-adapter/server
-- can only be used on server side@enonic/nextjs-adapter/client
-- can only be used on client side@enonic/nextjs-adapter/views/...
-- views folder, every view has its own file with a default exportHere's the usage example in your project:
// server-side functions are accessible at /server
import {fetchContent} from "@enonic/nextjs-adapter/server";
// views are placed in a folder called `views` and are default exports in files
import MainView from "@enonic/nextjs-adapter/views/MainView"
// ...
const props = await fetchContent(path, {
contentPath: '/content/path',
locale: 'en',
});
// ...
return <MainView {...props}/>
They are available at @enonic/nextjs-adapter/server
fetchContent(contentPath: string | string[], context: Context) => Promise<FetchContentResult>
Fetches the content/component by path with component queries optimization, page structure as well as runtime info calculation. This is the main method for querying content.
Argument | Description |
---|---|
context | Execution context |
Usage:
import {fetchContent} from '@enonic/nextjs-adapter/server';
import {headers} from 'next/headers';
const context = {
contentPath: '/current/content/path',
locale: 'en',
headers: headers(),
};
const response = fetchContent(context);
Response type:
type FetchContentResult = {
error?: {
code: string,
message: string
} | null;
data: Record<string, any> | null, // Result of the content query
common: Record<string, any> | null, // Result of the common query
meta: MetaData, // Runtime information
page: PageComponent | null, // The structure of the page (not present when rendering single component)
};
fetchGuillotine(apiUrl: string, mapping: LocaleMapping, options?: FetchOptions) => Promise<GuillotineResult>
Makes a custom request to Guillotine. Used by fetchContent() method.
Argument | Description |
---|---|
apiUrl | Guillotine API URL |
mapping | Mapping locale to project |
options | Request and Next.js config options (Optional) |
Usage:
import {fetchGuillotine} from '@enonic/nextjs-adapter/server';
import {getLocaleMapping} from '@enonic/nextjs-adapter';
const apiUrl = 'http://domain:8000/graphql/api';
const mapping = getLocaleMapping({
contentPath: '/current/content/path',
});
const body = {
query: 'qraphql query as string',
variables: {
foo: 'bar',
},
};
const headers = {
'custom-header': 'header-value',
};
const opts = {
body,
headers,
method: 'GET',
next: {
revalidate: 60,
tags: ['tag1', 'tag2'],
}
};
const result = fetchGuillotine(apiUrl, mapping, opts);
Response type:
type GuillotineResult = {
error?: {
code: string,
message: string
} | null;
[dataKey: string]: any;
};
fetchFromApi(apiUrl: string, mapping: LocaleMapping, options?: FetchOptions) => Promise<GuillotineResponseJson>
Makes custom third-party service request. Used by the fetchGuillotine() method.
Argument | Description |
---|---|
apiUrl | Service API URL |
mapping | Mapping locale to project |
options | Request and Next.js config options (Optional) |
Usage:
import {fetchFromApi} from '@enonic/nextjs-adapter/server';
import {getLocaleMapping} from '@enonic/nextjs-adapter';
const apiUrl = 'http://domain:8000/graphql/api';
const mapping = getLocaleMapping({
contentPath: '/current/content/path',
});
const body = {
query: 'qraphql query as string',
variables: {
foo: 'bar',
},
}
const headers = {
'custom-header': 'header-value',
}
const opts = {
body,
headers,
method: 'POST',
next: {
revalidate: 60,
tags: ['tag1', 'tag2'],
}
};
const result = fetchFromApi(apiUrl, mapping, opts);
fetchContentPathsForAllLocales(path: string, query?: string, count?: number) => Promise<ContentPathItem[]>
Loads all content paths for all locales. Generally used for static site generation.
Argument | Description |
---|---|
path | Root content path |
query | Request and Next.js config options (Optional) * |
count | Max result count (Optional, defaults to 999) |
* Default query gets up to count
results, sorts them by modifiedTime
and excludes following content types:
"base:shortcut",
"portal:fragment",
"portal:template-folder",
"portal:page-template",
"media:*"
Usage:
import {fetchContentPathsForAllLocales} from '@enonic/nextjs-adapter/server';
const contentPaths = fetchContentPathsForLocale('/site-name', 'custom graphql query', 1001);
fetchContentPathsForLocale(path: string, mapping: LocaleMapping, query?: string, count?: number) => Promise<ContentPathItem[]>
Loads all content paths for the current locale. Generally used for static site generation. Used by fetchContentPathsForAllLocales()
Argument | Description |
---|---|
path | Root content path |
mapping | Mapping locale to project |
query | Request and Next.js config options (Optional, default value here) |
count | Max result count (Optional, defaults to 999) |
Usage:
import {fetchContentPathsForLocale} from '@enonic/nextjs-adapter/server';
import {getLocaleMapping} from '@enonic/nextjs-adapter';
const mapping = getLocaleMapping({
contentPath: '/current/content/path',
});
const contentPaths = fetchContentPathsForLocale('/', mapping, 'custom graphql query', 1001);
They are available at @enonic/nextjs-adapter/client
<LocaleContextProvider locale="en">
Create a React.js context that allows child elements to access and modify current locale as well as localize static texts for current locale. See useLocaleContext() method for example.
Argument | Type | Description |
---|---|---|
locale | String | Set the initial locale value |
Usage:
import {LocaleContextProvider} from '@enonic/nextjs-adapter/client';
<LocaleContextProvider locale="en"> ...child elements... </LocaleContextProvider>
useLocaleContext() => LocaleContextType
Methods to access and modify current locale as well as localize static texts, where LocaleContextType
is:
interface LocaleContextType {
dictionary: Dict
locale: string
localize: (key: string, ...args: any[]) => string
setLocale: (locale: string) => Promise<Dict>
}
Usage:
'use client';
import {useLocaleContext} from '@enonic/nextjs-adapter/client';
export default function ClientSideComponent() {
const {locale, localize, setLocale} = useLocaleContext();
console.log(`Current locale: ${locale}`);
const localizedText = localize('text.key');
setLocale('en').then((dict) => {
console.log(`New locale: ${locale}`);
});
// ...
}
They are available at @enonic/nextjs-adapter
getUrl(url: string, meta: MetaData) => string
Converts a site-relative or absolute URL to relative one for current viewer (Next.js/Enonic XP). Also takes care of locale if needed.
INFO: For your URLs to work both in Enonic XP and Next.js you need to:
- Query site-relative or absolute URLs from guillotine
- Wrap them with
getUrl()
function in the views
Argument | Description |
---|---|
url | URL you want to transform |
meta | Runtime data returned by fetchContent |
Usage:
import {getUrl} from '@enonic/nextjs-adapter';
const urlRelativeToViewer = getUrl('/some/content/url', meta);
getAsset(url: string, meta: MetaData) => string
Converts a local asset URL to relative one for current viewer (Next.js/Enonic XP). It doesn't append locales unlike the getUrl().
INFO: For your URLs to work both in Enonic XP and Next.js you need to:
- Use relative URL to local asset
- Wrap them with
getAsset()
function in the views
Argument | Description |
---|---|
url | asset URL you want to transform |
meta | Runtime data returned by fetchContent |
Usage:
import {getAsset} from '@enonic/nextjs-adapter';
const urlRelativeToViewer = getAsset('/some/asset/url', meta);
richTextQuery(fieldName: string) => string
This is a utility function for querying for RichTextData
needed for RichTextView. It creates a graphql query string for
HTML area input type with given field name.
Argument | Description |
---|---|
fieldName | HTML area field name |
Usage:
import {richTextQuery} from '@enonic/nextjs-adapter';
const query = `query($path:ID!){
guillotine {
get(key:$path) {
_path
type
${richTextQuery('htmlField')}
}
}
}`;
validateData(props: FetchContentResult) => void
Utility method to validate data returned by fetchContent() method. Throws an error or notFound() if data is invalid. Also prevents shortcut content types from being rendered in preview/edit modes.
Argument | Description |
---|---|
props | FetchContentResult object |
Usage:
import {fetchContent} from '@enonic/nextjs-adapter/server';
import {validateData} from '@enonic/nextjs-adapter';
const data = fetchContent({
contentPath: '/path/to/content',
locale: 'en',
});
validateData(data);
ComponentRegistry
Registry containing definitions of all components (i.e. pages, parts, layouts, macros, etc. ). It is used in the runtime by nextjs-adapter
to make component queries and render components. It has several public methods:
static setCommonQuery(query: SelectedQueryMaybeVariablesFunc): void
Sets up a common query that is going to be executed along with component queries and passed to every component on the page.
Argument | Description |
---|---|
query | Common query definition |
Usage:
import {ComponentRegistry} from '@enonic/nextjs-adapter';
const query = {
query: 'graphql query',
variables: (path, context, config) => {
return {
path: path + '/some/processing'
};
}
}
ComponentRegistry.setCommonQuery(query);
static getCommonQuery(): SelectedQueryMaybeVariablesFunc
Gets the common query definition.
type SelectedQueryMaybeVariablesFunc =
string |
QueryGetter |
{
query: string | QueryGetter,
variables: VariablesGetter
} |
[string | QueryGetter, VariablesGetter];
Usage:
import {ComponentRegistry} from '@enonic/nextjs-adapter';
const query = ComponentRegistry.getCommonQuery();
static getByComponent(component: PageComponent): ComponentDefinition | undefined
Gets component definition from the ComponentRegistry.
Argument | Description |
---|---|
component | Page component to get definition for |
Usage:
import {ComponentRegistry} from '@enonic/nextjs-adapter';
const definition = ComponentRegistry.getByComponent(component);
interface ComponentDefinition {
catchAll?: boolean; // set automatically depending on the binding
query?: SelectedQueryMaybeVariablesFunc,
configQuery?: string,
processor?: DataProcessor,
view?: React.FunctionComponent<any>
}
static addMacro(name: string, obj: ComponentDefinition): void
static addPart(name: string, obj: ComponentDefinition): void
static addLayout(name: string, obj: ComponentDefinition): void
static addCPage(name: string, obj: ComponentDefinition): void
static addContentType(name: string, obj: ComponentDefinition): void
static addComponent(name: string, obj: ComponentDefinition): void
Saves the component definition in ComponentRegistry by name.
NOTE:
addComponent
is used for defining general types of Enonic XP components bynextjs-adapter
so you don't need to do it manually. Overriding default setup may break Enonic XP integration!
Argument | Description |
---|---|
name | Component name |
obj | Component definition |
Usage:
import {ComponentRegistry} from '@enonic/nextjs-adapter';
const definition = {}
ComponentRegistry.addMacro('macro-name', definition);
static getMacro(name: string): ComponentDefinition | undefined
static getPart(name: string): ComponentDefinition | undefined
static getLayout(name: string): ComponentDefinition | undefined
static getPage(name: string): ComponentDefinition | undefined
static getContentType(name: string): ComponentDefinition | undefined
static getComponent(name: string): ComponentDefinition | undefined
Gets the component definition stored in ComponentRegistry by its name.
NOTE: Read addComponent note before using
getComponent
.
Argument | Description |
---|---|
name | Component name |
Usage:
import {ComponentRegistry} from '@enonic/nextjs-adapter';
const definition = ComponentRegistry.getMacro('macro-name');
Response type: component definition
static getMacros(): ComponentDefinition[]
static getParts(): ComponentDefinition[]
static getLayouts(): ComponentDefinition[]
static getPages(): ComponentDefinition[]
static getContentTypes(): ComponentDefinition[]
static getComponents(): ComponentDefinition[]
Gets all component definitions stored in ComponentRegistry.
NOTE: Read addComponent note before using
getComponents
.
Usage:
import {ComponentRegistry} from '@enonic/nextjs-adapter';
const macros = ComponentRegistry.getMacros();
Response type: List of component definitions
UrlProcessor
Helper singleton for processing URLs.
static process(url: string, meta: MetaData, serverSide = false, isResource = false): string
Processes the absolute URL to become relative for the current viewer, while keeping in mind Next.js assets and Enonic XP binary content links
NOTE: There are convenience aliases to this function called getUrl() and getAsset()
Argument | Description |
---|---|
url | Absolute URL |
meta | Runtime data returned by fetchContent |
serverSide | Whether URL is going to be used on the server side (Skips adding basePath) |
isResource | Whether URL is a resource (Skips adding locale) |
Usage:
import {UrlProcessor} from '@enonic/nextjs-adapter';
const url = UrlProcessor.process('http://www.some.site.com/url/to/content', meta, true, false);
static processSrcSet(srcset: string, meta: MetaData): string
Processes the image srcset attribute to transform each URL with process
method
Argument | Description |
---|---|
srcset | Value of the srcset attribute |
meta | Runtime data returned by fetchContent |
Usage:
import {UrlProcessor} from '@enonic/nextjs-adapter';
const url = UrlProcessor.processSrcSet('<srcset value>', meta);
static setSiteKey(key: string): void
DEPRECATED: It is automatically done by
nextjs-adapter
now and have no effect.
Sets the site key value that is needed for correct absolute URL processing.
Argument | Description |
---|---|
key | Site key |
Usage:
import {UrlProcessor} from '@enonic/nextjs-adapter';
UrlProcessor.setSiteKey('<site key>');
static isMediaLink(ref: string, linkData: LinkData[]): boolean
Checks if link data array contains link with provided ref. Positive result means that this is a link to Enonic XP content.
NOTE: link data array is contained in response of the query generated by richTextQuery('fieldName')
Argument | Description |
---|---|
ref | Link ref |
linkData | Link data array |
Usage:
import {UrlProcessor} from '@enonic/nextjs-adapter';
UrlProcessor.isMediaLink('<link ref>', linkData);
static isContentImage(ref: string, imageData: ImageData[]): boolean
Checks if image data array contains image with provided ref. Positive response means that this is an Enonic XP image.
NOTE: image data array is contained in response of the query generated by richTextQuery('fieldName')
Argument | Description |
---|---|
ref | Image ref |
imageData | Image data array |
Usage:
import {UrlProcessor} from '@enonic/nextjs-adapter';
UrlProcessor.isContentImage('<image ref>', imageData);
In order to create association between locale and Enonic XP project, ENONIC_MAPPINGS
environment variable should be set.
Functions for reading those mappings are available at @enonic/nextjs-adapter
.
getLocaleMapping(context: Context): LocaleMapping
Argument | Description |
---|---|
context | Context object |
Usage:
import {getLocaleMapping} from '@enonic/nextjs-adapter';
const mapping = getLocaleMapping({
contentPath: '/current/content/path',
locale: 'en',
});
export interface LocaleMapping {
default: boolean
project: string
site: string
locale: string
}
getLocaleMappingByProjectId(projectId?: string, useDefault = true): LocaleMapping
Argument | Description |
---|---|
projectId | Enonic project ID (Optional) |
useDefault | Use default locale as fallback (Optional, default: true) |
Usage:
import {getLocaleMappingByProjectId} from '@enonic/nextjs-adapter';
const mapping = getLocaleMappingByProjectId('project-id', true);
getLocaleMappingByLocale(locale?: string, useDefault = true): LocaleMapping
Argument | Description |
---|---|
locale | locale ID (Optional) |
useDefault | Use default locale as fallback (Optional, default: true) |
Usage:
import {getLocaleMappingByLocale} from '@enonic/nextjs-adapter';
const mapping = getLocaleMappingByLocale('en', true);
getRequestLocaleInfo(context: Context): LocaleMapping
Attempts to get the locale info from the request. Along with that it also returns the default locale and all configured locales.
Argument | Description |
---|---|
context | Context object |
Usage:
import {getRequestLocaleInfo} from '@enonic/nextjs-adapter';
const mapping = getRequestLocaleInfo({
contentPath: '/current/content/path',
locale: 'en',
});
Response type:
interface LocaleInfo {
locale: string,
locales: string[],
defaultLocale: string
}
I18n
localization functionsThese functions can be used both on server and client sides, but it is recommended to use native React.js context classes for client-side localization.
static I18n.setLocale(locale: string): Promise<Dict>
Sets the current locale and returns the dictionary for it.
Argument | Description |
---|---|
locale | Locale id, i.e. en |
Usage:
import {I18n} from '@enonic/nextjs-adapter';
const dict = await I18n.setLocale('en');
interface Dict {
[key: string]: string
}
static I18n.localize(key: string, ...args: any[]): string
Localizes the static text by key and replaces placeholders with provided arguments.
Argument | Description |
---|---|
key | text key |
...args | template arguments |
Usage:
import {I18n} from '@enonic/nextjs-adapter';
const localizedText = I18n.localize('text.key', 'value1', 'value2');
static I18n.getLocale(): string
Returns the current locale.
Usage:
import {I18n} from '@enonic/nextjs-adapter';
const locale = I18n.getLocale();
static I18n.getDictionary(): Dict
Returns dictionary for the current locale.
Usage:
import {I18n} from '@enonic/nextjs-adapter';
const dict = I18n.getDictionary();
There is also a number of utility constants and functions available at @enonic/nextjs-adapter
.
import {CATCH_ALL} from './constants';
IS_DEV_MODE; // True if current mode == development
APP_NAME; // Name of the app defined in .env files
APP_NAME_UNDERSCORED; // APP_NAME with underscores instead of dots
APP_NAME_DASHED; // APP_NAME with dashes instead of dots
CATCH_ALL; // Catch all component name
PORTAL_COMPONENT_ATTRIBUTE; // Portal component attribute name
PORTAL_REGION_ATTRIBUTE; // Portal region attribute name
JSESSIONID_HEADER; // JSESSIONID header name
PROJECT_ID_HEADER; // Project ID header name
RENDER_MODE_HEADER; // Render mode header name
XP_BASE_URL_HEADER; // XP base URL header name
enum XP_REQUEST_TYPE { // Enum for XP request types
COMPONENT = 'component',
TYPE = 'type',
PAGE = 'page',
}
enum RENDER_MODE { // Enum for render modes
INLINE = 'inline',
EDIT = 'edit',
PREVIEW = 'preview',
LIVE = 'live',
ADMIN = 'admin',
NEXT = 'next',
}
enum XP_COMPONENT_TYPE { // Enum for XP component types
PART = 'part',
LAYOUT = 'layout',
TEXT = 'text',
FRAGMENT = 'fragment',
PAGE = 'page',
}
// Sanitizes text according to graphql naming spec http://spec.graphql.org/October2021/#sec-Names
const sanitizeGraphqlName = (text: string) => string;
// Returns full content api URL with current project and branch appended
const getContentApiUrl = (context: Context) => string;
They are located in @enonic/nextjs-adapter/views
folder. Each view is a default export in the corresponding file.
<MainView common="common" data="data" page="page" meta="meta">
The main view of the application. It accepts the result of fetchContent method and is intended to be used as a view for your next.js route
Argument | Type | Description |
---|---|---|
common | Record<string, any> | null | Result of the common query |
data | Record<string, any> | null | Result of the graphql query |
page | PageComponent | null | Page structure |
meta | MetaData | Runtime info |
Usage:
import MainView from '@enonic/nextjs-adapter/views/MainView';
import fetchContent from '@enonic/nextjs-adapter';
export async function getServerSideProps(context: Context) {
const props = fetchContent('/content/path', context);
return {
props
}
}
export default MainView;
<StaticContent condition="true" tag="div">
Tag for disabling client side hydration if the condition is true. This will remove interactivity from children.
Argument | Type | Description |
---|---|---|
condition = true | Boolean | Condition to trigger static output |
tag = 'div' | String | Html tag to use for static output |
Usage:
import StaticContent from '@enonic/nextjs-adapter/views/StaticContent';
<StaticContent condition={true} tag="div"> ...child elements... </StaticContent>
<RichTextView className="css-class" tag="section" data={data} meta={meta}, renderMacroInEditMode="true", customReplacer={customReplacerFn}>
Tag for displaying contents of html area input types. Takes care of processing macros, URLs and images inside.
Argument | Type | Description |
---|---|---|
data | RichTextData | Rich text data |
meta | MetaData | Runtime data returned by fetchContent method. |
customReplacer | Replacer | Function to do custom element processing. Not invoked for image, link and macro nodes. Optional |
className | String | Class name to add to the root html element. Optional |
renderMacroInEditMode = true | boolean | Flag passed to macros telling if they should render themselves in edit mode |
tag = 'div' | String | Html tag to use as a root |
TIP! There is a utility function richTextQuery(fieldName) generating part of the graphql query to obtain
RichTextData
for html area input types.
Usage:
import RichTextView from '@enonic/nextjs-adapter/views/RichTextView';
<RichTextView data={richTextData} meta={meta} tag="section" className="rich-text-view" renderMacroInEditMode="false"></RichTextView>
<Regions page={page} meta={meta} name="main" common={common}>
Tag for rendering page regions. It is useful when implementing custom page views. All necessary data can be acquired by running fetchContent()
Argument | Type | Description |
---|---|---|
page | PageData | null; | Page structure |
meta | MetaData | Runtime info |
name | String | Render only this region. Optional |
common | any | Result of common query. Optional |
Usage:
import StaticContent from '@enonic/nextjs-adapter/views/StaticContent';
<StaticContent condition={true} tag="div"> ...child elements... </StaticContent>
FAQs
> NextJS adapter with Guillotine support and basic views
The npm package @enonic/nextjs-adapter receives a total of 100 weekly downloads. As such, @enonic/nextjs-adapter popularity was classified as not popular.
We found that @enonic/nextjs-adapter demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.