contentful-import 10.2.3 → 10.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.
package/README.md CHANGED
@@ -163,6 +163,14 @@ Skip updating existing content
163
163
 
164
164
  Skips content publishing. Creates content but does not publish it
165
165
 
166
+ #### `unpublishDraftLocales` [boolean] [default: false]
167
+
168
+ Unpublish locales that the content file marks as `draft` but that are still published in the destination.
169
+
170
+ Per-locale publishing is additive, so importing can add published locales but cannot demote one on its own. This only matters when importing over content that is already published — for a fresh import into a clean environment it makes no difference. Enable it to make repeated imports converge on exactly the state in the content file.
171
+
172
+ Note that this lets an import **unpublish** content in the destination, which is why it is opt-in.
173
+
166
174
  ### Assets
167
175
 
168
176
  #### `uploadAssets` [boolean] [default: false]
@@ -219,6 +227,10 @@ Path to a JSON file with the configuration options. This file will be merged wit
219
227
 
220
228
  Flag controlling whether Experience Orchestration (ExO) entities — Design Tokens, Components, Experience Templates, Experience Fragments, Data Assemblies, and Experiences — are imported when present in the source content. Requires the `exoM1` entitlement on the destination space's organization. Set to `false` to opt out. See the "Experience Orchestration (ExO) entities" section below for what happens when the destination isn't entitled.
221
229
 
230
+ #### `skipExoVariants` [boolean] [default: false]
231
+
232
+ Skip importing nested Experience and Experience Fragment Optimization Variants. This can be useful when re-importing the same export because the upstream API generates new variant IDs on every create and cannot upsert by the source variant ID.
233
+
222
234
  ## :rescue_worker_helmet: Troubleshooting
223
235
 
224
236
  ### Proxy
@@ -284,6 +296,8 @@ The `designTokens`, `components`, `experienceTemplates`, `dataAssemblies`, `expe
284
296
 
285
297
  ExO import is on by default (`includeExperienceOrchestration: true`) — for the CLI and the module API alike. Pass `includeExperienceOrchestration: false` (`--include-experience-orchestration=false` on the CLI) to opt out.
286
298
 
299
+ Optimization Variant import is on automatically when the source contains nested variants. Pass `skipExoVariants: true` (or `--skip-exo-variants`) to leave them out of the import. When variants are imported, a warning is logged because each run creates fresh destination variant IDs and re-importing can create duplicates.
300
+
287
301
  ```javascript
288
302
  import contentfulImport from 'contentful-import'
289
303
 
@@ -314,10 +328,21 @@ ExO entities are created and published in dependency order, then unpublished in
314
328
  4. Experience Templates — create, then publish
315
329
  5. Experience Fragments — create, then publish
316
330
  6. Experiences — create, then publish
317
- 7. Unpublish pass, in reverse: Experiences Experience Fragments Experience Templates Components Data Assemblies
331
+ 7. Experience Optimization Variants create, then publish/archive (only if the source has any; see below)
332
+ 8. Experience Fragment Optimization Variants — create, then publish/archive (only if the source has any; see below)
333
+ 9. Unpublish pass, in reverse: Experiences → Experience Fragments → Experience Templates → Components → Data Assemblies
318
334
 
319
335
  An entity that's published in the source is published in the destination on import. An entity that's unpublished (or removed) in the source but still published in the destination is unpublished on re-import — this propagates in both directions, so reverting a published ExO entity back to draft in the source and re-running the import will unpublish it in the destination too.
320
336
 
