@sequoialabs/payload-plugin-reversia 0.1.8 → 0.2.0

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/README.md CHANGED
@@ -71,6 +71,7 @@ Then mark whichever fields are translatable. **You don't need to annotate contai
71
71
  - **[Field annotations](./docs/field-annotations.md)** — the `custom.reversia` metadata reference.
72
72
  - **[Rich text & JSON fields](./docs/rich-text.md)** — `translatableKeys`, path patterns, and the `extract`/`apply` escape hatch.
73
73
  - **[API reference](./docs/api-reference.md)** — HTTP endpoints consumed by the Reversia SaaS.
74
+ - **[Triggering crawls](./docs/trigger-crawl.md)** — `triggerCrawl()` for server code and `useTriggerCrawl()` for admin UI.
74
75
  - **[Contributing](./CONTRIBUTING.md)** — local dev, linting, testing.
75
76
 
76
77
  ## Requirements
@@ -0,0 +1 @@
1
+ export { type TriggerCrawlArgs, type TriggerCrawlOutcome, type TriggerCrawlStatus, type UseTriggerCrawlOptions, type UseTriggerCrawlResult, useTriggerCrawl, } from './use-trigger-crawl';
@@ -0,0 +1 @@
1
+ export { useTriggerCrawl, } from './use-trigger-crawl';
@@ -0,0 +1,30 @@
1
+ import type { CollectionSlug, GlobalSlug } from 'payload';
2
+ export type TriggerCrawlStatus = 'idle' | 'pending' | 'success' | 'error';
3
+ export interface UseTriggerCrawlOptions {
4
+ /**
5
+ * Override the server endpoint path. Defaults to
6
+ * `/api/reversia/dashboard/trigger-crawl`.
7
+ */
8
+ endpoint?: string;
9
+ }
10
+ export interface TriggerCrawlArgs {
11
+ /**
12
+ * Collection and/or global slugs to crawl. Slugs are prefixed with
13
+ * `payloadcms:` server-side before reaching Reversia. Omit/empty to crawl
14
+ * every enabled resource for the project.
15
+ */
16
+ types?: Array<CollectionSlug | GlobalSlug>;
17
+ /** Bypass cached crawl content. Defaults to `false`. */
18
+ noCache?: boolean;
19
+ }
20
+ export interface TriggerCrawlOutcome {
21
+ success: boolean;
22
+ error?: string;
23
+ }
24
+ export interface UseTriggerCrawlResult {
25
+ trigger: (args?: TriggerCrawlArgs) => Promise<TriggerCrawlOutcome>;
26
+ status: TriggerCrawlStatus;
27
+ error: string | null;
28
+ reset: () => void;
29
+ }
30
+ export declare function useTriggerCrawl(options?: UseTriggerCrawlOptions): UseTriggerCrawlResult;
@@ -0,0 +1,43 @@
1
+ 'use client';
2
+ import { useCallback, useState } from 'react';
3
+ const DEFAULT_ENDPOINT = '/api/reversia/dashboard/trigger-crawl';
4
+ export function useTriggerCrawl(options = {}) {
5
+ const endpoint = options.endpoint ?? DEFAULT_ENDPOINT;
6
+ const [status, setStatus] = useState('idle');
7
+ const [error, setError] = useState(null);
8
+ const trigger = useCallback(async (args = {}) => {
9
+ setStatus('pending');
10
+ setError(null);
11
+ try {
12
+ const response = await fetch(endpoint, {
13
+ method: 'POST',
14
+ headers: { 'Content-Type': 'application/json' },
15
+ credentials: 'same-origin',
16
+ body: JSON.stringify({
17
+ ...(args.types && args.types.length > 0 ? { types: args.types } : {}),
18
+ ...(args.noCache ? { noCache: true } : {}),
19
+ }),
20
+ });
21
+ const body = (await response.json().catch(() => ({})));
22
+ if (!response.ok || body.success === false) {
23
+ const message = body.error ?? `Request failed (${response.status})`;
24
+ setStatus('error');
25
+ setError(message);
26
+ return { success: false, error: message };
27
+ }
28
+ setStatus('success');
29
+ return { success: true };
30
+ }
31
+ catch (err) {
32
+ const message = err instanceof Error ? err.message : String(err);
33
+ setStatus('error');
34
+ setError(message);
35
+ return { success: false, error: message };
36
+ }
37
+ }, [endpoint]);
38
+ const reset = useCallback(() => {
39
+ setStatus('idle');
40
+ setError(null);
41
+ }, []);
42
+ return { trigger, status, error, reset };
43
+ }
@@ -1,3 +1,3 @@
1
1
  import type { Endpoint } from 'payload';
