@dashkite/drn
v0.12.16
Published
Helpers for DashKite Resource Names
Readme
DRN
Helpers for Dynamic Resource Names
import { resolve } from "@dashkite/drn-sky"
do ->
console.log "Lambda name:",
await resolve "drn:lambda/dashkite/load-media"
console.log "Graphene database:",
await resolve
namespace: "dashkite"
name: "accounts"Installation
pnpm add @dashkite/drn
In practice, you probably want to use DRN Sky (@dashkite/drn-sky) or DRN Browser (@dashkite/drn-browser) rather than the DRN module itself, since it doesn’t include any actual resolvers itself.
Status
Do not use in production unless you know what you’re doing. 😅
Roadmap
- Possibly make use of AWS staging distributions (see below)
- Codex for domain-like resources (including origins, S3 buckets, and so on) may map to a
subdomainproperty, rather than a fixednamespaceandnamepair. We would need to reorder the components so that the subdomain came last because URL Codex templates don’t support wildcard components that are followed by additional components, in part because that would allow specification of ambiguous templates. Alternatively, we could use dot-notation to indicate a subdomain, since we don’t typically need to parse it farther. - We could also incorporate addresses into subdomains by simply adding another domain component, instead of prefixing the subdomain.
- Improve the interface for defining resolvers. Right now, the templates show up in both of the modules that define resolvers. Perhaps the templates should be “baked in” to the core DRN module? In addition, the DRN Browser module overrides the
resolvefunction by simply exporting a different implementation, which is a little wonky. It still feels like we don’t quite have the right abstraction for providing different resolvers. - We might want to consider introducing a URI Codex module, that’s analogous to the URL Codex module, but supports creating URI templates directly. (What we currently do is extract the path from the URI and use path templates.)
DRN API
resolve
resolve drn ⇢ name
resolve drd ⇢ name
Takes a DRN or DRD and returns a promise resolving to a name.
Example
import { resolve } from "@dashkite/drn-sky"
do ->
console.log "Lambda name:",
await resolve "drn:lambda/dashkite/load-media"
console.log "Graphene database address:",
await resolve
type: "graphene"
namespace: "dashkite"
name: "accounts"encode
encode drd → drn
Takes a DRD and returns the corresponding DRN.
decode
decode drn → drd
Takes a DRN and returns the corresponding DRD.
describe
describe drn ⇢ text
describe drd ⇢ text
Takes a DRN or DRD and returns a textual description of the resource.
Resolving DRNs In The Browser
The DRN Browser module implements the complete DRN API and a complete set of resolvers, just like the DRN Sky module. However, you must activate the Sky env preset when building the browser application to ensure the DRN dictionary is available. Each DRN you want to access should be listed in the env configuration stanza:
sky:
env:
drn:
- drn:domain/workspaces/dashkite/io
- drn:domain/authenticate/dashkite/io
- drn:domain/db/dashkite/io
- drn:domain/sites/dashkite/io
- drn:origin/workspaces/dashkite/io
- drn:origin/authenticate/dashkite/io
- drn:origin/db/dashkite/io
- drn:origin/sites/dashkite/io
- drn:origin/workspaces/dashkite/comThe Sky env preset resolves the DRNs into a dictionary, which is The dictionary is serialized and placed into the registry under the sky.env.drn.dictionary key. We currently use the dictionary to expand templates containing DRNs. However, in the future, we could migrate to simply resolving them as necessary within the application code.
Background
Dynamic Resource Names[^naming-things-is-hard]are URIs that look like this:
drn:domain/modules/dashkite/io
drn:graphene/dashkite/accounts
drn:lambda/dashkite/load-mediaThe main thing you do with DRNs is resolve them relative to an environment. For example, resolving a DRN that corresponds to a domain name will give you an environment-specific domain name, such as:
modules-ey22d0g5bun7110sjiguxirip.dashkite.ioEnvironments
So: what’s an environment? The environment refers to the runtime envionment. This can be the browser, a development machine, or a server. A resolver extracts traits from an environment when resolving a DRN into an actual name.
In other words, so long as you use DRNs everywhere, you can reference things relative to an environment. We can then say things like deploy drn:lambda/dashkite/load-media without needing to specify that we want to deploy a development version, not a production version.
The Resolve Function
As you might expect, the main interface for a DRN is the resolve function. You can pass either a URI or an description object, also known as a Dynamic Resource Description, or DRD. For example, the DRD for the Lambda function in the previous example would be:
type: lambda
namespace: dashkite
name: load-mediaDRDs are handy when you already have the properties typically encoded in a DRN, but you don’t actually have a DRN. Instead of first constructing a DRN, you can just resolve the DRD directly.[^why-drds]
Other Features
However, sometimes you don’t necessarily want to just resolve something. You can encode a DRD to get a DRN and decode a DRN to get a DRD. In addition, you can describe a DRD or DRN if you want to include a text description of the associated resource in something like a CloudFormation template.
Structure Of A DRN
The format of a DRN depends on the type of the resource. However, they always start out with the drn: prefix, followed by the type. By convention, the remainder of the DRN is a path, whose components encode different properties. Let’s consider two examples: a domain DRN and a Lambda DRN.
drn:domain/modules/dashkite/io
└─┬──┘ └──┬──┘ └──┬───┘ └┬┘
type name namespace tldTypically, DRNs allow for a logical namespace and a name. For domains, these correspond to the subdomain.[^domains] The corresponding path template looks like:
/{name}/{namespace}/{tld}Similarly, Lambdas may be referenced like this:
drn:lambda/dashkite/load-media
└─┬──┘ └──┬───┘ └───┬────┘
type namespace nameThe corresponding path template looks like:
/{namespace}/{name}Resolvers
Now that we understand what DRNs are and how they’re used, let’s talk about resolvers. A resolver knows how to map DRNs to their corresponding names. The DRN Sky module provides resolvers that incorporate environment variables, branch names, and even MAC addresses to generate an address that can be used to construct unique, environment-specific names. Meanwhile, the DRN Browser module relies on a DRN dictionary in the registry. The Genie Sky env preset knows to inject the dictionary into the application HTML at build time.
Changes From Initial Implementation
- The original implementation used DRN to refer to the resolved name. Thus, we had a function called
getDRNthat was analogous to ourresolvefunction. That function would only accept URIs (what we now refer to as DRNs), so we often first had to create one using a separate Name module. Sinceresolvemay take a description object now, that module is no longer necessary. - We originally encoded the DRNs using a
>in place of the URI:to avoid possible YAML parsing problems. As it turns out that syntax works fine with YAML (which requires a space after the colon), we no longer do this. - The components and their order within a DRN path was previously fixed. We can now specify these using URL path templates, using the URL Codex format. In particular, we can now specify domains using the same order in which they appear in the resolved domain name, such as
modules/dashkite/io.
Relationship To Other Concepts And Technologies
HTTP Resources
DRDs are similar to HTTP resources, in that we effectively encode a description of a resource in the URI. Like HTTP URLs, the encoding may be expressed via a template. Of course, the content-type is always text (a name), and instead of accessing the resource via HTTP, we resolve it via a function.
Cloud Deployment Environments
Cloud providers like AWS may provide direct support for different environments. For example, Amazon CloudFront allows you to create different distributions for testing from an existing distribution. These are directly associated with the initial distribution: routing is based on headers, rather than creating a new distribution and corresponding DNS entry. However, this feature is primarily designed to allow seamless transition to a new distribution, which is a slightly different problem than the one we’re trying to solve with DRNs. At some point, we might want to integrate features like this into Sky, but we would still want a way to reference Lambdas or database tables relative to a given environment.
CI/CD Tools
One of the design goals we’ve embraced with Sky is to lean into cloud-development. In particular, we rarely, if ever, test locally, even in development. This approach puts us at odds with most deployment solutions because they assume that you test locally and only need to deploy to production or staging environments. Our cloud-centric development model means that we need our deploys to be fast and frictionless, meaning that we want to be able to deploy an entire set of cloud resources even for things like testing in feature branches.
DIDs
DIDs and DRNs are both URIs that may be mapped to another value. DRNs resolve to text, whereas DIDs are meant to resolve to documents, but since we can serialize a document as text, we could use DRNs in a similar fashion. However, the nature of the mapping—using environmental parameters to derive a name—is somewhat different, although we might imagine that things like public keys or hashed documents might be obtained from an environment. For now, the scope of DRNs is limited to deployments. In any event, DIDs seem unlikely to become the basis for identity on the Web—that analysis is beyond the scope of this document—but the idea of using URIs to encode identity may prove useful in more or less the same way they’re useful for resource names. For example, we could encode type, domain, and byname (nickname) fields in a path, like this:
din:mastodon/dyoder/mastodon/social[^naming-things-is-hard]: DRN originally stood for DashKite Resource Names, but their purpose is not necessarily constrained to DashKite technology, so we went with a more general name.
[^why-drds]: This probably comes up more than it should because the configuration for Genie Sky presets evolved before we had DRNs. Over time, we can migrate toward DRNs. [^domains]: Originally, we specified the namespace first, but this is confusing in the context of domain names. We may also switch to a single subdomain parameter here to allow for more than two subdomain components.
