terradart_core 0.35.0 copy "terradart_core: ^0.35.0" to clipboard
terradart_core: ^0.35.0 copied to clipboard

terradart core runtime — Stack, Resource, Provider, Variable, Data, TfArg, TfRef, and LifecycleOptions for Dart-first Terraform synthesis.

Changelog #

0.35.0 - 2026-10-03 #

  • No API changes. Lockstep release with the terradart command's --json output, fixed exit codes, --no-input, --dry-run, terradart help <topic> and bundled agent skill.

0.34.0 - 2026-10-03 #

  • runEnvironments takes defaultEnv, the member terradart runs against when neither --env nor TERRADART_ENV names one; it records it in the manifest (default). Without --env, environments that share a directory write only defaultEnv instead of exiting 64. A defaultEnv that is not one of the environments throws ArgumentError.

0.33.0 - 2026-10-02 #

  • runStack(args, build) and runEnvironments(args, Env.values, build, {dir, workspace, backendConfig}) are the entry points bin/infra.dart calls: runEnvironments takes the members of an enum of the project's own, writes tf-out/<name> per member (every member, or the one --env <name> names; an unknown name exits 64 listing the members), and throws ArgumentError when environments share a directory that neither a workspace nor a partial backend configuration tells apart. Both describe what they wrote to the terradart command in the file TERRADART_MANIFEST names (terradartManifestVariable).
  • The <Stack>Outputs reader's missing-define StateError names the define file that carries the variable (--dart-define-from-file=.terradart/dart_defines.json) and the terradart apply / terradart outputs command that writes it, or says no addDartDefineOutput carries it.

