Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clone-assets/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
VITE_PERSONAL_ACCESS_TOKEN=YOUR_PERSONAL_ACCESS_TOKEN
# Optional: use two least-privilege tokens instead of the single one above.
# When set, these take precedence over VITE_PERSONAL_ACCESS_TOKEN. The source
# token only reads (and only writes if VITE_CLEAR_SOURCE is used); the target
# token needs write access.
VITE_SOURCE_PERSONAL_ACCESS_TOKEN=OPTIONAL_READ_ONLY_SOURCE_TOKEN
VITE_TARGET_PERSONAL_ACCESS_TOKEN=OPTIONAL_WRITE_TARGET_TOKEN
VITE_SOURCE_SPACE_ID=THE_SOURCE_SPACE_ID
VITE_TARGET_SPACE_ID=THE_TARGET_SPACE_ID
VITE_SIMULTANEOUS_UPLOADS=NUMBER_OF_SIMULTANEOUS_UPLOADS
Expand Down
2 changes: 2 additions & 0 deletions clone-assets/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
interface ImportMetaEnv {
readonly VITE_PERSONAL_ACCESS_TOKEN: string;
readonly VITE_SOURCE_PERSONAL_ACCESS_TOKEN?: string;
readonly VITE_TARGET_PERSONAL_ACCESS_TOKEN?: string;
readonly VITE_SOURCE_SPACE_ID: number;
readonly VITE_TARGET_SPACE_ID: number;
readonly VITE_SIMULTANEOUS_UPLOADS: number;
Expand Down
13 changes: 11 additions & 2 deletions clone-assets/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import Migration from "./src/index.js";

const paToken = import.meta.env.VITE_PERSONAL_ACCESS_TOKEN;
// Optionally use two least-privilege tokens: a read-only source token and a
// write target token. Falls back to the single VITE_PERSONAL_ACCESS_TOKEN
// when only one is provided.
const sourcePaToken =
import.meta.env.VITE_SOURCE_PERSONAL_ACCESS_TOKEN ||
import.meta.env.VITE_PERSONAL_ACCESS_TOKEN;
const targetPaToken =
import.meta.env.VITE_TARGET_PERSONAL_ACCESS_TOKEN ||
import.meta.env.VITE_PERSONAL_ACCESS_TOKEN;
const sourceSpaceId = import.meta.env.VITE_SOURCE_SPACE_ID;
const targetSpaceId = import.meta.env.VITE_TARGET_SPACE_ID;
const simultaneousUploads = import.meta.env.VITE_SIMULTANEOUS_UPLOADS;
Expand All @@ -21,7 +29,8 @@ const assetsIds =
: [];

const migration = new Migration(
paToken,
sourcePaToken,
targetPaToken,
sourceSpaceId,
targetSpaceId,
simultaneousUploads,
Expand Down
2 changes: 2 additions & 0 deletions clone-assets/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Clone Assets | A tool to clone assets from a space to its clone | [Christian Zop
Copy the `.env.example` file to `.env` and fill out the variables. These are the parameters you will have to fill out:

- `VITE_PERSONAL_ACCESS_TOKEN`: Personal Access Token from your account.
- `VITE_SOURCE_PERSONAL_ACCESS_TOKEN` (optional): A separate token used only for the source space. When set, it takes precedence over `VITE_PERSONAL_ACCESS_TOKEN` for source requests, so you can scope it read-only. Falls back to `VITE_PERSONAL_ACCESS_TOKEN` when not set.
- `VITE_TARGET_PERSONAL_ACCESS_TOKEN` (optional): A separate token used only for the target space. When set, it takes precedence over `VITE_PERSONAL_ACCESS_TOKEN` for target requests. Falls back to `VITE_PERSONAL_ACCESS_TOKEN` when not set.
- `VITE_SOURCE_SPACE_ID`: Source space id.
- `VITE_TARGET_SPACE_ID`: Target space id.
- `VITE_SIMULTANEOUS_UPLOADS` (optional, default is 20): Max simultaneous uploads.
Expand Down
24 changes: 13 additions & 11 deletions clone-assets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ interface LocalAssetData {
export default class Migration {
sourceSpaceId: number;
targetSpaceId: number;
oauth: string;
sourceOauth: string;
targetOauth: string;
simultaneousUploads: number;
sourceRegion: string;
targetRegion: string;
Expand Down Expand Up @@ -71,7 +72,8 @@ export default class Migration {
importAssetsByIds: string[];

constructor(
oauth: string,
sourceOauth: string,
targetOauth: string,
sourceSpaceId: number,
targetSpaceId: number,
simultaneousUploads: number,
Expand All @@ -95,7 +97,8 @@ export default class Migration {
this.assets = [];
this.sourceSpaceId = sourceSpaceId;
this.targetSpaceId = targetSpaceId;
this.oauth = oauth;
this.sourceOauth = sourceOauth;
this.targetOauth = targetOauth;
this.simultaneousUploads = simultaneousUploads || 20;
this.sourceRegion = (sourceRegion || "eu").toLowerCase();
this.targetRegion = (targetRegion || "eu").toLowerCase();
Expand All @@ -112,17 +115,16 @@ export default class Migration {
this.limit = limit;
this.offset = offset;
this.importAssetsByIds = assetsIds;
// Separate clients per space so each can carry a least-privilege token:
// the source token can be read-only, keeping the source space safe.
this.mapiClient = new StoryblokClient({
oauthToken: this.oauth,
oauthToken: this.sourceOauth,
region: this.sourceRegion,
});
this.targetMapiClient =
this.sourceRegion === this.targetRegion
? this.mapiClient
: new StoryblokClient({
oauthToken: this.oauth,
region: this.targetRegion,
});
this.targetMapiClient = new StoryblokClient({
oauthToken: this.targetOauth,
region: this.targetRegion,
});
this.stepsTotal = this.clearSource ? 8 : 7;
}

Expand Down