@easyling/sanity-connector 1.3.0-rc.9 → 1.4.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.
@@ -6,6 +6,20 @@
6
6
  */
7
7
  import React from 'react';
8
8
  import type { LocaleDefinition } from '../../types/locale';
9
+ import type { CollisionResolutionMode, ExistingDocumentHandling } from '../../types/pluginConfig';
10
+ /**
11
+ * Result returned when user confirms locale selection
12
+ */
13
+ export interface LocaleSelectionResult {
14
+ /** Selected locale codes */
15
+ locales: string[];
16
+ /** Document creation mode */
17
+ creationMode?: 'draft' | 'published';
18
+ /** Collision resolution mode (if override is enabled) */
19
+ collisionResolutionMode?: CollisionResolutionMode;
20
+ /** Existing document handling (if override is enabled) */
21
+ existingDocumentHandling?: ExistingDocumentHandling;
22
+ }
9
23
  export interface LocaleSelectionDialogProps {
10
24
  /** Whether the dialog is open */
11
25
  open: boolean;
@@ -29,8 +43,16 @@ export interface LocaleSelectionDialogProps {
29
43
  showCreationModeOption?: boolean;
30
44
  /** Default creation mode to pre-select */
31
45
  defaultCreationMode?: 'draft' | 'published';
46
+ /** Whether to show collision resolution override options */
47
+ showCollisionResolutionOverride?: boolean;
48
+ /** Default collision resolution mode from config */
49
+ defaultCollisionResolutionMode?: CollisionResolutionMode;
50
+ /** Default existing document handling from config */
51
+ defaultExistingDocumentHandling?: ExistingDocumentHandling;
32
52
  /** Callback when user confirms selection */
33
53
  onConfirm: (selectedLocales: string[], creationMode?: 'draft' | 'published') => void;
54
+ /** Enhanced callback with full result object */
55
+ onConfirmWithOptions?: (result: LocaleSelectionResult) => void;
34
56
  /** Callback when user cancels */
35
57
  onCancel: () => void;
36
58
  }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Collision Detection Service
3
+ * Requirements: Translation Collision Handling - EARS 2.1, 2.2
4
+ *
5
+ * Detects existing translated documents for the same source document and target locale
6
+ * to enable collision resolution handling.
7
+ */
8
+ import { SanityClient, SanityDocument } from 'sanity';
9
+ /**
10
+ * Result of a collision detection check
11
+ */
12
+ export interface CollisionResult {
13
+ /** Whether a collision was detected */
14
+ detected: boolean;
15
+ /** The existing translated document if collision was detected */
16
+ existingDocument?: SanityDocument;
17
+ /** How the collision was identified */
18
+ matchedBy?: 'parent' | 'slug-locale';
19
+ }
20
+ /**
21
+ * Options for collision detection
22
+ */
23
+ export interface CollisionDetectionOptions {
24
+ /** The source document ID (the original document being translated) */
25
+ sourceDocumentId: string;
26
+ /** The target locale code for the translation */
27
+ targetLocale: string;
28
+ /** The slug of the translated document (optional, used for slug-locale matching) */
29
+ slug?: string;
30
+ /** The document type to search within */
31
+ documentType?: string;
32
+ }
33
+ /**
34
+ * Error type for collision detection operations
35
+ */
36
+ export declare class CollisionDetectionError extends Error {
37
+ code: string;
38
+ details?: unknown | undefined;
39
+ constructor(message: string, code: string, details?: unknown | undefined);
40
+ }
41
+ /**
42
+ * Service for detecting translation collisions
43
+ *
44
+ * A collision occurs when a translated document already exists for the same
45
+ * source document and target locale. The service identifies collisions using:
46
+ * 1. Parent reference matching: parentDocument._ref == sourceDocumentId AND locale == targetLocale
47
+ * 2. Slug-locale matching: slug.current == slug AND locale == targetLocale
48
+ */
49
+ export declare class CollisionDetectionService {
50
+ private client;
51
+ constructor(client: SanityClient);
52
+ /**
53
+ * Detect if a collision exists for the given source document and target locale
54
+ *
55
+ * @param options - Options specifying the source document, target locale, and optional slug
56
+ * @returns CollisionResult indicating whether a collision was found and details
57
+ */
58
+ detectCollision(options: CollisionDetectionOptions): Promise<CollisionResult>;
59
+ /**
60
+ * Find an existing document by parent reference and locale
61
+ *
62
+ * @param sourceDocumentId - The ID of the source/parent document
63
+ * @param targetLocale - The target locale code
64
+ * @param documentType - Optional document type to filter by
65
+ */
66
+ private findByParentReference;
67
+ /**
68
+ * Find an existing document by slug and locale
69
+ *
70
+ * @param slug - The document slug to match
71
+ * @param targetLocale - The target locale code
72
+ * @param documentType - Optional document type to filter by
73
+ */
74
+ private findBySlugAndLocale;
75
+ /**
76
+ * Check if multiple collisions exist for bulk translation operations
77
+ *
78
+ * @param sourceDocumentId - The source document being translated
79
+ * @param targetLocales - Array of target locale codes
80
+ * @param slug - Optional slug for slug-locale matching
81
+ * @param documentType - Optional document type to filter by
82
+ * @returns Map of locale code to collision result
83
+ */
84
+ detectBulkCollisions(sourceDocumentId: string, targetLocales: string[], slug?: string, documentType?: string): Promise<Map<string, CollisionResult>>;
85
+ }
@@ -1,5 +1,6 @@
1
1
  import { SanityDocument, SanityClient } from 'sanity';
2
2
  import { TranslationResponse } from './translationService';
3
+ import { CollisionResolutionMode, ExistingDocumentHandling } from '../types/pluginConfig';
3
4
  /**
4
5
  * Options for document creation from translation
5
6
  */
@@ -31,6 +32,18 @@ export interface DocumentCreationOptions {
31
32
  * Used to write translated content back to the correct location.
32
33
  */
33
34
  bodyFieldName?: string;
35
+ /**
36
+ * How to handle collisions when a translated document already exists.
37
+ * - 'replace': Overwrite the existing document with new translations
38
+ * - 'create': Create a new document (default behavior if not specified)
39
+ */
40
+ collisionResolutionMode?: CollisionResolutionMode;
41
+ /**
42
+ * How to handle the existing document when creating a new one (only for 'create' mode).
43
+ * - 'draft': Set the existing document to draft state
44
+ * - 'delete': Delete the existing document
45
+ */
46
+ existingDocumentHandling?: ExistingDocumentHandling;
34
47
  }
35
48
  export interface SlugFallbackInfo {
36
49
  documentId: string;
@@ -39,12 +52,29 @@ export interface SlugFallbackInfo {
39
52
  locale: string;
40
53
  reason: string;
41
54
  }
55
+ /**
56
+ * Information about a collision that was detected and resolved
57
+ */
58
+ export interface CollisionResolutionInfo {
59
+ /** Whether a collision was detected */
60
+ collisionDetected: boolean;
61
+ /** The resolution action that was taken */
62
+ resolutionAction?: 'replaced' | 'created_new' | 'none';
63
+ /** The ID of the document that was replaced, updated, or deleted */
64
+ existingDocumentId?: string;
65
+ /** How the existing document was handled (for 'create' mode) */
66
+ existingDocumentAction?: 'set_to_draft' | 'deleted' | 'none';
67
+ /** How the collision was detected */
68
+ matchedBy?: 'parent' | 'slug-locale';
69
+ }
42
70
  export interface DocumentCreationResult {
43
71
  success: boolean;
44
72
  documentId?: string;
45
73
  document?: SanityDocument;
46
74
  error?: string;
47
75
  slugFallback?: SlugFallbackInfo;
76
+ /** Information about collision detection and resolution */
77
+ collisionInfo?: CollisionResolutionInfo;
48
78
  }
49
79
  export interface BulkDocumentCreationResult {
50
80
  totalDocuments: number;
@@ -63,12 +93,48 @@ export interface RollbackInfo {
63
93
  export declare class DocumentCreationService {
64
94
  private client;
65
95
  private defaultCreationMode;
96
+ private collisionDetectionService;
97
+ private defaultCollisionResolutionMode;
98
+ private defaultExistingDocumentHandling;
66
99
  constructor(client: SanityClient, defaultCreationMode?: 'draft' | 'published');
67
100
  /**
68
101
  * Set the default document creation mode
69
102
  * @param mode - The creation mode to use by default ('draft' or 'published')
70
103
  */
71
104
  setDefaultCreationMode(mode: 'draft' | 'published'): void;
105
+ /**
106
+ * Set the default collision resolution mode
107
+ * @param mode - How to handle collisions ('replace' or 'create')
108
+ */
109
+ setDefaultCollisionResolutionMode(mode: CollisionResolutionMode): void;
110
+ /**
111
+ * Set the default existing document handling mode
112
+ * @param handling - How to handle existing documents when creating new ('draft' or 'delete')
113
+ */
114
+ setDefaultExistingDocumentHandling(handling: ExistingDocumentHandling): void;
115
+ /**
116
+ * Configure collision resolution defaults
117
+ * @param mode - Collision resolution mode
118
+ * @param handling - Existing document handling (only applicable when mode is 'create')
119
+ */
120
+ setCollisionResolutionConfig(mode: CollisionResolutionMode, handling?: ExistingDocumentHandling): void;
121
+ /**
122
+ * Replace an existing document with new translated content
123
+ * Requirements: EARS 4 - Resolution Behavior - Replace
124
+ *
125
+ * @param existingDocument - The document to replace
126
+ * @param newDocument - The new translated document content
127
+ * @param creationMode - Whether to create as draft or published
128
+ */
129
+ private replaceExistingDocument;
130
+ /**
131
+ * Handle an existing document when creating a new translation (for 'create' mode)
132
+ * Requirements: EARS 5 - Resolution Behavior - Create
133
+ *
134
+ * @param existingDocument - The existing document to handle
135
+ * @param handling - How to handle the existing document ('draft' or 'delete')
136
+ */
137
+ private handleExistingDocument;
72
138
  /**
73
139
  * Create a new Sanity document from translation response
74
140
  * Requirements: 1.1, 1.2, 2.1, 3.2, 3.4
@@ -12,6 +12,7 @@
12
12
  import { SanityClient } from 'sanity';
13
13
  import { OAuthConfig } from '../types/oauth';
14
14
  import { LocaleConfig } from '../types/locale';
15
+ import { CollisionResolutionMode, ExistingDocumentHandling } from '../types/pluginConfig';
15
16
  /**
16
17
  * Unified plugin configuration structure
17
18
  */
@@ -24,6 +25,9 @@ export interface UnifiedPluginConfig {
24
25
  requestContentType?: 'application/json' | 'application/x-protobuf';
25
26
  responseAcceptHeader?: 'application/json' | 'application/x-protobuf';
26
27
  defaultDocumentCreationMode?: 'draft' | 'published';
28
+ /** Collision resolution settings */
29
+ collisionResolutionMode?: CollisionResolutionMode;
30
+ existingDocumentHandling?: ExistingDocumentHandling;
27
31
  /** Locale configuration */
28
32
  locales?: LocaleConfig['locales'];
29
33
  defaultLocale?: string;
@@ -122,6 +126,27 @@ export declare class UnifiedConfigStorage {
122
126
  * Get default document creation mode with fallback to default
123
127
  */
124
128
  getDefaultDocumentCreationMode(): Promise<'draft' | 'published'>;
129
+ /**
130
+ * Get collision resolution mode with fallback to default ('replace')
131
+ */
132
+ getCollisionResolutionMode(): Promise<CollisionResolutionMode>;
133
+ /**
134
+ * Get existing document handling mode with fallback to default ('draft')
135
+ * Only applicable when collision resolution mode is 'create'
136
+ */
137
+ getExistingDocumentHandling(): Promise<ExistingDocumentHandling>;
138
+ /**
139
+ * Get complete collision resolution configuration
140
+ * Returns both the resolution mode and existing document handling settings
141
+ */
142
+ getCollisionResolutionConfig(): Promise<{
143
+ collisionResolutionMode: CollisionResolutionMode;
144
+ existingDocumentHandling: ExistingDocumentHandling;
145
+ }>;
146
+ /**
147
+ * Set collision resolution configuration
148
+ */
149
+ setCollisionResolutionConfig(mode: CollisionResolutionMode, handling?: ExistingDocumentHandling): Promise<void>;
125
150
  /**
126
151
  * Get debug mode status
127
152
  */
@@ -68,6 +68,12 @@ export interface LocaleSelectionDialogOptions extends BaseDialogOptions {
68
68
  showCreationModeOption?: boolean;
69
69
  /** Default creation mode to pre-select */
70
70
  defaultCreationMode?: 'draft' | 'published';
71
+ /** Whether to show collision resolution override options */
72
+ showCollisionResolutionOverride?: boolean;
73
+ /** Default collision resolution mode from config */
74
+ defaultCollisionResolutionMode?: CollisionResolutionMode;
75
+ /** Default existing document handling from config */
76
+ defaultExistingDocumentHandling?: ExistingDocumentHandling;
71
77
  }
72
78
  /**
73
79
  * Locale selection result
@@ -77,6 +83,10 @@ export interface LocaleSelectionResult {
77
83
  locales: string[];
78
84
  /** Selected creation mode (if showCreationModeOption was true) */
79
85
  creationMode?: 'draft' | 'published';
86
+ /** Collision resolution mode (if override was enabled) */
87
+ collisionResolutionMode?: CollisionResolutionMode;
88
+ /** Existing document handling (if override was enabled) */
89
+ existingDocumentHandling?: ExistingDocumentHandling;
80
90
  }
81
91
  /**
82
92
  * Dialog result types
@@ -103,4 +113,6 @@ export interface DialogManager {
103
113
  closeAll(): void;
104
114
  }
105
115
  import type { LocaleDefinition } from './locale';
116
+ import type { CollisionResolutionMode, ExistingDocumentHandling } from './pluginConfig';
106
117
  export type { LocaleDefinition } from './locale';
118
+ export type { CollisionResolutionMode, ExistingDocumentHandling } from './pluginConfig';
@@ -14,6 +14,20 @@ export type DocumentCreationMode = 'draft' | 'published';
14
14
  * Specifies the serialization format for translation API communication
15
15
  */
16
16
  export type ContentType = 'application/json' | 'application/x-protobuf';
17
+ /**
18
+ * Collision resolution mode options
19
+ * Determines how to handle existing translated documents when a collision is detected
20
+ * - 'replace': Overwrite the existing translated document with new translations
21
+ * - 'create': Create a new translated document alongside the existing one
22
+ */
23
+ export type CollisionResolutionMode = 'replace' | 'create';
24
+ /**
25
+ * Existing document handling options (only applicable when CollisionResolutionMode is 'create')
26
+ * Determines what happens to the existing translated document when creating a new one
27
+ * - 'draft': Set the existing document to draft state
28
+ * - 'delete': Delete the existing document
29
+ */
30
+ export type ExistingDocumentHandling = 'draft' | 'delete';
17
31
  /**
18
32
  * Complete plugin configuration interface
19
33
  * Represents all configurable settings for the Easyling Translation Plugin
@@ -31,6 +45,10 @@ export interface PluginConfiguration {
31
45
  responseAcceptHeader?: ContentType;
32
46
  /** Default mode for creating translated documents (draft or published) */
33
47
  defaultDocumentCreationMode?: DocumentCreationMode;
48
+ /** How to handle collisions when a translated document already exists for the same source and locale */
49
+ collisionResolutionMode?: CollisionResolutionMode;
50
+ /** How to handle existing documents when creating new translations (only applicable when mode is 'create') */
51
+ existingDocumentHandling?: ExistingDocumentHandling;
34
52
  /** Array of configured locales for translation */
35
53
  locales?: LocaleDefinition[];
36
54
  /** Default source locale code */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easyling/sanity-connector",
3
- "version": "1.3.0-rc.9",
3
+ "version": "1.4.0",
4
4
  "description": "A *Sanity Studio v4* plugin that enables document translation with support for single and bulk operations, using Easyling's AI translation capabilities.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",