0.32.1 - 2026-10-02 #

  • No API changes. Republishes the 0.32.0 workspace so terradart_appwrite, terradart_cloudflare, terradart_aws and terradart_migrate reach pub.dev; the 0.32.0 publish workflow stopped them at a wrapper-count check that also counted hand-written files, and now counts only generated wrappers (#877).

0.32.0 - 2026-10-02 #

  • Breaking: TfRef<T> is a sealed subtype of TfArg<T>, so an attribute getter passes straight into an argument of its type (labels: other.labels, addOutput('id', topic.id)). TfArg.ref and TfArgRef are removed; match TfRef() / AttributeRef(:owner, :attr) where code matched TfArgRef(:ref). AppConstant.ref(...) is unchanged. See MIGRATING.md.
  • RefTo.alsoAs(attribute) reads another attribute of the referenced block (null for a reference built from a value). Generated IAM adjuncts default the location / project / region / zone they share with their parent to it.
  • Stack.addDartDefineOutput({name = 'dart_defines', only, description}) declares an output whose value maps each variable outputEnvironment() would pass to its value — the JSON --dart-define-from-file reads, from terraform output -json dart_defines. It carries the non-sensitive outputs registered by synth time, or those only names; Stack.dartDefineOutputs lists them. Registration throws ArgumentError for a name that is not a Terraform identifier or is taken; synth reports InvalidDartDefineOutput when only names an unregistered or sensitive output, two outputs share a variable, or the file carries no output.
  • The generated <Stack>Outputs reader has const constructors — fromTerraformJson, fromEnvironment, and fromDartDefine(), which reads the variables compiled into the app (bool.hasEnvironment / String.fromEnvironment). A missing define throws StateError naming the variable and the output.
  • Stack.addConfigurationAlias registers a provider alias the calling module passes in (configuration_aliases = [google.eu]). Synth lists it on required_providers and emits no provider block for it; a resource selects the instance with provider:. The alias carries no configuration arguments.
  • Stack.addExternalProvider registers a provider configuration that lives in a file beside main.tf.json. Synth lists it on required_providers and emits no provider block, so a resource can still select the instance with provider:.
  • Breaking: Stack takes backend and requiredVersion (default '>= 1.11.0') as constructor arguments; setBackend and setRequiredVersion are removed, and writeTo defaults to 'tf-out'. TfTimeouts fields are Duration? (written as Go duration strings; a negative one is an InvalidTimeout), and TfTimeouts.of / isDuration are removed. outputEnvironment() returns an OutputEnvironment, an Iterable<({String name, TfArg<String> value})> for a list of blocks (a Cloud Run container's env) whose variables is the TfArg<Map<String, String>> a map argument takes (environment: .new(variables: outputEnvironment().variables) on an AwsLambdaFunction, environmentVariables on a Cloud Function). TfArg.literal is a const factory, so an explicit type argument is written TfArg<String>.literal(...). goDurationString / parseGoDuration are in package:terradart_core/internal.dart. See MIGRATING.md.
  • Breaking: TfJsonEncoder, hasTemplateSequence and templateVariableNames move from terradart_core.dart to package:terradart_core/internal.dart, the library for tools that generate or read TerraDart code. See MIGRATING.md.
  • Breaking: Resource.provider is the StackProvider? the block uses instead of a 'name.alias' string, and ModuleCall.providers is a Map<String, StackProvider>. Stack.addProvider registers a configuration from the constructor body and returns it, so provider: eu passes the instance. Resource.defaultProvider (the type prefix by default) is the provider a block without one uses; synth emits it when it differs from the prefix. MissingProvider covers an instance the Stack does not register (unregisteredInstance). See MIGRATING.md.
  • Breaking: LifecycleOptions.ignoreChanges is a sealed IgnoreChanges (IgnoreChanges.all, IgnoreChanges.of([...])) instead of List<String>, and replaceTriggeredBy is a List<ReplaceTrigger> — Resource and TfRef implement it, so a whole resource goes in as it is ([template, template.id]). LifecycleOptions.conditions takes LifecycleCondition.pre / .post (precondition / postcondition blocks). createBeforeDestroy: false and preventDestroy: false are written instead of dropped. Synth reports InvalidLifecycle for a data source in replaceTriggeredBy, 'all' inside .of, or an empty condition message. See MIGRATING.md.
  • Breaking: Sensitive<T> is the type of an argument Terraform marks sensitive: a sealed TfArg<T> with Sensitive.variable and Sensitive.expression but no .literal. TfArgVariable, TfArgExpression and every TfRef (attribute getters) implement it. See MIGRATING.md.
  • Breaking: Stack.variable<T>(name, {type, description, defaultValue, sensitive, nullable}) declares a variable and returns its TfArgVariable<T> handle, which an argument takes as is (location: region); the Terraform type is derived from T unless type: says otherwise. addVariable is removed, addExternalVariable is externalVariable<T> (returning the handle), and TfVariable.type is a sealed TfType (TfType.string, .list(...), .set(...), .map(...), .object({...}), .tuple([...]), .optional(...)) instead of a string. TfArgVariable.interpolation is ${var.<name>}. See MIGRATING.md.
  • Breaking: TerraformEnum is removed. A Terraform enum is an extension type over TfArg<String> whose members are static const TfArgLiterals (the README shows the shape), so it passes to a TfArg<String> slot directly. TfArgLiteral.toTfJson() throws ArgumentError for a plain Dart enum. See MIGRATING.md.
  • Breaking: Resource, Data and ModuleCall take the local name as their first positional argument: Resource(this.localName, {...}), ModuleCall(this.localName, {required this.source, ...}). See MIGRATING.md.
  • Breaking: Stack.add registers a data source as well as a resource, and Stack.addData is removed. See MIGRATING.md.
  • Breaking: dependsOn on Resource, Data and ModuleCall is a List<TfAddressed> — dependsOn: [schema, api]. DependencyTarget, ResourceDependency and RefDependency are removed (Terraform rejects an attribute in depends_on). Synth output is unchanged. See MIGRATING.md.
  • Breaking: synth validation is one sealed type. Stack.synth() / writeTo() throw one SynthException listing every SynthIssue (NoProviders, MissingProvider, ProviderConflict, UndeclaredVariable, UnregisteredReference, SensitiveLiteral, InvalidTimeout, InvalidMoveTarget, UnresolvableConstant) instead of throwing StateError / SensitiveLiteralError / ArgumentError at the first problem; Stack.validate() returns the issues without throwing. SensitiveLiteralError, TfJsonEncoder.validateProviders and TfJsonEncoder.encodeArgMapWithSensitive are removed, and the remaining TfJsonEncoder helpers no longer validate.
  • New check: a reference (or depends_on / replace_triggered_by) to a resource, data source or module the Stack does not hold is an UnregisteredReference. Stack.addExternalBlock(address) / externalBlocks declare a block a hand-written file holds.
  • add, addModule, variable and externalVariable throw ArgumentError for a name that is not a Terraform identifier.
  • Every Dart example in a doc comment compiles (tool/doc_snippets.dart): the TfTimeouts, TfMoved, ModuleCall, Stack.outputEnvironment, Stack.addModule, AppExports, S3Backend.r2 and TfArg examples name every required argument. Doc comments only.

0.31.0 - 2026-10-01 #

  • The appExports file also holds <Stack>Outputs, a typed reader of the Stack's non-sensitive outputs: a lowerCamelCase getter per output, typed like its value, from <Stack>Outputs.fromTerraformJson(Map<String, Object?>) (terraform output -json) or <Stack>Outputs.fromEnvironment(Map<String, String>) (ORDERS_TOPIC_ID for orders_topic_id; a String is the raw value, any other type JSON). Getters read lazily and throw StateError on a missing or mistyped value. With appExports set, addOutput throws ArgumentError when the output's getter is not a usable Dart identifier or its getter or variable is another output's. The file now imports dart:convert.
  • Stack.outputEnvironment({Iterable<String>? only}) returns the environment fromEnvironment reads — Map<String, TfArg<String>> from variable name to the output's value (a String as is, any other type ${jsonencode(...)}), for the non-sensitive outputs registered so far — to pass as a Cloud Run service's or function's env. Throws StateError without appExports, and ArgumentError for a name in only that is not a registered non-sensitive output or an output with no environment value.
  • Breaking — Stack.addOutput and Stack.addConstant replace addExport. addOutput<T>(name, TfArg<T> value, {description, sensitive}) declares a Terraform output; addConstant<T>(name, AppConstant<T>) declares a static const of the generated <Stack>Constants class, from a sealed AppConstant<T>: .ref(TfRef<T>) (the literal the attribute is set to, resolved at synth), .value(T) or AppConstant.fromEnvironment(name). T is any JSON value type, List<E> or Map<String, V> of them, each optionally nullable. The constants file is a constructor parameter, appExports: AppExports(path, {name}), and Stack.outputs / Stack.constants expose what was registered. Registration rejects a bad or duplicate name, an unsupported type, a .value that is not a T, a whole-resource .ref, a constant without appExports, and a non-sensitive output that reads a sensitive field. Synth throws StateError when a .ref constant's attribute is not a literal (naming what sets it), is a sensitive field, or belongs to an unregistered block. With appExports set, writeTo rewrites the file on every synth. SynthResult.dartConstants becomes dartSource + dartSourcePath, and Stack.synth() loses its stackName parameter (AppExports.name sets the class prefix). Removed: AppExport, ResourceIdExport, ResourceAttributeExport, StringExport, EnvBackedExport, setAppExportsOutputPath, appExportsOutputPath, and the barrel exports of the synth internals DartConstantsEmitter, LiteralResolver, OutputEmitter, OutputEmissionResult, TerraformOutputSpec and DartConstantSpec. See MIGRATING.md.
  • AppConstant.valueType, TfOutput.valueType and TfOutput.toTfJson are @internal: synth reads them, and valueType returns a type the barrel does not export.
  • RefToList — encodeAs on a TfArg<List<RefTo<R>>>: a literal list encodes element by element, a whole-list value (TfArg.variable('subnet_ids')) passes through.
  • RefTo<R> — a reference to a resource of type R, for arguments that name another resource. An extension type over a record, so R is checked at compile time and erased at run time. A generated ref getter returns one (RefTo.of), the argument that takes it picks the attribute it emits (encodeAs('self_link')), pinned('id') keeps a given attribute, and RefTo.literal / RefTo.variable / RefTo.expression / RefTo.arg carry values from outside the Stack (dot shorthands: .literal('...')). No argument takes one yet.
  • Breaking — requires Dart 3.10 (sdk: ^3.10.0, was ^3.6.0). Source is formatted in the Dart 3.7+ tall style.
  • Dartdoc on TfAddressed.tfAddress and Resource.tfAddress, which every factory inherits. No API changes.

0.30.0 - 2026-09-28 #

  • Sensitive-field paths accept a * segment for a map of blocks: env_vars.*.value checks value in every entry of env_vars, and a plain literal fails synth with the entry's key in the field path (env_vars.API_KEY.value).

0.29.0 - 2026-09-27 #

Lockstep release. No terradart_core API changes; terradart_time and terradart_aws publish for the first time on this version.

0.28.1 - 2026-09-13 #

Lockstep release with terradart_migrate 0.28.1 (passthrough emission fix — a bare Map / List parameter no longer comes out as TfArg.literal). No terradart_core API changes.

0.28.0 - 2026-09-13 #

Added #

  • TfArg.expression (TfArgExpression) — a raw Terraform expression, emitted verbatim as the tf.json template it is: TfArg.expression(r'${lower(var.name)}-x'), TfArg.expression<int>(r'${var.replicas * 2}'). Accepted on sensitive fields like TfArg.ref and TfArg.variable (no value is stored in it); the var.<name> references inside it are checked against the Stack's declarations at synth time; a plain value with no ${ ... } / %{ ... } sequence is rejected with an ArgumentError. Replaces the TfArg.literal(r'${...}') workaround. Breaking for exhaustive switches over TfArg — see MIGRATING.md (#662).
  • hasTemplateSequence / templateVariableNames — the template scanner behind it (escapes, quoted strings and directives handled), exported for tools that generate TfArg code.
  • Provider aliases — StackProvider.alias (provider "google" { alias = "eu" }), settable on every provider class in the workspace, and Resource.provider / Data.provider settable from every curated factory's new provider: parameter (provider: 'google.eu', or provider: 'google-beta' on a GA type). Synth emits provider.<name> as a list when a name has more than one configuration (Terraform's JSON form for aliases; a single default configuration keeps the object form) and rejects a provider: with no matching registration, the same name registered twice without an alias or with the same alias twice, and an alias that is not a Terraform identifier. Breaking for hand-written StackProvider implementations (one getter) — see MIGRATING.md (#666).
  • TfTimeouts / Resource.timeouts — the timeouts { ... } block as a Dart value (create, read, update, delete), on every curated factory and data source through the shared timeouts: parameter, emitted verbatim under the block's timeouts key. Provider-neutral like lifecycle: the values are the Go duration strings Terraform writes ('30m', '1h30m') — references are not allowed there — and which operations a type declares is terraform validate's business, not synth's. TfTimeouts.of(create: Duration(minutes: 30)) builds one from Durations; a value that is not a duration string throws (#671).
  • TfArg.workspace() — ${terraform.workspace}, the selected workspace's name, as a named argument instead of a hand-written expression. Sugar over TfArg.expression, so nothing about state layout or workspace selection changes (#671).
  • Partial backend configuration — every field of GcsBackend and S3Backend is optional, so a block whose values arrive at init time (terraform init -backend-config=bucket=...) is expressible: const GcsBackend() emits backend "gcs" {}. S3Backend.r2 keeps its endpoint and flag preset with bucket / key left out (#671).
  • ModuleCall / Stack.addModule — a module "<name>" { ... } call as a Dart value: source, version, inputs, providers, count / for_each and depends_on, emitted under the top-level module key in registration order. A module's outputs are read back as TfRefs (call.output<String>('member') → ${module.<name>.member}), so they flow into any TfArg slot, depends_on, lifecycle and exports. Synth validates what Terraform would: an input named like a meta-argument is rejected at construction, a providers value must name a registered provider configuration, and var.<name> references inside the inputs are checked like a resource's. A repeated local name throws DuplicateModuleError (#665).
  • A Stack that only calls modules needs no provider — Stack(providers: []) synthesizes when the stack registers at least one ModuleCall and no resource or data source of its own: the child modules pin what they use, so required_providers is omitted rather than empty. A stack with a resource still needs its provider (#665).
  • Stack.addMoved / TfMoved — moved { from = ... to = ... } blocks, emitted under the top-level moved key in registration order, so a renamed resource (or a count / for_each instance unrolled into its own resource) keeps its state. Registration rejects an empty or repeated from and from == to; synth rejects a to that names no resource of the Stack (a module. address passes) (#663).

Changed #

  • Sensitive nested fields accept any Terraform template — an unescaped ${ ... } or %{ ... } anywhere in the string — where they accepted only a string starting with ${ (#662).
  • SensitiveLiteralError — the recovery hint mentions TfArg.expression for values Terraform computes.

0.27.0 - 2026-08-30 #

Lockstep release across the workspace. Breaking — see MIGRATING.md.

Added #

  • S3Backend — terraform { backend "s3" { ... } } configuration, alongside the existing GcsBackend and LocalBackend. Covers S3 and the S3-compatible stores (Cloudflare R2, MinIO, Backblaze B2) via endpoints plus the skip_* flags. S3Backend.r2(accountId:, bucket:, key:) fills in the R2 endpoint, region = "auto", path-style addressing, and all five skip flags. Optional fields are omitted from the emitted JSON when null; an explicit false is emitted.
  • TfVariable + Stack.addVariable — declare the variable "<name>" { ... } blocks that TfArg.variable references. Synth emits them under the top-level variable key, and omits the key when a stack declares none (Terraform rejects an empty variable block).
  • Stack.addExternalVariable — accept TfArg.variable references to a variable declared in a hand-written file beside the generated main.tf.json, without emitting a block for it. For declarations TfVariable cannot model (validation { ... }) and for existing stacks that keep a variables.tf.
  • Undeclared-variable check at synth time — synth throws a StateError naming the variable and the resources referencing it when a TfArg.variable reference has no matching addVariable declaration, including references nested inside literal Maps and Lists. Previously such a config synthesised cleanly and failed at terraform plan with "Reference to undeclared input variable". Breaking — see MIGRATING.md.

Fixed #

  • Docs — Stack.backend and backends.dart described S3 as living in "provider-specific packages" and named an S3Backend that no package shipped. Both now describe what core actually provides.

Changed #

  • SensitiveLiteralError — the recovery hint now points at addVariable instead of telling the user to hand-write a variable block.

0.26.0 - 2026-08-24 #

Lockstep release with terradart_cloudflare 0.26.0 (catalog filled at the 5.23.0 pin). No terradart_core API changes.

0.25.3 - 2026-08-23 #

Lockstep release with terradart_appwrite 0.25.3 (catalog filled at the 2.0.0-beta.1 pin). No terradart_core API changes.

0.25.2 - 2026-08-22 #

Lockstep release with terradart_cloudflare 0.25.2 (initial release). No terradart_core API changes.

0.25.1 - 2026-08-19 #

Lockstep release with terradart_google_beta 0.25.1 (beta-only catalog filled). No terradart_core API changes.

0.25.0 - 2026-08-15 #

Lockstep release with terradart_google 0.25.0 (GA hashicorp/google catalog filled). No terradart_core API changes.

0.24.0 - 2026-07-03 #

Lockstep release with terradart_google 0.24.0 (typed nested helpers). No terradart_core API changes.

0.23.0 - 2026-07-02 #

Lockstep release. Breaking — see MIGRATING.md.

Breaking #

  • Removed the StackProvider.toTfJson() backwards-compat shim; read configArgs directly. Backend.toTfJson() / TfArg.toTfJson() are unchanged (real, distinct APIs).

0.22.0 - 2026-06-30 #

Lockstep release for Waves 76–77. No API changes in terradart_core.

0.21.0 - 2026-06-28 #

Lockstep release for Wave 74. No API changes in terradart_core.

0.20.0 - 2026-06-21 #

Lockstep release for Wave 73. No API changes in terradart_core.

0.19.0 - 2026-06-21 #

Lockstep release. No API changes vs 0.18.0.

0.18.0 - 2026-06-21 #

Lockstep release. No API changes vs 0.17.1.

0.17.1 - 2026-06-21 #

Lockstep release. No terradart_core API changes.

0.17.0 - 2026-06-21 #

Lockstep release. No terradart_core API changes.

0.16.0 - 2026-06-21 #

Lockstep release. No terradart_core API changes.

0.15.0 - 2026-06-20 #

Lockstep release. No terradart_core API changes.

0.14.0 - 2026-06-16 #

Lockstep release. No terradart_core API changes.

0.13.0 - 2026-06-14 #

Lockstep release. Breaking — see MIGRATING.md.

Breaking #

  • TimeProvider / TimeSleep moved to terradart_google (package:terradart_google/time.dart) — core is provider-neutral again.
  • Removed the unimplemented provider-aliasing surface: StackProvider.providerAlias, ProviderBinding, and Resource.provider. None of it ever reached the synthesized JSON; aliasing returns when multi-provider stacks land.
  • Stack.synth() validates provider coverage: a registered resource / data source whose type prefix (segment before the first _) has no matching provider providerName now throws StateError instead of silently falling back to an unpinned implied provider.

0.12.19 #

Added #

  • TimeProvider — hashicorp/time stack provider (~> 0.12) for propagation waits.
  • TimeSleep — hand-written time_sleep resource wrapper.

0.12.18 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.18 (Wave 31 Private CA template + pool IAM).

0.12.17 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.17 (Apis.required helper).

0.12.16 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.16 (Wave 30 Private CA certificate).

0.12.15 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.15 (Wave 29 Private CA certificate authority).

0.12.14 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.14 (Wave 28 Private CA pool).

0.12.13 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.13 (Wave 27 Certificate Manager trust + issuance; GoogleProject example backfill).

0.12.12 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.12 (sealed exactly_one_of enforcement on seven factories; see MIGRATING.md).

0.12.11 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.11 (Wave 25 VPC Access connector; Wave 26 Certificate Manager; Artifact Registry remote docker/maven/npm enums).

0.12.10 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.10 (Wave 23 DNS, Eventarc, Cloud Run worker pool, IAP).

0.12.9 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.9 (Wave 22 BigQuery Analytics Hub IAM + Compute regional Armor).

0.12.8 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.8 (Waves 17–21 Eventarc + Compute/BigQuery/Storage/SQL/Firebase).

0.12.7 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.7 (Waves 12–15 Monitoring + Compute/KMS/Pub/Sub/Storage).

0.12.6 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.6 (Wave 10 GKE Backup + Wave 11 Logging project ops).

0.12.5 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.5 (Wave 9 GKE Hub + example/docs debt).

0.12.4 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.4 (Wave 8 GKE core curated factories).

0.12.3 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.3 (WIF provider sealed trust-source breaking fix).

0.12.2 #

No user-facing API changes. Lockstep version bump for terradart_google v0.12.2 (two new curated factories). The terradart_core public surface is unchanged from 0.12.1.

0.12.1 #

No user-facing API changes. Lockstep version bump alongside the terradart_agent v0.12.1 fix (MCP structuredContent object shape). The terradart_core public surface is unchanged from 0.12.0.

0.12.0 #

No user-facing API changes. Lockstep version bump alongside the rest of the workspace for the v0.12.0 release (terradart_codegen static-catalog emission, terradart_google generated catalog, and the new terradart_agent / terradart-mcp package). The terradart_core public surface is unchanged from 0.11.0.

0.11.0 2026-MM-DD #

BREAKING — pre-1.0 polish wave on the terradart_core public surface. Coordinated changes from ADR-0016 (codegen identifier rename) and ADR-0017 (Stack API surface). v0.x permits breaking changes; the 0.11.x line continues to stage the 1.0 surface. See MIGRATING.md for before / after snippets covering every item below.

  • Stack.synth({required outDir}) split — Stack.synth() → SynthResult is now the pure in-memory step that returns the encoded tfJson plus the optional dartConstants source for AppExports. Stack.writeTo(outDir) → Future<void> is the new file-IO wrapper that always writes main.tf.json and, when AppExports produced Dart constants AND setAppExportsOutputPath was called, also writes the generated constants file at that path. writeTo throws StateError atomically — before any disk write — when addExport was called without setAppExportsOutputPath.
  • StackSynth removed from the public barrel — call stack.synth() instead of StackSynth.synth(stack). The class is annotated @internal; advanced users may still import it via the deep path package:terradart_core/src/synth/stack_synth.dart.
  • Stack, Resource, Data promoted to abstract base class — user subclasses must now be declared final class XxxStack extends Stack (or base / sealed). implements Stack / implements Resource / implements Data are no longer permitted (was a state-bypass foot-gun).
  • Resource.$sensitiveFields → Resource.sensitiveFields and Resource.$supportsDeletionProtection → Resource.supportsDeletionProtection — dollar-prefix dropped. Both annotated @protected (from package:meta); non-subclass reads require an // ignore: invalid_use_of_protected_member directive with rationale. Privileged in-library consumers (the TfJsonEncoder synth call sites) already carry the ignore comment with justification.
  • TerraformEnum interface added — abstract interface class TerraformEnum { String get terraformValue; } is re-exported from the terradart_core barrel. TfArgLiteral.toTfJson enum dispatch now routes through if (v is TerraformEnum); the previous duck-typed dynamic.terraformValue cast and its // ignore: avoid_dynamic_calls directive are retired. Hand-rolled Terraform-mapped enums must add implements TerraformEnum and @override final String terraformValue;; codegen-emitted enums get this automatically.

Non-breaking improvements #

  • encodeArg / encodeArgMap / encodeArgMapWithSensitive return types tightened from dynamic to Object? / Map<String, Object?> — non-breaking at runtime, but call sites benefit from static type checking.
  • Internal _DedupKey value type rewritten as a Dart 3 named record. Drops the unused package:meta/meta.dart import.
  • dart:convert import prefixes unified across lib/ and test/ (as dart_convert / as conv / as convert → no prefix everywhere).

0.10.0 2026-MM-DD #

No user-facing API changes. Workspace consistency bump alongside terradart_google 0.10.0 (Firestore document curation + FirestoreFields.encode helper).

0.9.0 - 2026-05-21 #

BREAKING — pre-1.0 polish wave consuming dogfood findings (issues #52-#57). v0.x permits breaking changes; 1.0 semver lock is deferred until cookbook recipes + real-apply feedback have absorbed more cycles. The 0.9.x line is the staging ground for the 1.0 surface:

  • Stack.synth({required String outDir}) is now concrete — default implementation writes pretty-printed ${outDir}/main.tf.json and creates outDir recursively. Subclasses may still override; existing overrides that delegated to StackSynth.synth(this) + JsonEncoder.withIndent(' ') can be deleted in favour of the default.
  • JsonEncoder → TfJsonEncoder — the synth-time JSON encoder class no longer shadows dart:convert's JsonEncoder. Consumers that imported the class directly need to rename references; consumers using only Stack / StackSynth are unaffected.
  • Stack({bool devMode = false}) — new constructor parameter. When true, synth-time injection flips deletion_protection: false on registered resources whose Resource.$supportsDeletionProtection is true and that did not explicitly set the field. Intended for dogfood / sample apps; production stacks leave it false.
  • Resource.$supportsDeletionProtection — new capability getter (default false); codegen overrides to true on 6 curated resources with a deletion_protection attribute.
  • LocalBackend added — StackBackend implementation matching the existing GcsBackend shape. Pass via Stack(backend: const LocalBackend()); no more handwritten tf-out/terraform.tf.
  • TfArg.variable(String name) + TfArgVariable<T> added — third peer of the sealed TfArg<T> family. Emits "${var.<name>}" interpolation. Canonical pattern for sensitive runtime values.
  • SensitiveLiteralError added — thrown by TfJsonEncoder.encodeArgMapWithSensitive when a TfArgLiteral is assigned to a sensitive field. v0.x silently masked the value to empty string, which caused apply-time HTTP 400. Recovery: switch to TfArg.variable(...) or the <field>_wo write-only variant.
  • encodeArgMapWithSensitive signature — gains a required String resourceAddress parameter (used by SensitiveLiteralError for diagnostic messages). Internal callers (TfJsonEncoder.resourceBlock) updated.

See MIGRATING.md for the full rename table + sed recipes.

0.8.0-dev - 2026-05-19 #

No user-facing API changes. Workspace consistency bump alongside terradart_google 0.8.0-dev (Wave 7: 23 new GA resources across Data ops + observability + CI/CD — Cloud Build, Artifact Registry, Logging, Monitoring, BigQuery, plus event-driven adjacent: Eventarc, Pub/Sub schema, Storage notification).

0.7.0-dev - 2026-05-19 #

No user-facing API changes. Workspace consistency bump alongside terradart_google 0.7.0-dev (Wave 6: 25 new GA resources across the L7 Application Load Balancer stack — Global + Regional/Internal cores, Health checks, MIG/Autoscaler, NEG, Cloud Armor, SSL Policy).

0.6.0-dev - 2026-05-18 #

No user-facing API changes. Workspace consistency bump alongside terradart_google 0.6.0-dev (Wave 5: 22 new GA resources across IAM completion + Cloud SQL + *_iam_member fill).

0.5.0-dev #

BREAKING — Plan 5.X: schemantic removal + Resource type flattening.

  • Dropped Resource<S> generic — Resource is now flat. User wrappers extend Resource without a type parameter.
  • Dropped Resource.schema field.
  • Dropped SchemaCarrier<S> interface.
  • Dropped ResourceRef<S>.placeholder — ResourceRef no longer carries a schemantic-instance type parameter (it pins to Object? since the value never escapes).
  • Dropped TfArgRef.literalOrPlaceholder.
  • Deleted placeholder.dart.
  • Existing dead tests around the above (e.g. r.schema.name assertions) removed.
  • See ADR-0013 for full rationale.

0.4.0-dev - 2026-05-17 #

No user-facing API changes. Workspace consistency bump alongside terradart_codegen 0.4.0-dev (Plan 5.D: codegen correctness improvements — MM YAML deprecation parsing fix, encode skeleton fix + Gate 6, paramOrder measurement tool, min_items assert hints).

0.3.0-dev - 2026-05-16 #

No user-facing API changes. Workspace consistency bump alongside terradart_google 0.3.0-dev (Wave 4: 21 new GA resources across 6 Firebase / Cloud Functions / Firestore services).

0.2.1-dev - 2026-05-16 #

No API change since 0.2.0-dev. Workspace consistency bump after the 0.2.0-dev publish run partially failed; 0.2.1-dev republishes through a re-ordered publish pipeline.

0.2.0-dev - 2026-05-16 #

Added #

  • TfArg.duration(Duration) factory — converts a Dart Duration to the "{seconds}s" form Terraform expects for duration-string fields (rotation_period, message_retention_duration, the 's'-suffixed forms of ack_deadline_seconds, etc.). Sub-second precision and negative durations are rejected with ArgumentError.

Fixed #

  • JsonEncoder.encodeArgMapWithSensitive now masks sensitive paths through nested-block (List<Map>) structures. Previously, paths like customer_encryption.encryption_key were left as plaintext in tf-out/main.tf.json because the masker only walked top-level keys. Ref interpolations (${...}) continue to pass through unchanged so Terraform wiring is preserved.

0.1.0-dev - 2026-05-14 #

Added #

  • TfArg<MyEnum>.literal(MyEnum.foo) now encodes typed Dart enums to Terraform strings via a new .terraformValue convention. Declare your enum as:

    enum MyEnum {
      foo('FOO'),
      bar('BAR');
      const MyEnum(this.terraformValue);
      final String terraformValue;
    }
    

    and TfArgLiteral.toTfJson() will serialize MyEnum.foo as the string "FOO". Throws ArgumentError (not silent wrong-output) if you pass an enum value whose type does not implement the convention.

  • String / int / num / bool literals continue to pass through toTfJson() unchanged.

Notes #

  • No breaking changes to Stack / Resource / Data / StackSynth / Provider / Variable<T> / LifecycleOptions / AppExport / TfArg / TfRef.

0.0.4-dev - 2026-05-11 #

  • No user-facing API changes. Version bumped for workspace consistency with Phase 4.1 (terradart wrap subcommand + DataSource emitters + 13 terradart_google wrappers migrated to generator output).

0.0.3-dev - 2026-05-09 #

  • Fix: rename terradart_core main library file to match package name.

0.0.2-dev - 2026-05-09 #

  • CI automated publishing via OIDC trusted publisher.
  • Fix: prepare_publish.sh now syncs version from tag name.

0.0.1-dev - 2026-05-09 #

Added #

  • Initial pre-alpha release of terradart core runtime.
  • Stack abstract base — register Resource<S> / Data<S> instances via add(...) / addData(...).
  • StackSynth.synth(stack) returning SynthResult (Terraform JSON + optional Dart constants).
  • Resource<S> / Data<S> typed nodes; Provider, Variable<T>, LifecycleOptions, AppExport.
  • TfArg.literal(...) / TfArg.ref(...) argument helpers.

Notes #

  • Pre-alpha — surface and emitted Dart symbols may change between 0.0.x releases.
3
likes
160
points
1.17k
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

terradart core runtime — Stack, Resource, Provider, Variable, Data, TfArg, TfRef, and LifecycleOptions for Dart-first Terraform synthesis.

Repository (GitHub)
View/report issues
Contributing

Topics

#terraform #infrastructure #codegen #google-cloud

License

Apache-2.0 (license)

Dependencies

meta

More

Packages that depend on terradart_core