337
+ ### Optimization Variants
338
+
339
+ Experiences and Experience Fragments each support **Optimization Variants** — alternate personalization versions nested onto their parent (`experience.optimizationVariants` / `experienceFragment.optimizationVariants`), not a flat top-level array like the other six ExO entity types. A variant's `sys.id` is borrowed from its parent rather than being globally unique — see the export tool's own doc ([contentful-export's ExO doc](https://github.com/contentful/contentful-export/blob/main/docs/exo-export.md#optimization-variants)) for the full rationale.
340
+
341
+ Two behaviors are worth calling out explicitly because they differ from every other ExO entity type:
342
+
343
+ - **No ID preservation.** Every other ExO entity is created via upsert-with-known-ID. Variants can't be: the upstream API's create endpoint always server-generates a fresh ID, and its update endpoint 404s on an unknown ID instead of creating one. Every import run creates brand-new destination variants — re-running an import with variants in the source data creates additional variants rather than updating existing ones.
344
+ - **The API's synthetic "default" entry is filtered out.** The upstream list endpoint always leads with an entry representing the parent's own base view (`sys.variantType: 'default'`) — not a real variant. `contentful-export` already excludes it; `contentful-import` filters it again defensively for older export files.
345
+
321
346
  ### URN rewriting / backward compatibility
322
347
 
323
348
  - Export files taken before the ExO entity rename (`ComponentType` → `Component`, `Fragment` → `ExperienceFragment`, `Template` → `ExperienceTemplate`) are upgraded automatically on import, including the corresponding resource-link `linkType`s and URN path segments. This upgrade is upgrade-only (there's no downgrade path) and idempotent, so it's safe to run against already-upgraded data.
@@ -333,6 +358,7 @@ An entity that's published in the source is published in the destination on impo
333
358
  - Publishing strategy:
334
359
  - If an entity is in draft, it will be created as draft in the destination space.
335
360
  - If an entity is published and has pending changes (updated) in the source space, it will be published with the latest changes in the destination space.
361
+ - If an entry or asset was published for only some of its locales, only those locales are published in the destination space. This is read from `sys.fieldStatus` in the content file, which `contentful-export` writes automatically — existing export files already contain it, so no re-export is needed. Content files without `sys.fieldStatus` are published as a whole, as before.
336
362
 
337
363
  ## :warning: Limitations
338
364
 
@@ -342,6 +368,11 @@ An entity that's published in the source is published in the destination on impo
342
368
  - Imported webhooks with credentials will be imported as normal webhooks. Credentials should be added manually afterwards.
343
369
  - Imported webhooks with secret headers will be imported without these headers. Secret headers should be added manuall afterwards.
344
370
  - If you have custom UI extensions, you need to reinstall them manually in the new space.
371
+ - Per-locale publish state is restored, with three caveats:
372
+ - The destination has to support [locale-based publishing](https://www.contentful.com/help/localization/locale-based-publishing/), which means two things: the organization is entitled to it (it is not on every plan), and the destination environment has "Locale-based (un)publishing" selected under **Settings > Locales > Publishing options** — the default is "Publish all locales". The import checks the entitlement up front and detects an environment that publishes whole entities anyway, and in either case logs a warning and falls back to publishing every locale, exactly as it did before this feature. The import itself does not fail.
373
+ - A locale that was `changed` in the source space (published, with newer draft edits on top) is imported as `published`. Reconstructing `changed` needs two separate writes, which an import cannot express.
374
+ - Locale-scoped publishing only adds published locales. If an entry in the destination space is already published for a locale that should be draft, that locale stays published by default — importing into a clean environment is unaffected. Set [`unpublishDraftLocales`](#unpublishdraftlocales-boolean-default-false) to demote those locales as well.
375
+ - Locales that are published in the source space but do not exist in the destination environment are skipped. If none of an entity's published locales exist in the destination, the entity is left unpublished and a warning is logged.
345
376
 
346
377
  ## :memo: Changelog
347
378
 
package/dist/index.d.mts CHANGED
@@ -8,6 +8,7 @@ type RunContentfulImportParams = {
8
8
  skipContentModel?: boolean;
9
9
  skipLocales?: boolean;
10
10
  skipContentPublishing?: boolean;
11
+ unpublishDraftLocales?: boolean;
11
12
  skipAssetUpdates?: boolean;
12
13
  skipContentUpdates?: boolean;
13
14
  uploadAssets?: boolean;
@@ -20,6 +21,7 @@ type RunContentfulImportParams = {
20
21
  errorLogFile?: string;
21
22
  useVerboseRenderer?: boolean;
22
23
  includeExperienceOrchestration?: boolean;
24
+ skipExoVariants?: boolean;
23
25
  timeout?: number;
24
26
  retryLimit?: number;
25
27
  config?: string;
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ type RunContentfulImportParams = {
8
8
  skipContentModel?: boolean;
9
9
  skipLocales?: boolean;
10
10
  skipContentPublishing?: boolean;
11
+ unpublishDraftLocales?: boolean;
11
12
  skipAssetUpdates?: boolean;
12
13
  skipContentUpdates?: boolean;
13
14
  uploadAssets?: boolean;
@@ -20,6 +21,7 @@ type RunContentfulImportParams = {
20
21
  errorLogFile?: string;
21
22
  useVerboseRenderer?: boolean;
22
23
  includeExperienceOrchestration?: boolean;
24
+ skipExoVariants?: boolean;
23
25
  timeout?: number;
24
26
  retryLimit?: number;
25
27
  config?: string;