Skip to main content

writing-data-transfer-config

Use when writing or editing a @webiny/data-transfer config file (ddb.transfer.config.ts / os.transfer.config.ts / custom.transfer.config.ts). Covers createDdbConfig / createOsConfig signatures, credential shapes (fromAwsProfile vs literal), fromEnv / numberFromEnv helpers, loadEnv, source/target collision + trimming rules, pointing at a preset, tuning knobs.

معلومات المصدر

المستودع
webiny/data-transfer
آخر نشاط في المصدر
١١ مايو ٢٠٢٦ في ٢٠:٤٧
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
writing-data-transfer-config
description
Use when writing or editing a @webiny/data-transfer config file (ddb.transfer.config.ts / os.transfer.config.ts / custom.transfer.config.ts). Covers createDdbConfig / createOsConfig signatures, credential shapes (fromAwsProfile vs literal), fromEnv / numberFromEnv helpers, loadEnv, source/target collision + trimming rules, pointing at a preset, tuning knobs.
# Writing a `@webiny/data-transfer` config A config is a `.ts` file that `export default`s one of the two factory calls: - **`createDdbConfig(...)`** — DDB primary table (+ S3 files). Covers CMS + security + file manager + tenancy. - **`createOsConfig(...)`** — OpenSearch companion DDB table. CMS entries only, gzipped records. Both validate with Zod at import time — invalid configs fail fast with a useful message, before any AWS call. ## Minimal shape ```ts import { loadEnv, createDdbConfig, fromAwsProfile, fromEnv, numberFromEnv } from "@webiny/data-transfer"; loadEnv(import.meta.url); export default createDdbConfig({ source: { region: fromEnv("SOURCE_REGION", "us-east-1"), credentials: fromAwsProfile({ profile: fromEnv("SOURCE_PROFILE", "default") }), dynamodb: { tableName: fromEnv("SOURCE_DDB_TABLE") }, s3: { bucket: fromEnv("SOURCE_S3_BUCKET") } }, target: { region: fromEnv("TARGET_REGION", "us-east-1"), credentials: fromAwsProfile({ profile: fromEnv("TARGET_PROFILE", "default") }), dynamodb: { tableName: fromEnv("TARGET_DDB_TABLE") }, s3: { bucket: fromEnv("TARGET_S3_BUCKET") } }, pipeline: { preset: "v5-to-v6-ddb", // built-in, OR "./presets/my-preset.ts" segments: numberFromEnv("SEGMENTS", 4) } }); ``` ## Credentials — three accepted shapes The `credentials` field accepts any of the three. Pick what matches where the transfer runs; mixing is fine across source/target. ### A) Profile — explicit (`fromAwsProfile`) ```ts credentials: fromAwsProfile({ profile: fromEnv("SOURCE_PROFILE", "default") }) ``` Reads `~/.aws/credentials` using the named profile (re-export of `fromIni`; renamed because "ini" leaks the implementation detail). **Use locally** when you have multiple AWS accounts — explicit profile selection prevents a stray `AWS_ACCESS_KEY_ID` in your shell from silently overriding the wrong account. ### B) Default credential chain — flexible (`fromAwsCredentialChain`) ```ts credentials: fromAwsCredentialChain() ``` Runs the AWS SDK's default resolution: env vars → shared credentials file → SSO / web identity → EC2/ECS IAM role. **Use in CI / cloud** where the credentials source depends on the deploy target, or when you want one config that "just works" locally AND on a build agent AND on an IAM-instance-profile box. ### C) Literal credentials from env — explicit strings ```ts credentials: { accessKeyId: fromEnv("SOURCE_AWS_ACCESS_KEY_ID"), secretAccessKey: fromEnv("SOURCE_AWS_SECRET_ACCESS_KEY"), // sessionToken: fromEnv("SOURCE_AWS_SESSION_TOKEN") // only for temporary STS creds } ``` Use when your CI injects credentials as env vars directly, when you have temporary STS credentials to pass in, or when you prefer creds in a single `.env` file over a shared profile. ### Picking between them | Scenario | Pick | | --- | --- | | Local dev, multiple AWS accounts | **A** — `fromAwsProfile` | | CI with IAM role or env-based creds | **B** — `fromAwsCredentialChain` | | CI that injects `AWS_*` env vars explicitly | **B** or **C** | | One-config-works-everywhere | **B** — `fromAwsCredentialChain` | | Temporary STS creds (session token) | **C** — literal object | ## `fromEnv(name, default?)` Reads `process.env[name]` as a string. Throws if the variable is unset OR empty when no default is provided. Empty-string counts as missing because `KEY=` in a `.env` file is almost always a forgotten value. ```ts region: fromEnv("SOURCE_REGION", "us-east-1"), // has default tableName: fromEnv("SOURCE_DDB_TABLE"), // no default → throws if missing ``` ## `numberFromEnv(name, default?)` Same contract, but parses via `Number(...)`. Throws if the variable is set but not parseable (`SEGMENTS=four` → named error, not silent `NaN`). ```ts segments: numberFromEnv("SEGMENTS", 4), ``` ## `loadEnv(import.meta.url)` Loads the `.env` file **next to the config file** (not the one at the repo root). Using `import.meta.url` anchors the lookup to THIS file's directory — so running from the repo root with `--config=./projects/X/...` still loads `projects/X/.env`. Every project should have its own `.env`. ## Config validation rules Enforced by Zod at build time: - **All string fields are trimmed** (`region`, `tableName`, `bucket`, `endpoint`, creds, preset). A trailing-space paste error doesn't silently corrupt anything. - **Whitespace-only rejected** — empty-after-trim is treated as missing. - **Source/target collision guard**: - Same S3 bucket on both sides → rejected (would overwrite source files). - Same region + same DDB / OS-DDB table name → rejected (would read and write to the same table). Same table name across DIFFERENT regions is allowed — distinct physical tables. ## Pointing at a preset `pipeline.preset` takes one of: - **A built-in name**: `"v5-to-v6-ddb"` or `"v5-to-v6-os"` (filename in `src/presets/` without extension). The runner auto-discovers built-ins. - **A file path**: `"./presets/my-preset.ts"` or `"../shared/presets/foo.ts"`. Resolved relative to the CONFIG file's directory. ## `pipeline.modelsDir` — CMS model definitions Required by the OS preset (`v5-to-v6-os`) and by built-in transformers that inspect field types (`fixBrokenStorageKeys`, `transformRichText`, `addLiveField`). Point at a directory of exported model definitions. ```ts pipeline: { preset: "v5-to-v6-os", modelsDir: fromEnv("MODELS_DIR", "./models") } ``` Three JSON shapes are accepted and can be mixed freely in the same directory: | Shape | Example | |-------|---------| | Single model | `{ "modelId": "blog", "fields": [...], ... }` | | Array of models | `[{ "modelId": "blog", "fields": [...] }, ...]` | | Webiny admin export | `{ "groups": [...], "models": [...] }` | The Webiny admin panel's **Export** button produces the `{groups, models}` shape. JSON models override DB-loaded models (user-provided definition takes precedence over what was scanned from the source DDB table). ## Snapshot / debug (optional) ```ts debug: { snapshot: true // or: snapshot: { dir: "./my-snapshot", compress: false } } ``` Dumps every record the pipeline touches to local JSONL files. Useful for diffing source vs post-transform on a specific record without re-scanning AWS. Layout (one file per shard per pipeline per category): - `<dir>/<pipelineName>/segment-<n>.source.jsonl.gz` — post-filter, pre-transform records. - `<dir>/<pipelineName>/segment-<n>.post-transform.jsonl.gz` — after the transformer chain + onEnd. - `<dir>/<pipelineName>/segment-<n>.commands.jsonl.gz` — every emitted command (PutRecord, S3Copy, custom). - `<dir>/dropped/segment-<n>.jsonl.gz` — records that matched no pipeline filter. Default `dir`: `.transfer/<runId>/snapshot`. Default `compress`: `true`. Best-effort — write errors log `warn` but never fail the transfer. **Snapshot files may contain production data.** The default `.transfer/` location is gitignored in this repo. If you override `dir` to a path outside `.transfer/`, add your override path to `.gitignore` yourself — these files typically contain full source records + transformed records + emitted commands, which are usually not things you want committed. ### Persistent log file (`debug.logFile`) ```ts debug: { logFile: true // default: .transfer/<runId>/logs/<orchestrator|segment-N>.log // or: logFile: "./my-transfer.log" } ``` Writes raw pino JSONL to disk in addition to stdout. With `true`, each process gets its own file (orchestrator + one per worker), so concurrent appends can't interleave. With a string path, all processes append to the same file — fine for low-throughput orchestrator logs, risky when worker parallelism is high. Post-run inspection: `cat .transfer/<runId>/logs/*.log | pino-pretty`. Default path is under `.transfer/` (gitignored in this repo). Custom paths are the user's gitignore responsibility. ## Tuning (optional) ```ts tuning: { flushEvery: numberFromEnv("FLUSH_EVERY", 500), // records per shard flush — bounds peak memory ddb: { maxRetries: 3, initialBackoffMs: 100 }, s3: { concurrency: 10, maxRetries: 3, initialBackoffMs: 100 }, os: { maxRetries: 3, retryScheduleMs: [5000, 10000, 20000, 30000, 30000], gzipConcurrency: 16 } } ``` All optional; absent = built-in defaults. AWS SDK `retryMode: "adaptive"` is always on for DDB + S3 — it self-tunes backoff based on real throttle signals, so you usually don't need to tune these. **`flushEvery`** caps peak per-shard memory. The runner calls `processor.execute()` every N records and resets the pending-commands buffer. Default 500 (≈ 5 MB at a 10 KB average record). Lower to 100 for tables with very large records (approaching the 400 KB DDB max). ## Running it From the user project root: ```bash yarn transfer --config=./projects/<name>/ddb.transfer.config.ts ``` Or with a specific AWS profile pre-set in `.env`: ``` SOURCE_PROFILE=prod-reader TARGET_PROFILE=staging-writer ``` ## Common patterns - **DDB first, then OS** — run them as separate transfers with separate config files. They don't share state. DDB uses `v5-to-v6-ddb`; OS uses `v5-to-v6-os`. Both can share the same `.env`. - **Multiple target environments** — duplicate the project folder under `projects/` with different `.env`. Configs stay identical. - **Custom preset** — if the built-in doesn't match your needs, write one (see `writing-data-transfer-preset` skill) and point `pipeline.preset` at its file path. ## Anti-patterns - **`process.env.X!` bang-casting** — loses the friendly "variable not set" error, and silently passes `undefined` to the AWS SDK on typos. Use `fromEnv(name)` or `fromEnv(name, default)` instead. - **Hardcoded credentials in the config file** — `.env*` is gitignored; put secrets there. If `.env` ever grows a key that shouldn't be in source, make sure `.gitignore` covers it. - **Source and target point at the same table** — rejected at build time, but worth re-checking manually before a real run: different regions OR different table names.
عرض على GitHub