npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@c6fc/spellcraft-aws-terraform

v2.0.0

Published

S3 state backend, remote state lookups and artifact storage, including bootstrapping the bucket that holds them.

Readme

@c6fc/spellcraft-aws-terraform

S3 state backend, remote state, artifacts and provider aliases for SpellCraft.

NPM version License

This is the AWS half of the Terraform story: it decides where state lives, hands one spell the values another produced, and declares the providers that region-aware plugins bind to. @c6fc/spellcraft-terraform runs the apply; this tells it what to apply against.

npm install --save @c6fc/spellcraft-aws-terraform @c6fc/spellcraft-terraform

A complete spell

local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";
local s3 = import "@c6fc/spellcraft-aws-s3/module.libsonnet";

{
	// State backend, and the bucket to hold it. Created on first use.
	"backend.tf.json": aws.bootstrap("my-project"),

	// One aliased provider per region, plus an unaliased default.
	"providers.tf.json": { provider: aws.providerAliases("us-east-1") },

	"buckets.tf.json": s3.bucket("artifacts", "us-west-2"),
}
npx spellcraft terraform-apply manifest.jsonnet

Three things happen before Terraform sees anything: credentials resolve, the backend bucket is created if it is missing, and the region list is fetched to build the providers. The rendered .tf.json already contains the answers.

The bootstrap bucket

bootstrap(project) returns the Terraform backend block and makes sure the bucket behind it exists. There is one bucket per account, discovered by naming convention — spellcraft-<random>-<digits> — and shared by every spell, which is why project is a required argument: it becomes the key prefix that separates one spell's state from another's.

Finding more than one candidate bucket is an error rather than a guess.

getArtifact() and putArtifact() (below) both key their object off the project name bootstrap() records, so either one throws if it runs before some bootstrap() call has set it. Jsonnet doesn't otherwise guarantee that order — see the warning under "Sharing values between spells" for how to make it explicit.

Skipping bootstrap() entirely

Not every spell needs its project name computed at render time. If it's known ahead of time, set it in package.json instead:

{
	"config": {
		"spellcraftProject": "my-project"
	}
}

This bootstraps during init() — before any Jsonnet evaluation starts — so there's no ordering hazard to navigate at all: no threading a return value through, no risk of getArtifact()/putArtifact() running first. It also sidesteps a subtler hazard entirely: bootstrap()'s state lives in a module-level object shared by every SpellFrame in the process, so two renders for two different projects running concurrently (embedding SpellFrame as a library, rather than one process per spellcraft CLI invocation) could otherwise cross-contaminate. A config-driven project name is the same for every render in that process, so there's nothing left to race on.

config.spellcraftProject and an explicit bootstrap() call are mutually exclusive — set the former and the latter throws, rather than risking the two silently disagreeing about which project is live.

Sharing values between spells

Two ways, both resolved while the manifest evaluates rather than at apply time.

Remote state reads another spell's outputs:

local network = aws.getRemoteState("network");

{
	"app.tf.json": {
		resource: {
			aws_instance: {
				app: { subnet_id: network.outputs.subnet_id.value },
			},
		},
	},
}

Artifacts are arbitrary JSON values written under a project's prefix, for things that aren't Terraform outputs at all. Unlike getRemoteState(), they use this spell's own project — the one passed to bootstrap() — so bootstrap() has to run first:

local backend = aws.bootstrap("my-project");

{
	"backend.tf.json": backend,
	"meta.json": { ok: if backend != null then aws.putArtifact("build", { image: "app:1.4.2" }) else null },
}
local build = aws.getArtifact("build");

Jsonnet evaluates lazily and in no guaranteed field order, so merely calling bootstrap() somewhere in the manifest doesn't make it run before putArtifact()/getArtifact() elsewhere in the same manifest — the call that needs it has to depend on the result, as if backend != null then ... does above, not merely follow it. Get this wrong and putArtifact() / getArtifact() throw naming the fix, rather than silently writing to spellcraft/false/artifacts/<name>.

Because both land during evaluation, the value can shape the configuration — choosing how many resources to emit, or which branch to take — not merely appear inside it. A Terraform data source can only do the latter.

Provider aliases

providerAliases(default) emits an aliased aws provider for every region the account has enabled, with the alias set to the region name, plus an unaliased default for the region you name. Plugins then take a region as an argument and bind to aws.<region> without any per-spell wiring.

It is also the reason a spell only declares providers once, no matter how many region-aware plugins it uses.

The auth passthrough

aws.auth re-exports @c6fc/spellcraft-aws-auth, so a spell that already imports this module can reach the credential helpers without a second import:

{ "identity.json": aws.auth.getCallerIdentity() }

API Reference

bootstrap(project)

