| 1 | /** |
| 2 | * A Railway variable-reference template (`${{Service.KEY}}` or |
| 3 | * `${{shared.NAME}}`). Pass as {@link Variable} `value` or `Service.env`. |
| 4 | * |
| 5 | * Distinct from the unexported resource-prop `Ref<T>`. Never export that |
| 6 | * `Ref`. |
| 7 | */ |
| 8 | export type VariableRef = string; |
| 9 | |
| 10 | /** |
| 11 | * Something `Railway.ref` can take a namespace from: `"shared"`, an |
| 12 | * explicit service name, or a resource's `LogicalId`. |
| 13 | */ |
| 14 | export type VariableRefSource = |
| 15 | | string |
| 16 | | { |
| 17 | readonly LogicalId: string; |
| 18 | }; |
| 19 | |
| 20 | const SHARED = "shared"; |
| 21 | |
| 22 | const namespaceOf = (resource: VariableRefSource): string => { |
| 23 | if (typeof resource === "string") { |
| 24 | const trimmed = resource.trim(); |
| 25 | return trimmed.length > 0 ? trimmed : SHARED; |
| 26 | } |
| 27 | const logical = |
| 28 | typeof resource.LogicalId === "string" ? resource.LogicalId.trim() : ""; |
| 29 | return logical.length > 0 ? logical : SHARED; |
| 30 | }; |
| 31 | |
| 32 | /** |
| 33 | * Emit a Railway variable-reference template (`${{Service.KEY}}` or |
| 34 | * `${{shared.NAME}}`). Distinct from the unexported resource-prop |
| 35 | * `Ref<T>` — never export that `Ref`. |
| 36 | * |
| 37 | * `Railway.ref(Db, "DATABASE_URL")` returns `${{LogicalName.DATABASE_URL}}` |
| 38 | * where `LogicalName` is `resource.LogicalId` (`Postgres("Db")` → `Db`). |
| 39 | * Shared variables use the `"shared"` namespace: |
| 40 | * `Railway.ref("shared", "SENTRY_DSN")` returns `${{shared.SENTRY_DSN}}`. |
| 41 | * |
| 42 | * Store the string as a {@link Variable} `value` (or on `Service.env`). |
| 43 | * Railway keeps the template (`unrendered: true`) and interpolates it at |
| 44 | * build/runtime — it is not a resolved URI. Use {@link ConnectPostgres} |
| 45 | * when you want a typed client inside an Effect-native Service. |
| 46 | * |
| 47 | * Railway interpolates by service name. Set `name` on Postgres/Service to |
| 48 | * the LogicalId if you need the template to resolve to that service. |
| 49 | * |
| 50 | * @see https://docs.railway.com/variables/reference#template-syntax |
| 51 | * @see https://docs.railway.com/infrastructure-as-code/reference |
| 52 | * |
| 53 | * ### Reference a service variable |
| 54 | * Pass a resource (or its LogicalId) and the variable key. The result is |
| 55 | * a template string, not a URI. |
| 56 | * |
| 57 | * **Example:** Reference Postgres DATABASE_URL |
| 58 | * ```typescript |
| 59 | * const db = yield* Railway.Postgres("Db", { project: site }); |
| 60 | * yield* Railway.Variable("DatabaseUrl", { |
| 61 | * project: site, |
| 62 | * service: api, |
| 63 | * name: "DATABASE_URL", |
| 64 | * value: Railway.ref(db, "DATABASE_URL"), |
| 65 | * }); |
| 66 | * ``` |
| 67 | * |
| 68 | * ### Shared variables |
| 69 | * `"shared"` is the environment-wide namespace (IaC `ctx.shared.NAME`). |
| 70 | * |
| 71 | * **Example:** Shared variable |
| 72 | * ```typescript |
| 73 | * env: { |
| 74 | * SENTRY_DSN: Railway.ref("shared", "SENTRY_DSN"), |
| 75 | * } |
| 76 | * ``` |
| 77 | * |
| 78 | * @resource |
| 79 | * @product Project |
| 80 | */ |
| 81 | export const ref = (resource: VariableRefSource, key: string): VariableRef => |
| 82 | `\${{${namespaceOf(resource)}.${key}}}`; |