@xapps-platform/xapp-manifest 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/index.d.ts +387 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +345 -0
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8086,6 +8086,168 @@ var xappManifestJsonSchema = {
|
|
|
8086
8086
|
proxy_policy: { type: "object" }
|
|
8087
8087
|
}
|
|
8088
8088
|
},
|
|
8089
|
+
monetization: {
|
|
8090
|
+
type: "object",
|
|
8091
|
+
additionalProperties: false,
|
|
8092
|
+
properties: {
|
|
8093
|
+
products: {
|
|
8094
|
+
type: "array",
|
|
8095
|
+
maxItems: 200,
|
|
8096
|
+
items: {
|
|
8097
|
+
type: "object",
|
|
8098
|
+
required: ["slug", "product_family"],
|
|
8099
|
+
additionalProperties: false,
|
|
8100
|
+
properties: {
|
|
8101
|
+
slug: { type: "string", minLength: 1, maxLength: 100 },
|
|
8102
|
+
title: localizedTextSchema(200),
|
|
8103
|
+
description: localizedTextSchema(2e3),
|
|
8104
|
+
product_family: { type: "string", minLength: 1, maxLength: 100 },
|
|
8105
|
+
status: { type: "string", enum: ["draft", "active", "archived"] },
|
|
8106
|
+
metadata: { type: "object" }
|
|
8107
|
+
}
|
|
8108
|
+
}
|
|
8109
|
+
},
|
|
8110
|
+
offerings: {
|
|
8111
|
+
type: "array",
|
|
8112
|
+
maxItems: 200,
|
|
8113
|
+
items: {
|
|
8114
|
+
type: "object",
|
|
8115
|
+
required: ["slug"],
|
|
8116
|
+
additionalProperties: false,
|
|
8117
|
+
properties: {
|
|
8118
|
+
slug: { type: "string", minLength: 1, maxLength: 100 },
|
|
8119
|
+
title: localizedTextSchema(200),
|
|
8120
|
+
description: localizedTextSchema(2e3),
|
|
8121
|
+
placement: { type: "string", minLength: 1, maxLength: 100 },
|
|
8122
|
+
status: { type: "string", enum: ["draft", "active", "archived"] },
|
|
8123
|
+
targeting_rules: { type: "object" },
|
|
8124
|
+
metadata: { type: "object" }
|
|
8125
|
+
}
|
|
8126
|
+
}
|
|
8127
|
+
},
|
|
8128
|
+
packages: {
|
|
8129
|
+
type: "array",
|
|
8130
|
+
maxItems: 500,
|
|
8131
|
+
items: {
|
|
8132
|
+
type: "object",
|
|
8133
|
+
required: ["slug", "product_ref", "offering_ref"],
|
|
8134
|
+
additionalProperties: false,
|
|
8135
|
+
properties: {
|
|
8136
|
+
slug: { type: "string", minLength: 1, maxLength: 100 },
|
|
8137
|
+
product_ref: { type: "string", minLength: 1, maxLength: 100 },
|
|
8138
|
+
offering_ref: { type: "string", minLength: 1, maxLength: 100 },
|
|
8139
|
+
package_kind: {
|
|
8140
|
+
type: "string",
|
|
8141
|
+
enum: ["standard", "one_time_unlock", "credit_pack", "subscription"]
|
|
8142
|
+
},
|
|
8143
|
+
display_order: { type: "integer", minimum: 0, maximum: 1e6 },
|
|
8144
|
+
status: { type: "string", enum: ["draft", "active", "archived"] },
|
|
8145
|
+
metadata: { type: "object" }
|
|
8146
|
+
}
|
|
8147
|
+
}
|
|
8148
|
+
},
|
|
8149
|
+
prices: {
|
|
8150
|
+
type: "array",
|
|
8151
|
+
maxItems: 1e3,
|
|
8152
|
+
items: {
|
|
8153
|
+
type: "object",
|
|
8154
|
+
required: ["slug", "package_ref", "currency", "amount"],
|
|
8155
|
+
additionalProperties: false,
|
|
8156
|
+
properties: {
|
|
8157
|
+
slug: { type: "string", minLength: 1, maxLength: 100 },
|
|
8158
|
+
package_ref: { type: "string", minLength: 1, maxLength: 100 },
|
|
8159
|
+
currency: { type: "string", minLength: 1, maxLength: 16 },
|
|
8160
|
+
amount: { type: "number", minimum: 0 },
|
|
8161
|
+
billing_period: { type: "string", enum: ["day", "week", "month", "year"] },
|
|
8162
|
+
billing_period_count: { type: "integer", minimum: 1, maximum: 1e6 },
|
|
8163
|
+
trial_policy: { type: "object" },
|
|
8164
|
+
intro_policy: { type: "object" },
|
|
8165
|
+
country_rules: { type: "object" },
|
|
8166
|
+
status: { type: "string", enum: ["draft", "active", "archived"] },
|
|
8167
|
+
metadata: { type: "object" }
|
|
8168
|
+
}
|
|
8169
|
+
}
|
|
8170
|
+
},
|
|
8171
|
+
paywalls: {
|
|
8172
|
+
type: "array",
|
|
8173
|
+
maxItems: 200,
|
|
8174
|
+
items: {
|
|
8175
|
+
type: "object",
|
|
8176
|
+
required: ["slug", "offering_refs"],
|
|
8177
|
+
additionalProperties: false,
|
|
8178
|
+
properties: {
|
|
8179
|
+
slug: { type: "string", minLength: 1, maxLength: 100 },
|
|
8180
|
+
title: localizedTextSchema(200),
|
|
8181
|
+
description: localizedTextSchema(2e3),
|
|
8182
|
+
placement: { type: "string", minLength: 1, maxLength: 100 },
|
|
8183
|
+
offering_refs: {
|
|
8184
|
+
type: "array",
|
|
8185
|
+
minItems: 1,
|
|
8186
|
+
maxItems: 50,
|
|
8187
|
+
items: { type: "string", minLength: 1, maxLength: 100 }
|
|
8188
|
+
},
|
|
8189
|
+
package_refs: {
|
|
8190
|
+
type: "array",
|
|
8191
|
+
minItems: 1,
|
|
8192
|
+
maxItems: 200,
|
|
8193
|
+
items: { type: "string", minLength: 1, maxLength: 100 }
|
|
8194
|
+
},
|
|
8195
|
+
default_package_ref: { type: "string", minLength: 1, maxLength: 100 },
|
|
8196
|
+
status: { type: "string", enum: ["draft", "active", "archived"] },
|
|
8197
|
+
targeting_rules: { type: "object" },
|
|
8198
|
+
metadata: { type: "object" }
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
},
|
|
8202
|
+
usage_policies: {
|
|
8203
|
+
type: "array",
|
|
8204
|
+
maxItems: 200,
|
|
8205
|
+
items: {
|
|
8206
|
+
type: "object",
|
|
8207
|
+
required: ["tool_name", "credit_cost"],
|
|
8208
|
+
additionalProperties: false,
|
|
8209
|
+
properties: {
|
|
8210
|
+
tool_name: { type: "string", minLength: 1, maxLength: 100 },
|
|
8211
|
+
unit: { type: "string", minLength: 1, maxLength: 100 },
|
|
8212
|
+
credit_cost: { type: "number", minimum: 0 },
|
|
8213
|
+
status: { type: "string", enum: ["draft", "active", "archived"] },
|
|
8214
|
+
metadata: { type: "object" }
|
|
8215
|
+
}
|
|
8216
|
+
}
|
|
8217
|
+
},
|
|
8218
|
+
hooks: {
|
|
8219
|
+
type: "object",
|
|
8220
|
+
additionalProperties: false,
|
|
8221
|
+
properties: {
|
|
8222
|
+
after_payment_completed: {
|
|
8223
|
+
type: "object",
|
|
8224
|
+
additionalProperties: true,
|
|
8225
|
+
properties: {
|
|
8226
|
+
enabled: { type: "boolean" },
|
|
8227
|
+
guard_slug: { type: "string", minLength: 1, maxLength: 200 },
|
|
8228
|
+
guardSlug: { type: "string", minLength: 1, maxLength: 200 },
|
|
8229
|
+
invoice_ref: { type: "string", minLength: 1, maxLength: 200 },
|
|
8230
|
+
invoiceRef: { type: "string", minLength: 1, maxLength: 200 },
|
|
8231
|
+
by_payment_guard_ref: {
|
|
8232
|
+
type: "object",
|
|
8233
|
+
additionalProperties: {
|
|
8234
|
+
type: "object",
|
|
8235
|
+
additionalProperties: true
|
|
8236
|
+
}
|
|
8237
|
+
},
|
|
8238
|
+
byPaymentGuardRef: {
|
|
8239
|
+
type: "object",
|
|
8240
|
+
additionalProperties: {
|
|
8241
|
+
type: "object",
|
|
8242
|
+
additionalProperties: true
|
|
8243
|
+
}
|
|
8244
|
+
}
|
|
8245
|
+
}
|
|
8246
|
+
}
|
|
8247
|
+
}
|
|
8248
|
+
}
|
|
8249
|
+
}
|
|
8250
|
+
},
|
|
8089
8251
|
payment_guard_definitions: {
|
|
8090
8252
|
type: "array",
|
|
8091
8253
|
maxItems: 50,
|
|
@@ -8317,6 +8479,23 @@ var validate = ajv.compile(xappManifestJsonSchema);
|
|
|
8317
8479
|
function isRecord(value) {
|
|
8318
8480
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8319
8481
|
}
|
|
8482
|
+
function readMonetizationEntries(value) {
|
|
8483
|
+
return Array.isArray(value) ? value : [];
|
|
8484
|
+
}
|
|
8485
|
+
function requireUniqueSlug(entries, label) {
|
|
8486
|
+
const slugs = /* @__PURE__ */ new Set();
|
|
8487
|
+
for (const entry of entries) {
|
|
8488
|
+
const slug = String(entry?.slug ?? "").trim();
|
|
8489
|
+
if (!slug) {
|
|
8490
|
+
throw Object.assign(new Error(`${label} entries require non-empty slug`), { status: 400 });
|
|
8491
|
+
}
|
|
8492
|
+
if (slugs.has(slug)) {
|
|
8493
|
+
throw Object.assign(new Error(`Duplicate ${label} slug: ${slug}`), { status: 400 });
|
|
8494
|
+
}
|
|
8495
|
+
slugs.add(slug);
|
|
8496
|
+
}
|
|
8497
|
+
return slugs;
|
|
8498
|
+
}
|
|
8320
8499
|
function isTemplatedUrl(value) {
|
|
8321
8500
|
return /^__[A-Z0-9_]+__(?:[/?#].*)?$/.test(String(value || "").trim());
|
|
8322
8501
|
}
|
|
@@ -8733,6 +8912,13 @@ function parseXappManifest(input, options) {
|
|
|
8733
8912
|
});
|
|
8734
8913
|
}
|
|
8735
8914
|
const manifest = input;
|
|
8915
|
+
const monetization = isRecord(manifest.monetization) ? manifest.monetization : null;
|
|
8916
|
+
const monetizationProducts = readMonetizationEntries(monetization?.products);
|
|
8917
|
+
const monetizationOfferings = readMonetizationEntries(monetization?.offerings);
|
|
8918
|
+
const monetizationPackages = readMonetizationEntries(monetization?.packages);
|
|
8919
|
+
const monetizationPrices = readMonetizationEntries(monetization?.prices);
|
|
8920
|
+
const monetizationPaywalls = readMonetizationEntries(monetization?.paywalls);
|
|
8921
|
+
const monetizationUsagePolicies = Array.isArray(monetization?.usage_policies) ? monetization.usage_policies : [];
|
|
8736
8922
|
const paymentDefinitions = Array.isArray(manifest.payment_guard_definitions) ? manifest.payment_guard_definitions : [];
|
|
8737
8923
|
const subjectProfileDefinitions = Array.isArray(manifest.subject_profile_guard_definitions) ? manifest.subject_profile_guard_definitions : [];
|
|
8738
8924
|
const notificationDefinitions = Array.isArray(manifest.notification_definitions) ? manifest.notification_definitions : [];
|
|
@@ -8745,6 +8931,14 @@ function parseXappManifest(input, options) {
|
|
|
8745
8931
|
const notificationTemplateNames = /* @__PURE__ */ new Set();
|
|
8746
8932
|
const invoiceDefinitionNames = /* @__PURE__ */ new Set();
|
|
8747
8933
|
const invoiceTemplateNames = /* @__PURE__ */ new Set();
|
|
8934
|
+
const monetizationProductSlugs = requireUniqueSlug(monetizationProducts, "monetization.products");
|
|
8935
|
+
const monetizationOfferingSlugs = requireUniqueSlug(
|
|
8936
|
+
monetizationOfferings,
|
|
8937
|
+
"monetization.offerings"
|
|
8938
|
+
);
|
|
8939
|
+
const monetizationPackageSlugs = requireUniqueSlug(monetizationPackages, "monetization.packages");
|
|
8940
|
+
requireUniqueSlug(monetizationPrices, "monetization.prices");
|
|
8941
|
+
requireUniqueSlug(monetizationPaywalls, "monetization.paywalls");
|
|
8748
8942
|
for (const list of [
|
|
8749
8943
|
[paymentDefinitions, paymentDefinitionNames, "payment_guard_definitions"],
|
|
8750
8944
|
[subjectProfileDefinitions, subjectProfileDefinitionNames, "subject_profile_guard_definitions"],
|
|
@@ -8789,6 +8983,30 @@ function parseXappManifest(input, options) {
|
|
|
8789
8983
|
const knownToolNames = new Set(
|
|
8790
8984
|
(manifest.tools ?? []).map((tool) => String(tool.tool_name || "").trim())
|
|
8791
8985
|
);
|
|
8986
|
+
const monetizationUsagePolicyTools = /* @__PURE__ */ new Set();
|
|
8987
|
+
for (const usagePolicy of monetizationUsagePolicies) {
|
|
8988
|
+
const toolName = String(usagePolicy?.tool_name ?? "").trim();
|
|
8989
|
+
const creditCost = Number(usagePolicy?.credit_cost);
|
|
8990
|
+
if (!knownToolNames.has(toolName)) {
|
|
8991
|
+
throw Object.assign(
|
|
8992
|
+
new Error(`monetization.usage_policies entry references unknown tool_name: ${toolName}`),
|
|
8993
|
+
{ status: 400 }
|
|
8994
|
+
);
|
|
8995
|
+
}
|
|
8996
|
+
if (!Number.isFinite(creditCost)) {
|
|
8997
|
+
throw Object.assign(
|
|
8998
|
+
new Error(`monetization.usage_policies entry requires numeric credit_cost: ${toolName}`),
|
|
8999
|
+
{ status: 400 }
|
|
9000
|
+
);
|
|
9001
|
+
}
|
|
9002
|
+
if (monetizationUsagePolicyTools.has(toolName)) {
|
|
9003
|
+
throw Object.assign(
|
|
9004
|
+
new Error(`monetization.usage_policies has duplicate tool_name: ${toolName}`),
|
|
9005
|
+
{ status: 400 }
|
|
9006
|
+
);
|
|
9007
|
+
}
|
|
9008
|
+
monetizationUsagePolicyTools.add(toolName);
|
|
9009
|
+
}
|
|
8792
9010
|
const referencedPaymentDefinitionNames = /* @__PURE__ */ new Set();
|
|
8793
9011
|
const referencedSubjectProfileDefinitionNames = /* @__PURE__ */ new Set();
|
|
8794
9012
|
const notificationDefinitionRegistry = buildNotificationDefinitionRegistry(
|
|
@@ -8839,6 +9057,133 @@ function parseXappManifest(input, options) {
|
|
|
8839
9057
|
validateWidgetPublisherRuntimeMode(widget);
|
|
8840
9058
|
validateWidgetPublisherBootstrapTransport(widget);
|
|
8841
9059
|
}
|
|
9060
|
+
for (const monetizationPackage of monetizationPackages) {
|
|
9061
|
+
const productRef = String(monetizationPackage.product_ref ?? "").trim();
|
|
9062
|
+
if (!monetizationProductSlugs.has(productRef)) {
|
|
9063
|
+
throw Object.assign(
|
|
9064
|
+
new Error(
|
|
9065
|
+
`monetization.packages entry ${String(monetizationPackage.slug ?? "unknown")} references unknown product_ref: ${productRef}`
|
|
9066
|
+
),
|
|
9067
|
+
{ status: 400 }
|
|
9068
|
+
);
|
|
9069
|
+
}
|
|
9070
|
+
const offeringRef = String(monetizationPackage.offering_ref ?? "").trim();
|
|
9071
|
+
if (!monetizationOfferingSlugs.has(offeringRef)) {
|
|
9072
|
+
throw Object.assign(
|
|
9073
|
+
new Error(
|
|
9074
|
+
`monetization.packages entry ${String(monetizationPackage.slug ?? "unknown")} references unknown offering_ref: ${offeringRef}`
|
|
9075
|
+
),
|
|
9076
|
+
{ status: 400 }
|
|
9077
|
+
);
|
|
9078
|
+
}
|
|
9079
|
+
}
|
|
9080
|
+
for (const monetizationPrice of monetizationPrices) {
|
|
9081
|
+
const packageRef = String(monetizationPrice.package_ref ?? "").trim();
|
|
9082
|
+
if (!monetizationPackageSlugs.has(packageRef)) {
|
|
9083
|
+
throw Object.assign(
|
|
9084
|
+
new Error(
|
|
9085
|
+
`monetization.prices entry ${String(monetizationPrice.slug ?? "unknown")} references unknown package_ref: ${packageRef}`
|
|
9086
|
+
),
|
|
9087
|
+
{ status: 400 }
|
|
9088
|
+
);
|
|
9089
|
+
}
|
|
9090
|
+
}
|
|
9091
|
+
const packageOfferingBySlug = /* @__PURE__ */ new Map();
|
|
9092
|
+
for (const monetizationPackage of monetizationPackages) {
|
|
9093
|
+
const packageSlug = String(monetizationPackage.slug ?? "").trim();
|
|
9094
|
+
const offeringRef = String(monetizationPackage.offering_ref ?? "").trim();
|
|
9095
|
+
if (packageSlug && offeringRef) {
|
|
9096
|
+
packageOfferingBySlug.set(packageSlug, offeringRef);
|
|
9097
|
+
}
|
|
9098
|
+
}
|
|
9099
|
+
for (const monetizationPaywall of monetizationPaywalls) {
|
|
9100
|
+
const paywallSlug = String(monetizationPaywall.slug ?? "unknown").trim() || "unknown";
|
|
9101
|
+
const offeringRefs = Array.isArray(monetizationPaywall.offering_refs) ? monetizationPaywall.offering_refs.map((value) => String(value ?? "").trim()).filter(Boolean) : [];
|
|
9102
|
+
if (!offeringRefs.length) {
|
|
9103
|
+
throw Object.assign(
|
|
9104
|
+
new Error(`monetization.paywalls entry ${paywallSlug} requires at least one offering_ref`),
|
|
9105
|
+
{ status: 400 }
|
|
9106
|
+
);
|
|
9107
|
+
}
|
|
9108
|
+
const offeringRefSet = /* @__PURE__ */ new Set();
|
|
9109
|
+
for (const offeringRef of offeringRefs) {
|
|
9110
|
+
if (!monetizationOfferingSlugs.has(offeringRef)) {
|
|
9111
|
+
throw Object.assign(
|
|
9112
|
+
new Error(
|
|
9113
|
+
`monetization.paywalls entry ${paywallSlug} references unknown offering_ref: ${offeringRef}`
|
|
9114
|
+
),
|
|
9115
|
+
{ status: 400 }
|
|
9116
|
+
);
|
|
9117
|
+
}
|
|
9118
|
+
if (offeringRefSet.has(offeringRef)) {
|
|
9119
|
+
throw Object.assign(
|
|
9120
|
+
new Error(
|
|
9121
|
+
`monetization.paywalls entry ${paywallSlug} has duplicate offering_ref: ${offeringRef}`
|
|
9122
|
+
),
|
|
9123
|
+
{ status: 400 }
|
|
9124
|
+
);
|
|
9125
|
+
}
|
|
9126
|
+
offeringRefSet.add(offeringRef);
|
|
9127
|
+
}
|
|
9128
|
+
const packageRefs = Array.isArray(monetizationPaywall.package_refs) ? monetizationPaywall.package_refs.map((value) => String(value ?? "").trim()).filter(Boolean) : [];
|
|
9129
|
+
const packageRefSet = /* @__PURE__ */ new Set();
|
|
9130
|
+
for (const packageRef of packageRefs) {
|
|
9131
|
+
if (!monetizationPackageSlugs.has(packageRef)) {
|
|
9132
|
+
throw Object.assign(
|
|
9133
|
+
new Error(
|
|
9134
|
+
`monetization.paywalls entry ${paywallSlug} references unknown package_ref: ${packageRef}`
|
|
9135
|
+
),
|
|
9136
|
+
{ status: 400 }
|
|
9137
|
+
);
|
|
9138
|
+
}
|
|
9139
|
+
if (packageRefSet.has(packageRef)) {
|
|
9140
|
+
throw Object.assign(
|
|
9141
|
+
new Error(
|
|
9142
|
+
`monetization.paywalls entry ${paywallSlug} has duplicate package_ref: ${packageRef}`
|
|
9143
|
+
),
|
|
9144
|
+
{ status: 400 }
|
|
9145
|
+
);
|
|
9146
|
+
}
|
|
9147
|
+
packageRefSet.add(packageRef);
|
|
9148
|
+
const packageOfferingRef = String(packageOfferingBySlug.get(packageRef) ?? "").trim();
|
|
9149
|
+
if (packageOfferingRef && !offeringRefSet.has(packageOfferingRef)) {
|
|
9150
|
+
throw Object.assign(
|
|
9151
|
+
new Error(
|
|
9152
|
+
`monetization.paywalls entry ${paywallSlug} package_ref ${packageRef} is not inside paywall offering_refs`
|
|
9153
|
+
),
|
|
9154
|
+
{ status: 400 }
|
|
9155
|
+
);
|
|
9156
|
+
}
|
|
9157
|
+
}
|
|
9158
|
+
const defaultPackageRef = String(monetizationPaywall.default_package_ref ?? "").trim();
|
|
9159
|
+
if (defaultPackageRef) {
|
|
9160
|
+
if (!monetizationPackageSlugs.has(defaultPackageRef)) {
|
|
9161
|
+
throw Object.assign(
|
|
9162
|
+
new Error(
|
|
9163
|
+
`monetization.paywalls entry ${paywallSlug} references unknown default_package_ref: ${defaultPackageRef}`
|
|
9164
|
+
),
|
|
9165
|
+
{ status: 400 }
|
|
9166
|
+
);
|
|
9167
|
+
}
|
|
9168
|
+
if (packageRefSet.size > 0 && !packageRefSet.has(defaultPackageRef)) {
|
|
9169
|
+
throw Object.assign(
|
|
9170
|
+
new Error(
|
|
9171
|
+
`monetization.paywalls entry ${paywallSlug} default_package_ref must also exist in package_refs when package_refs are declared`
|
|
9172
|
+
),
|
|
9173
|
+
{ status: 400 }
|
|
9174
|
+
);
|
|
9175
|
+
}
|
|
9176
|
+
const defaultOfferingRef = String(packageOfferingBySlug.get(defaultPackageRef) ?? "").trim();
|
|
9177
|
+
if (defaultOfferingRef && !offeringRefSet.has(defaultOfferingRef)) {
|
|
9178
|
+
throw Object.assign(
|
|
9179
|
+
new Error(
|
|
9180
|
+
`monetization.paywalls entry ${paywallSlug} default_package_ref ${defaultPackageRef} is not inside paywall offering_refs`
|
|
9181
|
+
),
|
|
9182
|
+
{ status: 400 }
|
|
9183
|
+
);
|
|
9184
|
+
}
|
|
9185
|
+
}
|
|
9186
|
+
}
|
|
8842
9187
|
for (const tool of manifest.tools ?? []) {
|
|
8843
9188
|
validateAdapterShape(tool);
|
|
8844
9189
|
const policy = tool.dispatch_policy;
|