Skip to content

Commit 910af2d

Browse files
Merge pull request #116 from contentstack/v2-dev
DX | 28-04-2026 | Release v2 AM2.0
2 parents 121788e + 9e30c97 commit 910af2d

115 files changed

Lines changed: 6397 additions & 1096 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/config/release.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"releaseAll": true,
33
"plugins": {
4+
"asset-management": false,
45
"export": false,
56
"import": false,
67
"clone": false,

.github/workflows/release-v2-beta-plugins.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ jobs:
3838
filename: .github/config/release.json
3939
prefix: release
4040

41+
# Asset Management
42+
- name: Publishing asset-management (Beta)
43+
uses: JS-DevTools/npm-publish@v3
44+
with:
45+
token: ${{ secrets.NPM_TOKEN }}
46+
package: ./packages/contentstack-asset-management/package.json
47+
access: public
48+
tag: beta
49+
4150
# Variants
4251
- name: Publishing variants (Beta)
4352
uses: JS-DevTools/npm-publish@v3

.talismanrc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
fileignoreconfig:
2+
- filename: packages/contentstack-import/src/utils/import-config-handler.ts
3+
checksum: 3194f537cee8041f07a7ea91cdc6351c84e400766696d9c3cf80b98f99961f76
24
- filename: pnpm-lock.yaml
3-
checksum: 8874a1f72aa1a707ee8303d51842e4c70746f94f6ccc4eeb51208a5ce6b6038d
5+
checksum: cea25dedde40bf962d825a088e505113c997ae666a4385d3eec0ae3f9f5d1404
46
version: '1.0'
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"env": {
3+
"node": true
4+
},
5+
"parser": "@typescript-eslint/parser",
6+
"parserOptions": {
7+
"project": "tsconfig.json",
8+
"sourceType": "module"
9+
},
10+
"extends": [
11+
"oclif-typescript",
12+
"plugin:@typescript-eslint/recommended"
13+
],
14+
"rules": {
15+
"@typescript-eslint/no-unused-vars": [
16+
"error",
17+
{
18+
"args": "none"
19+
}
20+
],
21+
"@typescript-eslint/prefer-namespace-keyword": "error",
22+
"@typescript-eslint/quotes": [
23+
"error",
24+
"single",
25+
{
26+
"avoidEscape": true,
27+
"allowTemplateLiterals": true
28+
}
29+
],
30+
"semi": "off",
31+
"@typescript-eslint/type-annotation-spacing": "error",
32+
"@typescript-eslint/no-redeclare": "off",
33+
"eqeqeq": [
34+
"error",
35+
"smart"
36+
],
37+
"id-match": "error",
38+
"no-eval": "error",
39+
"no-var": "error",
40+
"quotes": "off",
41+
"indent": "off",
42+
"camelcase": "off",
43+
"comma-dangle": "off",
44+
"arrow-parens": "off",
45+
"operator-linebreak": "off",
46+
"object-curly-spacing": "off",
47+
"node/no-missing-import": "off",
48+
"padding-line-between-statements": "off",
49+
"@typescript-eslint/ban-ts-ignore": "off",
50+
"unicorn/no-abusive-eslint-disable": "off",
51+
"unicorn/consistent-function-scoping": "off",
52+
"@typescript-eslint/no-use-before-define": "off"
53+
}
54+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
lib/
2+
node_modules/
3+
*.tsbuildinfo
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# @contentstack/cli-asset-management
2+
3+
Asset Management 2.0 API adapter for Contentstack CLI export and import. Used by the export and import plugins when Asset Management (AM 2.0) is enabled. To learn how to export and import content in Contentstack, refer to the [Migration guide](https://www.contentstack.com/docs/developers/cli/migration/).
4+
5+
[![License](https://img.shields.io/npm/l/@contentstack/cli)](https://github.com/contentstack/cli/blob/main/LICENSE)
6+
7+
<!-- toc -->
8+
* [@contentstack/cli-asset-management](#contentstackcli-asset-management)
9+
* [Overview](#overview)
10+
* [Usage](#usage)
11+
* [Exports](#exports)
12+
<!-- tocstop -->
13+
14+
# Overview
15+
16+
This package provides:
17+
18+
- **AssetManagementAdapter** – HTTP client for the Asset Management API (spaces, assets, folders, fields, asset types).
19+
- **exportSpaceStructure** – Exports space metadata and full workspace structure (metadata, folders, assets, fields, asset types) for linked workspaces.
20+
- **Types**`AssetManagementExportOptions`, `LinkedWorkspace`, `IAssetManagementAdapter`, and related types for export/import integration.
21+
22+
# Usage
23+
24+
This package is consumed by the export and import plugins. When using the export CLI with the `--asset-management` flag (or when the host app enables AM 2.0), the export plugin calls `exportSpaceStructure` with linked workspaces and options:
25+
26+
```ts
27+
import { exportSpaceStructure } from '@contentstack/cli-asset-management';
28+
29+
await exportSpaceStructure({
30+
linkedWorkspaces,
31+
exportDir,
32+
branchName: 'main',
33+
assetManagementUrl,
34+
org_uid,
35+
context,
36+
progressManager,
37+
progressProcessName,
38+
updateStatus,
39+
downloadAsset, // optional
40+
});
41+
```
42+
43+
# Exports
44+
45+
| Export | Description |
46+
|--------|-------------|
47+
| `exportSpaceStructure` | Async function to export space structure for given linked workspaces. |
48+
| `AssetManagementAdapter` | Class to call the Asset Management API (getSpace, getWorkspaceFields, getWorkspaceAssets, etc.). |
49+
| Types from `./types` | `AssetManagementExportOptions`, `ExportSpaceOptions`, `ChunkedJsonWriteOptions`, `LinkedWorkspace`, `SpaceResponse`, `FieldsResponse`, `AssetTypesResponse`, and related API types. |
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"name": "@contentstack/cli-asset-management",
3+
"version": "1.0.0-beta.0",
4+
"description": "Asset Management 2.0 API adapter for export and import",
5+
"main": "lib/index.js",
6+
"types": "lib/index.d.ts",
7+
"files": [
8+
"lib",
9+
"oclif.manifest.json"
10+
],
11+
"scripts": {
12+
"build": "pnpm compile",
13+
"clean": "rm -rf ./lib ./node_modules tsconfig.build.tsbuildinfo",
14+
"compile": "tsc -b tsconfig.json",
15+
"postpack": "rm -f oclif.manifest.json",
16+
"prepack": "pnpm compile && oclif manifest && oclif readme",
17+
"version": "oclif readme && git add README.md",
18+
"lint": "eslint src/**/*.ts",
19+
"format": "eslint src/**/*.ts --fix",
20+
"test": "nyc --extension .ts mocha --require ts-node/register --forbid-only \"test/**/*.test.ts\"",
21+
"posttest": "npm run lint",
22+
"test:unit": "mocha --require ts-node/register --forbid-only \"test/unit/**/*.test.ts\"",
23+
"test:unit:report": "nyc --extension .ts mocha --require ts-node/register --forbid-only \"test/unit/**/*.test.ts\""
24+
},
25+
"keywords": [
26+
"contentstack",
27+
"asset-management",
28+
"cli"
29+
],
30+
"license": "MIT",
31+
"dependencies": {
32+
"@contentstack/cli-utilities": "~2.0.0-beta.5"
33+
},
34+
"oclif": {
35+
"commands": "./lib/commands",
36+
"bin": "csdx",
37+
"devPlugins": [
38+
"@oclif/plugin-help"
39+
],
40+
"repositoryPrefix": "<%- repo %>/blob/main/packages/contentstack-asset-management/<%- commandPath %>"
41+
},
42+
"devDependencies": {
43+
"@types/chai": "^4.3.11",
44+
"@types/mocha": "^10.0.6",
45+
"@types/node": "^20.17.50",
46+
"@types/sinon": "^17.0.2",
47+
"chai": "^4.4.1",
48+
"eslint": "^8.57.1",
49+
"eslint-config-oclif": "^6.0.68",
50+
"mocha": "^10.8.2",
51+
"nyc": "^15.1.0",
52+
"oclif": "^4.17.46",
53+
"sinon": "^17.0.1",
54+
"source-map-support": "^0.5.21",
55+
"ts-node": "^10.9.2",
56+
"typescript": "^5.8.3"
57+
}
58+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/** Fallback when export/import do not pass `chunkFileSizeMb`. */
2+
export const FALLBACK_AM_CHUNK_FILE_SIZE_MB = 1;
3+
/** Fallback when import does not pass `apiConcurrency`. */
4+
export const FALLBACK_AM_API_CONCURRENCY = 5;
5+
/** @deprecated Use FALLBACK_AM_API_CONCURRENCY */
6+
export const DEFAULT_AM_API_CONCURRENCY = FALLBACK_AM_API_CONCURRENCY;
7+
8+
/** Fallback strip lists when import options omit `fieldsImportInvalidKeys` / `assetTypesImportInvalidKeys`. */
9+
export const FALLBACK_FIELDS_IMPORT_INVALID_KEYS = [
10+
'created_at',
11+
'created_by',
12+
'updated_at',
13+
'updated_by',
14+
'is_system',
15+
'asset_types_count',
16+
] as const;
17+
export const FALLBACK_ASSET_TYPES_IMPORT_INVALID_KEYS = [
18+
'created_at',
19+
'created_by',
20+
'updated_at',
21+
'updated_by',
22+
'is_system',
23+
'category',
24+
'preview_image_url',
25+
'category_detail',
26+
] as const;
27+
28+
/** @deprecated Use FALLBACK_AM_CHUNK_FILE_SIZE_MB */
29+
export const CHUNK_FILE_SIZE_MB = FALLBACK_AM_CHUNK_FILE_SIZE_MB;
30+
31+
/**
32+
* Main process name for Asset Management 2.0 export (single progress bar).
33+
* Use this when adding/starting the process and for all ticks.
34+
*/
35+
export const AM_MAIN_PROCESS_NAME = 'Asset Management 2.0';
36+
37+
/**
38+
* Process names for Asset Management 2.0 export progress (for tick labels).
39+
*/
40+
export const PROCESS_NAMES = {
41+
AM_SPACE_METADATA: 'Space metadata',
42+
AM_FOLDERS: 'Folders',
43+
AM_ASSETS: 'Assets',
44+
AM_FIELDS: 'Fields',
45+
AM_ASSET_TYPES: 'Asset types',
46+
AM_DOWNLOADS: 'Asset downloads',
47+
// Import process names
48+
AM_IMPORT_FIELDS: 'Import fields',
49+
AM_IMPORT_ASSET_TYPES: 'Import asset types',
50+
AM_IMPORT_FOLDERS: 'Import folders',
51+
AM_IMPORT_ASSETS: 'Import assets',
52+
} as const;
53+
54+
/**
55+
* Status messages for each process (exporting, fetching, importing, failed).
56+
*/
57+
export const PROCESS_STATUS = {
58+
[PROCESS_NAMES.AM_SPACE_METADATA]: {
59+
EXPORTING: 'Exporting space metadata...',
60+
FAILED: 'Failed to export space metadata.',
61+
},
62+
[PROCESS_NAMES.AM_FOLDERS]: {
63+
FETCHING: 'Fetching folders...',
64+
FAILED: 'Failed to fetch folders.',
65+
},
66+
[PROCESS_NAMES.AM_ASSETS]: {
67+
FETCHING: 'Fetching assets...',
68+
FAILED: 'Failed to fetch assets.',
69+
},
70+
[PROCESS_NAMES.AM_FIELDS]: {
71+
FETCHING: 'Fetching fields...',
72+
FAILED: 'Failed to fetch fields.',
73+
},
74+
[PROCESS_NAMES.AM_ASSET_TYPES]: {
75+
FETCHING: 'Fetching asset types...',
76+
FAILED: 'Failed to fetch asset types.',
77+
},
78+
[PROCESS_NAMES.AM_DOWNLOADS]: {
79+
DOWNLOADING: 'Downloading asset files...',
80+
FAILED: 'Failed to download assets.',
81+
},
82+
[PROCESS_NAMES.AM_IMPORT_FIELDS]: {
83+
IMPORTING: 'Importing shared fields...',
84+
FAILED: 'Failed to import fields.',
85+
},
86+
[PROCESS_NAMES.AM_IMPORT_ASSET_TYPES]: {
87+
IMPORTING: 'Importing shared asset types...',
88+
FAILED: 'Failed to import asset types.',
89+
},
90+
[PROCESS_NAMES.AM_IMPORT_FOLDERS]: {
91+
IMPORTING: 'Importing folders...',
92+
FAILED: 'Failed to import folders.',
93+
},
94+
[PROCESS_NAMES.AM_IMPORT_ASSETS]: {
95+
IMPORTING: 'Importing assets...',
96+
FAILED: 'Failed to import assets.',
97+
},
98+
} as const;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { log } from '@contentstack/cli-utilities';
2+
3+
import type { AssetManagementAPIConfig } from '../types/asset-management-api';
4+
import type { ExportContext } from '../types/export-types';
5+
import { AssetManagementExportAdapter } from './base';
6+
import { getArrayFromResponse } from '../utils/export-helpers';
7+
import { PROCESS_NAMES } from '../constants/index';
8+
9+
export default class ExportAssetTypes extends AssetManagementExportAdapter {
10+
constructor(apiConfig: AssetManagementAPIConfig, exportContext: ExportContext) {
11+
super(apiConfig, exportContext);
12+
}
13+
14+
async start(spaceUid: string): Promise<void> {
15+
await this.init();
16+
17+
log.debug('Starting shared asset types export process...', this.exportContext.context);
18+
19+
const assetTypesData = await this.getWorkspaceAssetTypes(spaceUid);
20+
const items = getArrayFromResponse(assetTypesData, 'asset_types');
21+
const dir = this.getAssetTypesDir();
22+
if (items.length === 0) {
23+
log.info('No asset types to export, writing empty asset-types', this.exportContext.context);
24+
} else {
25+
log.debug(`Writing ${items.length} shared asset types`, this.exportContext.context);
26+
}
27+
await this.writeItemsToChunkedJson(dir, 'asset-types.json', 'asset_types', ['uid', 'title', 'category', 'file_extension'], items);
28+
this.tick(true, PROCESS_NAMES.AM_ASSET_TYPES, null);
29+
}
30+
}

0 commit comments

Comments
 (0)