import type { Selectable } from 'kysely' import * as Id from '../../internal/Id.js' import type * as Db from '../Db.js' import type * as db_Schema from '../Schema.js' /** Columns of the `sponsorship_attributions` table. */ export type Table = db_Schema.SponsorshipAttribution /** One organization-scoped sponsorship attribution. */ export type Record = Selectable /** Reads a canonical attribution within its owning organization. */ export function get(db: Db.Db, options: get.Options): Promise { return db.kysely .selectFrom('sponsorship_attributions') .selectAll() .where('id', '=', options.id) .where('orgId', '=', options.orgId) .executeTakeFirst() } export declare namespace get { /** Canonical attribution identity. */ type Options = { /** Sponsorship attribution id (`sat_…`). */ id: string /** Owning Tempo organization id. */ orgId: string } } /** Reads an existing external attribution without granting a new promotion identity. */ export function getExternal(db: Db.Db, options: getExternal.Options): Promise { return db.kysely .selectFrom('sponsorship_attributions') .selectAll() .where('externalId', '=', options.externalId) .where('orgId', '=', options.orgId) .executeTakeFirst() } export declare namespace getExternal { /** Organization-owned external attribution identity. */ type Options = { /** Partner-provided opaque attribution id. */ externalId: string /** Owning Tempo organization id. */ orgId: string } } /** Provisions an organization-scoped external attribution through trusted server code. */ export function resolveExternal(db: Db.Db, options: resolveExternal.Options): Promise { return resolve(db, { externalId: options.externalId, orgId: options.orgId, projectId: null }) } export declare namespace resolveExternal { /** External attribution identity. */ type Options = { /** Partner-provided opaque attribution id. */ externalId: string /** Owning Tempo organization id. */ orgId: string } } /** Resolves or creates an organization-scoped Tempo Project attribution. */ export function resolveProject(db: Db.Db, options: resolveProject.Options): Promise { return resolve(db, { externalId: null, orgId: options.orgId, projectId: options.projectId }) } export declare namespace resolveProject { /** Tempo Project attribution identity. */ type Options = { /** Owning Tempo organization id. */ orgId: string /** Tempo Project id (`prj_…`). */ projectId: string } } async function resolve(db: Db.Db, options: resolve.Options): Promise { const now = new Date().toISOString() const inserted = await db.kysely .insertInto('sponsorship_attributions') .values({ createdAt: now, endsAt: null, externalId: options.externalId, id: Id.generate('sat'), orgId: options.orgId, projectId: options.projectId, spendLimit: null, startsAt: null, updatedAt: now, }) .onConflict((oc) => oc.doNothing()) .returningAll() .executeTakeFirst() if (inserted) return inserted return db.kysely .selectFrom('sponsorship_attributions') .selectAll() .where('orgId', '=', options.orgId) .$if(options.externalId !== null, (query) => query.where('externalId', '=', options.externalId)) .$if(options.projectId !== null, (query) => query.where('projectId', '=', options.projectId)) .executeTakeFirstOrThrow() } declare namespace resolve { /** Exactly one source for a canonical sponsorship attribution. */ type Options = | { /** Partner-provided opaque attribution id. */ externalId: string /** Owning Tempo organization id. */ orgId: string /** No Tempo Project source. */ projectId: null } | { /** No external partner source. */ externalId: null /** Owning Tempo organization id. */ orgId: string /** Tempo Project id (`prj_…`). */ projectId: string } } /** Atomically fixes an attribution's promotion policy on first activation. */ export async function activate(db: Db.Db, options: activate.Options): Promise { await db.kysely .updateTable('sponsorship_attributions') .set({ endsAt: options.endsAt, spendLimit: options.spendLimit, startsAt: options.startsAt, updatedAt: options.startsAt, }) .where('id', '=', options.id) .where('orgId', '=', options.orgId) .where('startsAt', 'is', null) .execute() return db.kysely .selectFrom('sponsorship_attributions') .selectAll() .where('id', '=', options.id) .where('orgId', '=', options.orgId) .executeTakeFirstOrThrow() } export declare namespace activate { /** Immutable first-activation inputs. */ type Options = { /** Promotion end time. */ endsAt: string /** Sponsorship attribution id (`sat_…`). */ id: string /** Owning Tempo organization id. */ orgId: string /** Optional promotion cap in fee-token base units. */ spendLimit: string | null /** Promotion start time. */ startsAt: string } }