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
}
}