2
- import type { ReversiaPluginConfig } from '../types.js';
2
+ import type { ReversiaPluginConfig } from '../types';
3
3
  export declare function createConfirmResourcesSyncEndpoint(pluginConfig: ReversiaPluginConfig): Endpoint;
@@ -1,5 +1,5 @@
1
- import { unauthorizedResponse, validateApiKey } from '../utils/auth.js';
2
- import { decodeCursor } from '../utils/cursor.js';
1
+ import { unauthorizedResponse, validateApiKey } from '../utils/auth';
2
+ import { decodeCursor } from '../utils/cursor';
3
3
  export function createConfirmResourcesSyncEndpoint(pluginConfig) {
4
4
  return {
5
5
  path: '/reversia/confirm-resources-sync',
@@ -1,3 +1,3 @@
1
1
  import type { CollectionConfig, Endpoint, GlobalConfig } from 'payload';
2
- import type { ReversiaPluginConfig } from '../types.js';
2
+ import type { ReversiaPluginConfig } from '../types';
3
3
  export declare function createResourceEndpoint(pluginConfig: ReversiaPluginConfig, collectionsMap: Map<string, CollectionConfig>, globalsMap: Map<string, GlobalConfig>): Endpoint;
@@ -1,6 +1,6 @@
1
- import { unauthorizedResponse, validateApiKey } from '../utils/auth.js';
2
- import { findLocalizedFields, serializeField } from '../utils/fields.js';
3
- import { resolveDefaultLocale } from '../utils/payload-helpers.js';
1
+ import { unauthorizedResponse, validateApiKey } from '../utils/auth';
2
+ import { findLocalizedFields, serializeField } from '../utils/fields';
3
+ import { resolveDefaultLocale } from '../utils/payload-helpers';
4
4
  function extract(doc, fields) {
5
5
  const content = {};
6
6
  const contentTypes = {};
@@ -1,3 +1,3 @@
1
1
  import type { CollectionConfig, Endpoint, GlobalConfig } from 'payload';
2
- import type { ReversiaPluginConfig } from '../types.js';
2
+ import type { ReversiaPluginConfig } from '../types';
3
3
  export declare function createResourcesDefinitionEndpoint(pluginConfig: ReversiaPluginConfig, collectionsMap: Map<string, CollectionConfig>, globalsMap: Map<string, GlobalConfig>): Endpoint;
@@ -1,6 +1,6 @@
1
- import { unauthorizedResponse, validateApiKey } from '../utils/auth.js';
2
- import { buildTranslatableConfiguration, findLocalizedFields } from '../utils/fields.js';
3
- import { resolveStaticLabel } from '../utils/labels.js';
1
+ import { unauthorizedResponse, validateApiKey } from '../utils/auth';
2
+ import { buildTranslatableConfiguration, findLocalizedFields } from '../utils/fields';
3
+ import { resolveStaticLabel } from '../utils/labels';
4
4
  export function createResourcesDefinitionEndpoint(pluginConfig, collectionsMap, globalsMap) {
5
5
  return {
6
6
  path: '/reversia/resources-definition',
@@ -1,3 +1,3 @@
1
1
  import type { CollectionConfig, Endpoint, GlobalConfig } from 'payload';
2
- import type { ReversiaPluginConfig } from '../types.js';
2
+ import type { ReversiaPluginConfig } from '../types';
3
3
  export declare function createResourcesInsertEndpoint(pluginConfig: ReversiaPluginConfig, collectionsMap: Map<string, CollectionConfig>, globalsMap: Map<string, GlobalConfig>): Endpoint;
@@ -1,5 +1,5 @@
1
- import { unauthorizedResponse, validateApiKey } from '../utils/auth.js';
2
- import { deflatePopulatedRelationships, deserializeFieldValue, findLocalizedFields, } from '../utils/fields.js';
1
+ import { unauthorizedResponse, validateApiKey } from '../utils/auth';
2
+ import { deflatePopulatedRelationships, deserializeFieldValue, findLocalizedFields, } from '../utils/fields';
3
3
  const WRITE_CONFLICT_MAX_RETRIES = 3;
4
4
  const WRITE_CONFLICT_BASE_DELAY_MS = 50;
5
5
  function isWriteConflict(error) {
@@ -109,7 +109,24 @@ function applyTranslations({ allowedFields, data, sourceDoc, previousDoc, }) {
109
109
  continue;
110
110
  }
111
111
  const sourceValue = source ? source[fieldName] : undefined;
112
- const finalValue = deserializeFieldValue(field, sourceValue, translatedValue);
112
+ let finalValue;
113
+ try {
114
+ finalValue = deserializeFieldValue(field, sourceValue, translatedValue);
115
+ }
116
+ catch (error) {
117
+ // Re-throw with the offending field name attached so the caller's
118
+ // logger can pinpoint which container's source-locale shape blew up
119
+ // (e.g. a richText with a missing `children` array, an array item
120
+ // without an `id`). Without this, the surface error is something like
121
+ // "Cannot set properties of undefined (setting '0')" with no clue
122
+ // which field caused it across a multi-field document.
123
+ const message = error instanceof Error ? error.message : String(error);
124
+ const wrapped = new Error(`field "${fieldName}" failed to deserialize: ${message}`);
125
+ if (error instanceof Error && error.stack) {
126
+ wrapped.stack = error.stack;
127
+ }
128
+ throw wrapped;
129
+ }
113
130
  updateData[fieldName] = finalValue;
114
131
  acceptedFields.push(fieldName);
115
132
  const prevValue = previous ? previous[fieldName] : undefined;
@@ -140,6 +157,7 @@ function applyTranslations({ allowedFields, data, sourceDoc, previousDoc, }) {
140
157
  */
141
158
  async function dropUniqueCollisions(params) {
142
159
  const { payload, collection, id, locale, fields, updateData, acceptedFields, diff } = params;
160
+ const dropped = [];
143
161
  for (const field of fields) {
144
162
  if (field.isContainer || !field.unique) {
145
163
  continue;
@@ -169,6 +187,7 @@ async function dropUniqueCollisions(params) {
169
187
  id,
170
188
  targetLocale: locale,
171
189
  field: field.name,
190
+ value,
172
191
  collidingDocId: existing.docs[0]?.id,
173
192
  }, '[reversia] skipping field to avoid unique collision');
174
193
  delete updateData[field.name];
@@ -177,7 +196,9 @@ async function dropUniqueCollisions(params) {
177
196
  acceptedFields.splice(acceptedIdx, 1);
178
197
  }
179
198
  delete diff[field.name];
199
+ dropped.push(field.name);
180
200
  }
201
+ return dropped;
181
202
  }
182
203
  export function createResourcesInsertEndpoint(pluginConfig, collectionsMap, globalsMap) {
183
204
  return {
@@ -293,7 +314,7 @@ export function createResourcesInsertEndpoint(pluginConfig, collectionsMap, glob
293
314
  response.errors.push(`Item ${index}: no recognised fields in data (keys: ${Object.keys(item.data).join(', ')})`);
294
315
  continue;
295
316
  }
296
- await dropUniqueCollisions({
317
+ const droppedForUnique = await dropUniqueCollisions({
297
318
  payload: req.payload,
298
319
  collection: slug,
299
320
  id: itemId,
@@ -304,7 +325,7 @@ export function createResourcesInsertEndpoint(pluginConfig, collectionsMap, glob
304
325
  diff,
305
326
  });
306
327
  if (acceptedFields.length === 0 || Object.keys(updateData).length === 0) {
307
- response.errors.push(`Item ${index}: all translatable fields skipped due to unique-constraint collisions in ${item.targetLocale}`);
328
+ response.errors.push(`Item ${index} (${item.type} ${itemId} → ${item.targetLocale}): all translatable fields skipped due to unique-constraint collisions [${droppedForUnique.join(', ')}]`);
308
329
  continue;
309
330
  }
310
331
  await withRetry(() => req.payload.update({
@@ -1,3 +1,3 @@
1
1
  import type { CollectionConfig, Endpoint } from 'payload';
2
- import type { ReversiaPluginConfig } from '../types.js';
2
+ import type { ReversiaPluginConfig } from '../types';
3
3
  export declare function createResourcesSyncEndpoint(pluginConfig: ReversiaPluginConfig, _collectionsMap: Map<string, CollectionConfig>): Endpoint;
@@ -1,6 +1,6 @@
1
- import { unauthorizedResponse, validateApiKey } from '../utils/auth.js';
2
- import { decodeCursor, encodeCursor } from '../utils/cursor.js';
3
- import { parseLimit } from '../utils/payload-helpers.js';
1
+ import { unauthorizedResponse, validateApiKey } from '../utils/auth';
2
+ import { decodeCursor, encodeCursor } from '../utils/cursor';
3
+ import { parseLimit } from '../utils/payload-helpers';
4
4
  export function createResourcesSyncEndpoint(pluginConfig, _collectionsMap) {
5
5
  return {
6
6
  path: '/reversia/resources-sync',
@@ -1,3 +1,3 @@
1
1
  import type { CollectionConfig, Endpoint, GlobalConfig } from 'payload';
2
- import type { ReversiaPluginConfig } from '../types.js';
2
+ import type { ReversiaPluginConfig } from '../types';
3
3
  export declare function createResourcesEndpoint(pluginConfig: ReversiaPluginConfig, collectionsMap: Map<string, CollectionConfig>, globalsMap: Map<string, GlobalConfig>): Endpoint;
@@ -1,7 +1,7 @@
1
- import { unauthorizedResponse, validateApiKey } from '../utils/auth.js';
2
- import { decodeCursor, encodeCursor } from '../utils/cursor.js';
3
- import { findLocalizedFields, serializeField } from '../utils/fields.js';
4
- import { parseLimit, resolveDefaultLocale } from '../utils/payload-helpers.js';
1
+ import { unauthorizedResponse, validateApiKey } from '../utils/auth';
2
+ import { decodeCursor, encodeCursor } from '../utils/cursor';
3
+ import { findLocalizedFields, serializeField } from '../utils/fields';
4
+ import { parseLimit, resolveDefaultLocale } from '../utils/payload-helpers';
5
5
  function extractContent(doc, fields) {
6
6
  const content = {};
7
7
  const contentTypes = {};
@@ -1,3 +1,3 @@
1
1
  import type { Endpoint } from 'payload';
2
- import type { ReversiaPluginConfig } from '../types.js';
2
+ import type { ReversiaPluginConfig } from '../types';
3
3
  export declare function createSettingsEndpoint(pluginConfig: ReversiaPluginConfig): Endpoint;
@@ -1,4 +1,4 @@
1
- import { unauthorizedResponse, validateApiKey } from '../utils/auth.js';
1
+ import { unauthorizedResponse, validateApiKey } from '../utils/auth';
2
2
  export function createSettingsEndpoint(pluginConfig) {
3
3
  return {
4
4
  path: '/reversia/settings',
@@ -0,0 +1,3 @@
1
+ import type { Endpoint } from 'payload';
2
+ import type { ReversiaPluginConfig } from '../types';
3
+ export declare function createTriggerCrawlDashboardEndpoint(pluginConfig: ReversiaPluginConfig): Endpoint;
@@ -0,0 +1,34 @@
1
+ import { triggerCrawl } from '../trigger-crawl';
2
+ export function createTriggerCrawlDashboardEndpoint(pluginConfig) {
3
+ return {
4
+ path: '/reversia/dashboard/trigger-crawl',
5
+ method: 'post',
6
+ handler: async (req) => {
7
+ if (!req.user) {
8
+ return Response.json({ error: 'Unauthorized' }, { status: 401 });
9
+ }
10
+ const body = req.json ? await req.json() : undefined;
11
+ const types = Array.isArray(body?.types)
12
+ ? body.types.filter((t) => typeof t === 'string')
13
+ : undefined;
14
+ const noCache = Boolean(body?.noCache);
15
+ try {
16
+ const result = await triggerCrawl({
17
+ apiKey: pluginConfig.apiKey,
18
+ baseUrl: pluginConfig.baseUrl,
19
+ ...(types && types.length > 0 ? { types } : {}),
20
+ ...(noCache ? { noCache: true } : {}),
21
+ });
22
+ return Response.json(result);
23
+ }
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ req.payload.logger.error({
27
+ msg: '[reversia] dashboard trigger-crawl failed',
28
+ err: message,
29
+ });
30
+ return Response.json({ error: message }, { status: 502 });
31
+ }
32
+ },
33
+ };
34
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { Config } from 'payload';
2
- import type { ReversiaPluginConfig } from './types.js';
3
- export type { ConfirmResourcesSyncResponse, InsertionRequest, InsertionResponse, ResourceDefinition, ResourceItem, ResourceResponse, ReversiaErrorResponse, ReversiaFieldCustom, ReversiaPluginConfig, SettingsResponse, StreamResponse, TranslatableFieldConfig, } from './types.js';
4
- export { ReversiaFieldBehavior, ReversiaFieldType } from './types.js';
2
+ import type { ReversiaPluginConfig } from './types';
3
+ export type { TriggerCrawlOptions, TriggerCrawlResult } from './trigger-crawl';
4
+ export { triggerCrawl } from './trigger-crawl';
5
+ export type { ConfirmResourcesSyncResponse, InsertionRequest, InsertionResponse, ResourceDefinition, ResourceItem, ResourceResponse, ReversiaErrorResponse, ReversiaFieldCustom, ReversiaPluginConfig, SettingsResponse, StreamResponse, TranslatableFieldConfig, } from './types';
6
+ export { ReversiaFieldBehavior, ReversiaFieldType } from './types';
5
7
  export declare const reversiaPlugin: (pluginConfig: ReversiaPluginConfig) => (config: Config) => Config;
6
8
  export default reversiaPlugin;
package/dist/index.js CHANGED
@@ -1,14 +1,16 @@
1
- import { reversiaSyncPendingCollection } from './collections/sync-pending.js';
2
- import { createConfirmResourcesSyncEndpoint } from './endpoints/confirm-resources-sync.js';
3
- import { createResourceEndpoint } from './endpoints/resource.js';
4
- import { createResourcesEndpoint } from './endpoints/resources.js';
5
- import { createResourcesDefinitionEndpoint } from './endpoints/resources-definition.js';
6
- import { createResourcesInsertEndpoint } from './endpoints/resources-insert.js';
7
- import { createResourcesSyncEndpoint } from './endpoints/resources-sync.js';
8
- import { createSettingsEndpoint } from './endpoints/settings.js';
9
- import { createAfterChangeHook } from './hooks/after-change.js';
10
- import { findLocalizedFields } from './utils/fields.js';
11
- export { ReversiaFieldBehavior, ReversiaFieldType } from './types.js';
1
+ import { reversiaSyncPendingCollection } from './collections/sync-pending';
2
+ import { createConfirmResourcesSyncEndpoint } from './endpoints/confirm-resources-sync';
3
+ import { createResourceEndpoint } from './endpoints/resource';
4
+ import { createResourcesEndpoint } from './endpoints/resources';
5
+ import { createResourcesDefinitionEndpoint } from './endpoints/resources-definition';
6
+ import { createResourcesInsertEndpoint } from './endpoints/resources-insert';
7
+ import { createResourcesSyncEndpoint } from './endpoints/resources-sync';
8
+ import { createSettingsEndpoint } from './endpoints/settings';
9
+ import { createTriggerCrawlDashboardEndpoint } from './endpoints/trigger-crawl-dashboard';
10
+ import { createAfterChangeHook } from './hooks/after-change';
11
+ import { findLocalizedFields } from './utils/fields';
12
+ export { triggerCrawl } from './trigger-crawl';
13
+ export { ReversiaFieldBehavior, ReversiaFieldType } from './types';
12
14
  const APPLIED_MARKER = Symbol.for('payload-plugin-reversia.applied');
13
15
  export const reversiaPlugin = (pluginConfig) => (config) => {
14
16
  if (pluginConfig.disabled) {
@@ -76,6 +78,7 @@ export const reversiaPlugin = (pluginConfig) => (config) => {
76
78
  createResourcesInsertEndpoint(pluginConfig, collectionsMap, globalsMap),
77
79
  createConfirmResourcesSyncEndpoint(pluginConfig),
78
80
  createSettingsEndpoint(pluginConfig),
81
+ createTriggerCrawlDashboardEndpoint(pluginConfig),
79
82
  ];
80
83
  return config;
81
84
  };
@@ -0,0 +1,24 @@
1
+ import type { CollectionSlug, GlobalSlug } from 'payload';
2
+ export interface TriggerCrawlOptions {
3
+ /** Reversia project API key (the same value passed to `reversiaPlugin({ apiKey })`). */
4
+ apiKey: string;
5
+ /**
6
+ * Collection and/or global slugs to crawl. Each slug is prefixed with
7
+ * `payloadcms:` before being sent to Reversia. Omit/empty → crawl all
8
+ * enabled resources for the project.
9
+ */
10
+ types?: Array<CollectionSlug | GlobalSlug>;
11
+ /** Bypass cached crawl content. Defaults to `false`. */
12
+ noCache?: boolean;
13
+ /**
14
+ * Override the Reversia API base URL. Defaults to `process.env.REVERSIA_API_URL`
15
+ * then a built-in production/staging URL.
16
+ */
17
+ baseUrl?: string;
18
+ /** Optional custom fetch (for tests / proxies). Defaults to the global `fetch`. */
19
+ fetch?: typeof fetch;
20
+ }
21
+ export interface TriggerCrawlResult {
22
+ success: boolean;
23
+ }
24
+ export declare function triggerCrawl(options: TriggerCrawlOptions): Promise<TriggerCrawlResult>;
@@ -0,0 +1,47 @@
1
+ const DEFAULT_BASE_URL = 'https://staging.api.reversia.tech';
2
+ const TYPE_NAMESPACE = 'payloadcms:';
3
+ const TRIGGER_CRAWL_PATH = '/projects/trigger-crawl';
4
+ export async function triggerCrawl(options) {
5
+ if (typeof options.apiKey !== 'string' || options.apiKey.length === 0) {
6
+ throw new Error('[reversia] apiKey is required. Pass `TriggerCrawlOptions.apiKey` as a non-empty string.');
7
+ }
8
+ const baseUrl = (options.baseUrl ?? process.env.REVERSIA_API_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
9
+ const normalizedTypes = (options.types ?? [])
10
+ .filter((t) => typeof t === 'string' && t.length > 0)
11
+ .map((t) => `${TYPE_NAMESPACE}${t}`);
12
+ const body = {};
13
+ if (normalizedTypes.length > 0) {
14
+ body.types = normalizedTypes;
15
+ }
16
+ if (options.noCache) {
17
+ body.noCache = true;
18
+ }
19
+ const fetchImpl = options.fetch ?? fetch;
20
+ const response = await fetchImpl(`${baseUrl}${TRIGGER_CRAWL_PATH}`, {
21
+ method: 'POST',
22
+ headers: {
23
+ Authorization: `Bearer ${options.apiKey}`,
24
+ 'Content-Type': 'application/json',
25
+ Accept: 'application/json',
26
+ },
27
+ body: JSON.stringify(body),
28
+ });
29
+ if (!response.ok) {
30
+ let excerpt = '';
31
+ try {
32
+ excerpt = (await response.text()).slice(0, 200);
33
+ }
34
+ catch {
35
+ // ignore body read errors — keep the status info
36
+ }
37
+ throw new Error(`[reversia] trigger-crawl failed: ${response.status} ${response.statusText}${excerpt ? ` — ${excerpt}` : ''}`);
38
+ }
39
+ let parsed = null;
40
+ try {
41
+ parsed = (await response.json());
42
+ }
43
+ catch {
44
+ parsed = null;
45
+ }
46
+ return { success: parsed?.success !== false };
47
+ }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { CollectionSlug } from 'payload';
2
- import type { LeafSegment } from './utils/path-resolver.js';
2
+ import type { LeafSegment } from './utils/path-resolver';
3
3
  export interface ReversiaPluginConfig {
4
4
  /**
5
5
  * API key used by Reversia SaaS to authenticate requests.
@@ -20,6 +20,12 @@ export interface ReversiaPluginConfig {
20
20
  * Whether the plugin is disabled. Defaults to false.
21
21
  */
22
22
  disabled?: boolean;
23
+ /**
24
+ * Override the Reversia API base URL used by `triggerCrawl` and the
25
+ * dashboard button. Defaults to `process.env.REVERSIA_API_URL` then the
26
+ * built-in production URL.
27
+ */
28
+ baseUrl?: string;
23
29
  }
24
30
  export declare enum ReversiaFieldType {
25
31
  TEXT = "TEXT",
@@ -1,4 +1,4 @@
1
- import type { Cursor } from '../types.js';
1
+ import type { Cursor } from '../types';
2
2
  /**
3
3
  * Opaque cursor encoding. Uses JSON in base64url so the delimiter concern
4
4
  * (types or ids containing `|`) is eliminated.
@@ -1,6 +1,6 @@
1
1
  import type { Field } from 'payload';
2
- import type { LocalizedFieldInfo, TranslatableFieldConfig } from '../types.js';
3
- import { ReversiaFieldType } from '../types.js';
2
+ import type { LocalizedFieldInfo, TranslatableFieldConfig } from '../types';
3
+ import { ReversiaFieldType } from '../types';
4
4
  /**
5
5
  * Collects one `LocalizedFieldInfo` per top-level field that is itself
6
6
  * localized OR that contains at least one localized descendant.
@@ -1,7 +1,7 @@
1
- import { ReversiaFieldType } from '../types.js';
2
- import { applyByKeys, compileKeyMatcher, DEFAULT_RICHTEXT_KEYS, extractByKeys, } from './json-extract.js';
3
- import { resolveStaticLabel } from './labels.js';
4
- import { applyTranslationsToContainer, joinPointers, resolveLeafLocations, } from './path-resolver.js';
1
+ import { ReversiaFieldType } from '../types';
2
+ import { applyByKeys, compileKeyMatcher, DEFAULT_RICHTEXT_KEYS, extractByKeys, } from './json-extract';
3
+ import { resolveStaticLabel } from './labels';
4
+ import { applyTranslationsToContainer, joinPointers, resolveLeafLocations, } from './path-resolver';
5
5
  function getFieldLabel(field) {
6
6
  if (!('name' in field)) {
7
7
  return '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sequoialabs/payload-plugin-reversia",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "author": {
5
5
  "name": "Jean Walrave",
6
6
  "email": "contact@reversia.tech",
@@ -27,6 +27,10 @@
27
27
  ".": {
28
28
  "types": "./dist/index.d.ts",
29
29
  "import": "./dist/index.js"
30
+ },
31
+ "./client": {
32
+ "types": "./dist/client/index.d.ts",
33
+ "import": "./dist/client/index.js"
30
34
  }
31
35
  },
32
36
  "main": "dist/index.js",
@@ -44,14 +48,17 @@
44
48
  "prepublishOnly": "bun run test && bun run build"
45
49
  },
46
50
  "peerDependencies": {
47
- "payload": "^3.0.0"
51
+ "payload": "^3.0.0",
52
+ "react": "^18.0.0 || ^19.0.0"
48
53
  },
49
54
  "devDependencies": {
50
55
  "@biomejs/biome": "2.4.12",
51
56
  "@payloadcms/db-sqlite": "^3.0.0",
52
57
  "@payloadcms/richtext-lexical": "^3.79.1",
53
58
  "@types/bun": "^1.3.10",
59
+ "@types/react": "^19.0.0",
54
60
  "payload": "^3.0.0",
61
+ "react": "^19.0.0",
55
62
  "typescript": "^5.0.0"
56
63
  }
57
- }
64
+ }