import * as Effect from "effect/Effect";
import * as Binding from "../../Binding.ts";
import { isBindingHost } from "../Lambda/Function.ts";
import { Region } from "../Region.ts";
import type { PublicRepository } from "./Repository.ts";
/**
* Shared HTTP scaffolding for the Amazon ECR Public runtime bindings.
*
* NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
* thin `Layer.effect(Cap, make…HttpBinding({ … }))` over one of the builders
* below. Everything except the operation, the IAM action list, and (for the
* repository-scoped builder) the injected repository name is boilerplate.
*
* Amazon ECR Public is a single global registry served exclusively from the
* `us-east-1` endpoint, so every operation is resolved with the Region
* pinned via {@link pinEcrPublic} — exactly like the resource provider in
* `Repository.ts`.
*
* Per the `ecr-public` service authorization reference, repository-scoped
* actions authorize on the repository ARN, while registry-level actions
* (`GetAuthorizationToken`, `DescribeRegistries`, `GetRegistryCatalogData`)
* support no repository resource type, so the registry builder grants on
* `Resource: ["*"]`.
*/
const US_EAST_1 = "us-east-1";
/** Pin a distilled `ecr-public` effect to the service's home region. */
export const pinEcrPublic = (effect: Effect.Effect) =>
effect.pipe(Effect.provideService(Region, Effect.succeed(US_EAST_1)));
/**
* Build the impl Effect for an operation scoped to one
* {@link PublicRepository}. The runtime callable injects the bound
* repository's name as the request's `repositoryName`; the deploy-time half
* grants `iamActions` on the repository's ARN.
*/
export const makePublicRepositoryHttpBinding = <
I extends { repositoryName: string },
A,
E,
R,
>(options: {
/**
* Short capability name used in the binding sid and runtime span, e.g.
* `"DescribeImages"`.
*/
capability: string;
/** IAM actions granted on the repository ARN. */
iamActions: readonly string[];
/** The distilled operation; `repositoryName` is injected. */
operation: Effect.Effect<(input: I) => Effect.Effect, never, R>;
}) =>
Effect.gen(function* () {
const op = yield* pinEcrPublic(options.operation);
return Effect.fn(function* (repository: PublicRepository) {
const RepositoryName = yield* repository.repositoryName;
if (!globalThis.__ALCHEMY_RUNTIME__) {
const host = yield* Binding.Host;
if (isBindingHost(host)) {
yield* host.bind`Allow(${host}, AWS.ECRPublic.${options.capability}(${repository}))`(
{
policyStatements: [
{
Effect: "Allow",
Action: [...options.iamActions],
Resource: [repository.repositoryArn],
},
],
},
);
}
}
return Effect.fn(
`AWS.ECRPublic.${options.capability}(${repository.LogicalId})`,
)(function* (request?: Omit) {
// The region must also be pinned at the call site: the yield-time
// snapshot is only a fallback — the calling fiber's ambient Region
// (the host Function's own region) wins over it.
return yield* pinEcrPublic(
op({
...request,
repositoryName: yield* RepositoryName,
} as unknown as I),
);
});
});
});
/**
* Build the impl Effect for a registry-level ECR Public operation
* (`GetAuthorizationToken`, `DescribeRegistries`, `GetRegistryCatalogData` —
* none of which are repository-scoped, so the grant is on
* `Resource: ["*"]`).
*/
export const makePublicRegistryHttpBinding = <
I extends object,
A,
E,
R,
>(options: {
/**
* Short capability name used in the binding sid and runtime span, e.g.
* `"GetAuthorizationToken"`.
*/
capability: string;
/** IAM actions granted on `Resource: ["*"]`. */
iamActions: readonly string[];
/** The distilled operation implementing the capability. */
operation: Effect.Effect<(input: I) => Effect.Effect, never, R>;
}) =>
Effect.gen(function* () {
const op = yield* pinEcrPublic(options.operation);
return Effect.fn(function* () {
if (!globalThis.__ALCHEMY_RUNTIME__) {
const host = yield* Binding.Host;
if (isBindingHost(host)) {
yield* host.bind`Allow(${host}, AWS.ECRPublic.${options.capability}())`(
{
policyStatements: [
{
Effect: "Allow",
Action: [...options.iamActions],
Resource: ["*"],
},
],
},
);
}
}
return Effect.fn(`AWS.ECRPublic.${options.capability}`)(function* (
request?: I,
) {
// Call-site region pin — see makePublicRepositoryHttpBinding above.
return yield* pinEcrPublic(op((request ?? {}) as I));
});
});
});