import { r as __exportAll } from "./chunk-BSw8zbkd.mjs";
import { t as require_main } from "./main-BY-64ifo.mjs";
import { n as createResolvers } from "./resolvers-DMenezt1.mjs";
import { n as OpenBaoTransitClient, t as createSecretsService } from "./secrets-service-TFqI9ubU.mjs";
import { BaseSubgraph } from "@powerhousedao/reactor-api";
const schema = require_main().gql`
  """
  A user's current early-access status, derived from their most recent
  non-expired redemption.
  """
  type AccessStatus {
    allowed: Boolean!
    code: String
    label: String
    accessExpires: String
    "Whether the caller has an active redemption whose code carries a Claude key. The key value itself is never returned."
    hasAttachedKey: Boolean!
  }

  """
  An invite code and its redemption count (admin view).
  """
  type InviteCode {
    code: String!
    label: String
    active: Boolean!
    expiresAt: String
    maxUses: Int
    createdAt: String!
    redemptions: Int!
    "Whether a Claude API key is attached to this code. The key value itself is never returned."
    hasAnthropicKey: Boolean!
  }

  """
  Result of applying a code's attached secret to a tenant's secret store.
  """
  type ApplyInviteCodeSecretResult {
    "True when a key was found for the caller and written to the tenant."
    injected: Boolean!
    "The secret names that were written (empty when nothing was injected)."
    secretNames: [String!]!
  }

  """
  A single redemption: which wallet (DID) redeemed which code, and when.
  """
  type Redemption {
    code: String!
    userDid: String!
    redeemedAt: String!
    accessExpires: String
  }

  type VetraAccessCodesQueries {
    "Whether a code is currently usable. Public; never consumes the code."
    inviteCodeValid(code: String!): Boolean!
    "Access status for the authenticated caller (DID taken from the token)."
    myAccessStatus: AccessStatus!
    "All codes with redemption counts. Admin only."
    inviteCodes: [InviteCode!]!
    "Redemptions (which wallet used which code), newest first. Filter by code and/or wallet address, or omit for all. Admin only."
    redemptions(code: String, address: String): [Redemption!]!
  }

  type VetraAccessCodesMutations {
    "Redeem a code for the authenticated caller. Idempotent."
    redeemInviteCode(code: String!): AccessStatus!
    """
    Write the caller's attached Claude key into a tenant's secret store under
    each of secretNames. The key is resolved server-side from the caller's
    redeemed code and never leaves the reactor. Returns injected=false when the
    caller has no active redemption carrying a key. Authenticated caller only.
    """
    applyInviteCodeSecret(
      tenantId: String!
      secretNames: [String!]!
    ): ApplyInviteCodeSecretResult!
    "Create a code, optionally attaching a Claude API key. Admin only."
    createInviteCode(
      code: String!
      label: String
      expiresAt: String
      maxUses: Int
      anthropicApiKey: String
    ): InviteCode!
    "Enable/disable a code. Admin only."
    setInviteCodeActive(code: String!, active: Boolean!): InviteCode!
    "Attach or rotate (value) / detach (null) a code's Claude API key. Admin only."
    setInviteCodeAnthropicKey(code: String!, anthropicApiKey: String): InviteCode!
    "Revoke a wallet's current access by expiring its redemptions. Returns how many grants were revoked. Admin only."
    revokeAccess(address: String!): Int!
  }

  type Query {
    VetraAccessCodes: VetraAccessCodesQueries!
  }

  type Mutation {
    VetraAccessCodes: VetraAccessCodesMutations!
  }
`;
//#endregion
//#region subgraphs/vetra-access-codes/db/migrations.ts
/** Postgres SQLSTATE for "column already exists". */
const DUPLICATE_COLUMN = "42701";
async function up(db) {
	await db.schema.createTable("invite_codes").addColumn("code", "varchar(255)", (col) => col.notNull()).addColumn("label", "varchar(255)").addColumn("active", "boolean", (col) => col.notNull().defaultTo(true)).addColumn("expires_at", "varchar(255)").addColumn("max_uses", "integer").addColumn("created_at", "varchar(255)", (col) => col.notNull()).addPrimaryKeyConstraint("invite_codes_pkey", ["code"]).ifNotExists().execute();
	try {
		await db.schema.alterTable("invite_codes").addColumn("anthropic_key_ciphertext", "text").execute();
	} catch (error) {
		if (error?.code !== DUPLICATE_COLUMN) throw error;
	}
	await db.schema.createTable("invite_redemptions").addColumn("code", "varchar(255)", (col) => col.notNull()).addColumn("user_did", "varchar(255)", (col) => col.notNull()).addColumn("redeemed_at", "varchar(255)", (col) => col.notNull()).addColumn("access_expires", "varchar(255)").addPrimaryKeyConstraint("invite_redemptions_pkey", ["code", "user_did"]).ifNotExists().execute();
	await db.schema.createIndex("invite_redemptions_user_did_idx").on("invite_redemptions").column("user_did").ifNotExists().execute();
}
//#endregion
//#region subgraphs/vetra-access-codes/index.ts
var vetra_access_codes_exports = /* @__PURE__ */ __exportAll({ VetraAccessCodesSubgraph: () => VetraAccessCodesSubgraph });
const DEFAULT_TRANSIT_ROLE = "vetra-secrets";
/**
* Early-access invite codes for vetra.to. Owns its own relational tables in
* an isolated namespace; the management mutations are gated behind the
* gateway's admin allowlist (see resolvers). No document model is involved.
*
* Codes may carry an attached Claude API key. The key is encrypted at rest via
* OpenBao transit and, on studio provisioning, written into the tenant secret
* store server-side — reusing the `vetra-cloud-secrets` service in-process so
* the key never leaves the reactor.
*/
var VetraAccessCodesSubgraph = class extends BaseSubgraph {
	name = "vetra-access-codes";
	typeDefs = schema;
	resolvers = {};
	additionalContextFields = {};
	async onSetup() {
		const db = await this.relationalDb.createNamespace("vetra-access-codes");
		await up(db);
		const openbaoAddr = process.env.OPENBAO_ADDR;
		if (!openbaoAddr) throw new Error("[access-codes] OPENBAO_ADDR is required — attached Claude keys cannot be encrypted without transit engine access");
		const transit = new OpenBaoTransitClient({
			addr: openbaoAddr,
			role: process.env.OPENBAO_TRANSIT_ROLE ?? DEFAULT_TRANSIT_ROLE,
			keyNamePrefix: process.env.OPENBAO_TRANSIT_KEY_PREFIX
		});
		this.resolvers = createResolvers(db, {
			transit,
			secretsService: createSecretsService({
				db: await this.relationalDb.createNamespace("vetra-cloud-secrets"),
				transit
			})
		});
	}
};
//#endregion
export { vetra_access_codes_exports as n, VetraAccessCodesSubgraph as t };

//# sourceMappingURL=vetra-access-codes-BPrL-LyS.mjs.map