Prepares the S3 backend for a project, creating the bootstrap bucket if it does not exist yet, and returns the Terraform backend block for it.

This is the one function here that writes: it creates the bucket on first use. State and artifacts for every project live in that one bucket, keyed by project name.

getArtifact() and putArtifact() key their object off the project name this sets, so either one throws if it runs before this has. Jsonnet does not guarantee that order on its own -- thread this function's result into whatever calls them, the way enableServices() is threaded elsewhere in this ecosystem, rather than merely calling both in the same manifest.

A spell that only ever bootstraps one project, known ahead of time, can skip calling this from Jsonnet at all: set config.spellcraftProject in package.json and it runs during init(), before evaluation starts, so there's no ordering hazard to think about. The two are mutually exclusive -- calling this explicitly throws if config.spellcraftProject already bootstrapped the spell, rather than letting the two silently disagree about which project is live.

A spell has one project. Calling this again with a different name in the same process throws for the same reason -- to read another spell's state, use getRemoteState(), not a second bootstrap() call. The same name twice is a no-op.

  • param {string} project - names the state prefix; use one per spell
  • returns {object} a Terraform block ready to merge into a .tf.json file

Examples:

local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";

{ "backend.tf.json": aws.bootstrap("my-project") }

// Returns:
// {
//   "terraform": {
//     "backend": {
//       "s3": {
//         "bucket": "spellcraft-random-0123456789",
//         "key": "spellcraft/my-project/terraform.tfstate",
//         "region": "us-east-1"
//       }
//     }
//   }
// }

getArtifact(name)

Reads an artifact previously stored by putArtifact().

Artifacts are how one spell hands a value to another without a Terraform data source — the value is fetched while the manifest evaluates, so it can shape the configuration rather than only appear in it.

Throws if bootstrap() hasn't set a project name yet -- see bootstrap() for why that ordering isn't automatic.

  • param {string} name - the artifact name given to putArtifact()
  • returns {*} the stored value, parsed back from JSON

Examples:

local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";

local backend = aws.bootstrap("my-project");
local shared = if backend != null then aws.getArtifact("network") else null;

{ "app.tf.json": { resource: { aws_instance: { app: { subnet_id: shared.subnetId } } } } }

getBootstrapBucket()

The name of the bootstrap bucket, or false when none exists yet.

Discovery is by naming convention rather than by tag, and more than one match in the account is an error — there is meant to be exactly one.

  • returns {string|boolean} the bucket name, or false

Examples:

local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";

{ "state.json": { bucket: aws.getBootstrapBucket() } }

getRemoteState(project)

Reads the Terraform state of another SpellCraft project in the same account.

Use it to consume another spell's outputs at evaluation time. The project name is the one passed to that spell's bootstrap().

  • param {string} project - the other spell's project name
  • returns {object} that project's Terraform state

Examples:

local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";

local network = aws.getRemoteState("network");

{ "app.tf.json": { output: { vpc: { value: network.outputs.vpc_id.value } } } }

putArtifact(name, content)

Stores a value as a JSON artifact in the bootstrap bucket, under this project's prefix. Read it back with getArtifact().

Throws if bootstrap() hasn't set a project name yet -- see bootstrap() for why that ordering isn't automatic.

  • param {string} name - the artifact name
  • param {*} content - any JSON-serialisable value
  • returns {boolean} true

Examples:

local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";

local backend = aws.bootstrap("my-project");

{
    "backend.tf.json": backend,
    "meta.json": { stored: if backend != null then aws.putArtifact("network", { subnetId: "subnet-abc123" }) else null },
}

providerAliases(default)

Builds the full set of AWS provider declarations for a spell.

Returns one aliased provider per region your credentials can see — the alias is the region name, so resources bind to it as aws.us-west-2 — plus an unaliased default provider for the region you name. This is what lets plugins like @c6fc/spellcraft-aws-s3 take a region as an argument and place resources in it without every spell wiring providers by hand.

The region list comes from a live describeRegions call, so the set reflects what the account actually has enabled.

  • param {string} default - region for the unaliased default provider
  • returns {object[]} provider declarations, for the provider key of a .tf.json

Examples:

local aws = import "@c6fc/spellcraft-aws-terraform/module.libsonnet";

{ "providers.tf.json": { provider: aws.providerAliases("us-east-2") } }

// Returns:
// [
//   { "aws": { "alias": "us-east-1", "region": "us-east-1" } },
//   { "aws": { "alias": "us-west-2", "region": "us-west-2" } },
//   ...
//   { "aws": { "region": "us-east-2" } }
// ]

Development

npm test        # renders test.jsonnet through a real SpellFrame
npm run doc     # regenerates the API section above from module.libsonnet

npm test writes: it creates the bootstrap bucket if your account has none, and stores an artifact in it.

License

MIT © Brad Woodward