openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
116 lines (115 loc) • 5.44 kB
JavaScript
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { r as captureOpenClawStateWorkerContext } from "./openclaw-state-worker-context-BvvgY6-t.mjs";
import { o as parseRegistryNpmSpec } from "./npm-registry-spec-B_IER0ZB.mjs";
import { n as executeOpenClawStateWorker, o as runOpenClawStateWorkerOperation } from "./openclaw-state-worker-store-BxZXTKna.mjs";
import { c as readClawHubBooleanField, d as readClawHubStringArrayField, f as readClawHubStringField, g as readRequiredClawHubStringField, i as fetchClawHubJson, m as readRequiredClawHubNumberField, p as readRequiredClawHubBooleanField, u as readClawHubNonEmptyStringFields } from "./clawhub-client-3QLl6MrZ.mjs";
//#region src/infra/clawhub-promotions.ts
const CLAWHUB_PROMOTION_MODEL_REF_RE = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
function parseClawHubPromotionModel(value, context) {
if (!isRecord(value)) throw new Error(`Malformed ClawHub ${context}: expected each model to be an object.`);
const modelRef = readRequiredClawHubStringField(value, "modelRef", context);
if (!CLAWHUB_PROMOTION_MODEL_REF_RE.test(modelRef)) throw new Error(`Malformed ClawHub ${context}: modelRef contains unsupported characters.`);
const model = {
modelRef,
...readClawHubNonEmptyStringFields(value, ["alias"], context)
};
const suggestedDefault = readClawHubBooleanField(value, "suggestedDefault", context);
if (suggestedDefault !== void 0) model.suggestedDefault = suggestedDefault;
return model;
}
const CLAWHUB_PROMOTION_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
const CLAWHUB_PROMOTION_IDENTIFIER_RE = /^[A-Za-z0-9][A-Za-z0-9._@/-]*$/;
function parseClawHubPromotion(value) {
const context = "promotion";
if (!isRecord(value)) throw new Error(`Malformed ClawHub ${context}: expected an object.`);
const modelsRaw = value.models;
if (!Array.isArray(modelsRaw) || modelsRaw.length === 0) throw new Error(`Malformed ClawHub ${context}: expected models to be a non-empty array.`);
const slug = readRequiredClawHubStringField(value, "slug", context);
if (!CLAWHUB_PROMOTION_SLUG_RE.test(slug)) throw new Error(`Malformed ClawHub ${context}: slug must be lowercase [a-z0-9-].`);
const startsAt = readRequiredClawHubNumberField(value, "startsAt", context);
const endsAt = readRequiredClawHubNumberField(value, "endsAt", context);
if (endsAt <= startsAt) throw new Error(`Malformed ClawHub ${context}: promotion window must end after it starts.`);
const promotion = {
slug,
title: readRequiredClawHubStringField(value, "title", context),
blurb: readRequiredClawHubStringField(value, "blurb", context),
startsAt,
endsAt,
models: modelsRaw.map((entry) => parseClawHubPromotionModel(entry, context)),
...readClawHubNonEmptyStringFields(value, [
"sponsor",
"signupUrl",
"docsUrl",
"launchPageUrl"
], context)
};
for (const field of ["provider", "authChoiceId"]) {
const parsed = readClawHubStringField(value, field, context);
if (!parsed) continue;
if (!CLAWHUB_PROMOTION_IDENTIFIER_RE.test(parsed)) throw new Error(`Malformed ClawHub ${context}: ${field} contains unsupported characters.`);
promotion[field] = parsed;
}
const pluginNames = readClawHubStringArrayField(value, "pluginNames", context);
if (pluginNames && pluginNames.length > 0) {
for (const name of pluginNames) {
const parsed = parseRegistryNpmSpec(name);
if (!parsed || parsed.selectorKind !== "none" || parsed.name !== name) throw new Error(`Malformed ClawHub ${context}: pluginNames must contain npm package names.`);
}
promotion.pluginNames = pluginNames;
}
return {
...promotion,
status: readRequiredClawHubStringField(value, "status", context),
active: readRequiredClawHubBooleanField(value, "active", context)
};
}
async function fetchClawHubPromotions(params = {}) {
const response = await fetchClawHubJson({
...params,
path: "/api/v1/promotions"
});
if (!isRecord(response) || !Array.isArray(response.promotions)) throw new Error("Malformed ClawHub promotions response: expected a promotions array.");
return response.promotions.map((entry) => parseClawHubPromotion(entry));
}
async function fetchClawHubPromotion(params) {
return parseClawHubPromotion(await fetchClawHubJson({
...params,
path: `/api/v1/promotions/${encodeURIComponent(params.slug)}`
}));
}
//#endregion
//#region src/infra/promotions-feed.ts
/** Retains explicit promotion notice and claim provenance. */
async function markPromotionSlugsNotified(slugs) {
try {
const input = {
slugs: [...slugs],
now: Date.now()
};
if (input.slugs.length === 0) return;
const context = captureOpenClawStateWorkerContext();
const command = {
type: "promotions.markNotified",
input
};
if (await runOpenClawStateWorkerOperation(context, (scope) => scope.execute(command), { existingOnly: true }) === void 0) await executeOpenClawStateWorker(context, command);
} catch {}
}
async function recordPromotionClaim(record) {
try {
const input = {
slug: record.slug,
provider: record.provider ?? null,
modelKeysJson: JSON.stringify(record.modelKeys),
endsAtMs: record.endsAtMs,
claimedAtMs: record.claimedAtMs
};
const context = captureOpenClawStateWorkerContext();
await executeOpenClawStateWorker(context, {
type: "promotions.recordClaim",
input
});
} catch {}
}
//#endregion
export { fetchClawHubPromotions as i, recordPromotionClaim as n, fetchClawHubPromotion as r, markPromotionSlugsNotified as t };