@xapps-platform/xapp-manifest 0.2.1 → 0.2.4

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/dist/index.js CHANGED
@@ -8090,6 +8090,20 @@ var xappManifestJsonSchema = {
8090
8090
  type: "object",
8091
8091
  additionalProperties: false,
8092
8092
  properties: {
8093
+ virtual_currencies: {
8094
+ type: "array",
8095
+ maxItems: 200,
8096
+ items: {
8097
+ type: "object",
8098
+ required: ["code"],
8099
+ additionalProperties: false,
8100
+ properties: {
8101
+ code: { type: "string", minLength: 1, maxLength: 100 },
8102
+ name: { type: "string", minLength: 1, maxLength: 200 },
8103
+ status: { type: "string", enum: ["active", "archived"] }
8104
+ }
8105
+ }
8106
+ },
8093
8107
  products: {
8094
8108
  type: "array",
8095
8109
  maxItems: 200,
@@ -8103,6 +8117,16 @@ var xappManifestJsonSchema = {
8103
8117
  description: localizedTextSchema(2e3),
8104
8118
  product_family: { type: "string", minLength: 1, maxLength: 100 },
8105
8119
  status: { type: "string", enum: ["draft", "active", "archived"] },
8120
+ virtual_currency: {
8121
+ type: "object",
8122
+ additionalProperties: false,
8123
+ required: ["code"],
8124
+ properties: {
8125
+ code: { type: "string", minLength: 1, maxLength: 100 },
8126
+ name: { type: "string", minLength: 1, maxLength: 200 },
8127
+ status: { type: "string", enum: ["active", "archived"] }
8128
+ }
8129
+ },
8106
8130
  metadata: { type: "object" }
8107
8131
  }
8108
8132
  }
@@ -8158,6 +8182,7 @@ var xappManifestJsonSchema = {
8158
8182
  package_ref: { type: "string", minLength: 1, maxLength: 100 },
8159
8183
  currency: { type: "string", minLength: 1, maxLength: 16 },
8160
8184
  amount: { type: "number", minimum: 0 },
8185
+ price_tax_mode: { type: "string", enum: ["gross", "net"] },
8161
8186
  billing_period: { type: "string", enum: ["day", "week", "month", "year"] },
8162
8187
  billing_period_count: { type: "integer", minimum: 1, maximum: 1e6 },
8163
8188
  trial_policy: { type: "object" },
@@ -8167,6 +8192,85 @@ var xappManifestJsonSchema = {
8167
8192
  metadata: { type: "object" }
8168
8193
  }
8169
8194
  }
8195
+ },
8196
+ paywalls: {
8197
+ type: "array",
8198
+ maxItems: 200,
8199
+ items: {
8200
+ type: "object",
8201
+ required: ["slug", "offering_refs"],
8202
+ additionalProperties: false,
8203
+ properties: {
8204
+ slug: { type: "string", minLength: 1, maxLength: 100 },
8205
+ title: localizedTextSchema(200),
8206
+ description: localizedTextSchema(2e3),
8207
+ placement: { type: "string", minLength: 1, maxLength: 100 },
8208
+ offering_refs: {
8209
+ type: "array",
8210
+ minItems: 1,
8211
+ maxItems: 50,
8212
+ items: { type: "string", minLength: 1, maxLength: 100 }
8213
+ },
8214
+ package_refs: {
8215
+ type: "array",
8216
+ minItems: 1,
8217
+ maxItems: 200,
8218
+ items: { type: "string", minLength: 1, maxLength: 100 }
8219
+ },
8220
+ default_package_ref: { type: "string", minLength: 1, maxLength: 100 },
8221
+ status: { type: "string", enum: ["draft", "active", "archived"] },
8222
+ targeting_rules: { type: "object" },
8223
+ metadata: { type: "object" }
8224
+ }
8225
+ }
8226
+ },
8227
+ usage_policies: {
8228
+ type: "array",
8229
+ maxItems: 200,
8230
+ items: {
8231
+ type: "object",
8232
+ required: ["tool_name", "credit_cost"],
8233
+ additionalProperties: false,
8234
+ properties: {
8235
+ tool_name: { type: "string", minLength: 1, maxLength: 100 },
8236
+ unit: { type: "string", minLength: 1, maxLength: 100 },
8237
+ credit_cost: { type: "number", minimum: 0 },
8238
+ virtual_currency_code: { type: "string", minLength: 1, maxLength: 100 },
8239
+ status: { type: "string", enum: ["draft", "active", "archived"] },
8240
+ metadata: { type: "object" }
8241
+ }
8242
+ }
8243
+ },
8244
+ hooks: {
8245
+ type: "object",
8246
+ additionalProperties: false,
8247
+ properties: {
8248
+ after_payment_completed: {
8249
+ type: "object",
8250
+ additionalProperties: true,
8251
+ properties: {
8252
+ enabled: { type: "boolean" },
8253
+ guard_slug: { type: "string", minLength: 1, maxLength: 200 },
8254
+ guardSlug: { type: "string", minLength: 1, maxLength: 200 },
8255
+ invoice_ref: { type: "string", minLength: 1, maxLength: 200 },
8256
+ invoiceRef: { type: "string", minLength: 1, maxLength: 200 },
8257
+ by_payment_guard_ref: {
8258
+ type: "object",
8259
+ additionalProperties: {
8260
+ type: "object",
8261
+ additionalProperties: true
8262
+ }
8263
+ },
8264
+ byPaymentGuardRef: {
8265
+ type: "object",
8266
+ additionalProperties: {
8267
+ type: "object",
8268
+ additionalProperties: true
8269
+ }
8270
+ }
8271
+ }
8272
+ }
8273
+ }
8170
8274
  }
8171
8275
  }
8172
8276
  },
@@ -8839,6 +8943,8 @@ function parseXappManifest(input, options) {
8839
8943
  const monetizationOfferings = readMonetizationEntries(monetization?.offerings);
8840
8944
  const monetizationPackages = readMonetizationEntries(monetization?.packages);
8841
8945
  const monetizationPrices = readMonetizationEntries(monetization?.prices);
8946
+ const monetizationPaywalls = readMonetizationEntries(monetization?.paywalls);
8947
+ const monetizationUsagePolicies = Array.isArray(monetization?.usage_policies) ? monetization.usage_policies : [];
8842
8948
  const paymentDefinitions = Array.isArray(manifest.payment_guard_definitions) ? manifest.payment_guard_definitions : [];
8843
8949
  const subjectProfileDefinitions = Array.isArray(manifest.subject_profile_guard_definitions) ? manifest.subject_profile_guard_definitions : [];
8844
8950
  const notificationDefinitions = Array.isArray(manifest.notification_definitions) ? manifest.notification_definitions : [];
@@ -8858,6 +8964,7 @@ function parseXappManifest(input, options) {
8858
8964
  );
8859
8965
  const monetizationPackageSlugs = requireUniqueSlug(monetizationPackages, "monetization.packages");
8860
8966
  requireUniqueSlug(monetizationPrices, "monetization.prices");
8967
+ requireUniqueSlug(monetizationPaywalls, "monetization.paywalls");
8861
8968
  for (const list of [
8862
8969
  [paymentDefinitions, paymentDefinitionNames, "payment_guard_definitions"],
8863
8970
  [subjectProfileDefinitions, subjectProfileDefinitionNames, "subject_profile_guard_definitions"],
@@ -8902,6 +9009,30 @@ function parseXappManifest(input, options) {
8902
9009
  const knownToolNames = new Set(
8903
9010
  (manifest.tools ?? []).map((tool) => String(tool.tool_name || "").trim())
8904
9011
  );
9012
+ const monetizationUsagePolicyTools = /* @__PURE__ */ new Set();
9013
+ for (const usagePolicy of monetizationUsagePolicies) {
9014
+ const toolName = String(usagePolicy?.tool_name ?? "").trim();
9015
+ const creditCost = Number(usagePolicy?.credit_cost);
9016
+ if (!knownToolNames.has(toolName)) {
9017
+ throw Object.assign(
9018
+ new Error(`monetization.usage_policies entry references unknown tool_name: ${toolName}`),
9019
+ { status: 400 }
9020
+ );
9021
+ }
9022
+ if (!Number.isFinite(creditCost)) {
9023
+ throw Object.assign(
9024
+ new Error(`monetization.usage_policies entry requires numeric credit_cost: ${toolName}`),
9025
+ { status: 400 }
9026
+ );
9027
+ }
9028
+ if (monetizationUsagePolicyTools.has(toolName)) {
9029
+ throw Object.assign(
9030
+ new Error(`monetization.usage_policies has duplicate tool_name: ${toolName}`),
9031
+ { status: 400 }
9032
+ );
9033
+ }
9034
+ monetizationUsagePolicyTools.add(toolName);
9035
+ }
8905
9036
  const referencedPaymentDefinitionNames = /* @__PURE__ */ new Set();
8906
9037
  const referencedSubjectProfileDefinitionNames = /* @__PURE__ */ new Set();
8907
9038
  const notificationDefinitionRegistry = buildNotificationDefinitionRegistry(
@@ -8914,6 +9045,44 @@ function parseXappManifest(input, options) {
8914
9045
  manifest.invoice_definitions ?? []
8915
9046
  );
8916
9047
  const invoiceTemplateRegistry = buildInvoiceTemplateRegistry(manifest.invoice_templates ?? []);
9048
+ const notificationTemplateFamilyNames = /* @__PURE__ */ new Map();
9049
+ for (const template of notificationTemplates) {
9050
+ const family = String(template?.family ?? "").trim();
9051
+ const name = String(template?.name ?? "").trim();
9052
+ if (!family || !name) continue;
9053
+ notificationTemplateFamilyNames.set(family, [
9054
+ ...notificationTemplateFamilyNames.get(family) ?? [],
9055
+ name
9056
+ ]);
9057
+ }
9058
+ const invoiceTemplateFamilyNames = /* @__PURE__ */ new Map();
9059
+ for (const template of invoiceTemplates) {
9060
+ const family = String(template?.family ?? "").trim();
9061
+ const name = String(template?.name ?? "").trim();
9062
+ if (!family || !name) continue;
9063
+ invoiceTemplateFamilyNames.set(family, [
9064
+ ...invoiceTemplateFamilyNames.get(family) ?? [],
9065
+ name
9066
+ ]);
9067
+ }
9068
+ const hasNotificationTemplateRef = (ref) => notificationTemplateRegistry.has(ref) || notificationTemplateFamilyNames.has(ref);
9069
+ const hasInvoiceTemplateRef = (ref) => invoiceTemplateRegistry.has(ref) || invoiceTemplateFamilyNames.has(ref);
9070
+ const markNotificationTemplateRef = (ref) => {
9071
+ const familyNames = notificationTemplateFamilyNames.get(ref);
9072
+ if (familyNames?.length) {
9073
+ for (const name of familyNames) referencedNotificationTemplateNames.add(name);
9074
+ return;
9075
+ }
9076
+ referencedNotificationTemplateNames.add(ref);
9077
+ };
9078
+ const markInvoiceTemplateRef = (ref) => {
9079
+ const familyNames = invoiceTemplateFamilyNames.get(ref);
9080
+ if (familyNames?.length) {
9081
+ for (const name of familyNames) referencedInvoiceTemplateNames.add(name);
9082
+ return;
9083
+ }
9084
+ referencedInvoiceTemplateNames.add(ref);
9085
+ };
8917
9086
  const subjectProfileDefinitionRegistry = buildSubjectProfileDefinitionRegistry(
8918
9087
  manifest.subject_profile_guard_definitions ?? []
8919
9088
  );
@@ -8924,8 +9093,8 @@ function parseXappManifest(input, options) {
8924
9093
  for (const def of notificationDefinitions) {
8925
9094
  const templateRef = readNotificationTemplateRef(def);
8926
9095
  if (!templateRef) continue;
8927
- referencedNotificationTemplateNames.add(templateRef);
8928
- if (!notificationTemplateRegistry.has(templateRef)) {
9096
+ markNotificationTemplateRef(templateRef);
9097
+ if (!hasNotificationTemplateRef(templateRef)) {
8929
9098
  throw Object.assign(
8930
9099
  new Error(
8931
9100
  `notification_definitions entry ${String(def?.name ?? "unknown")} references unknown template_ref: ${templateRef}`
@@ -8937,8 +9106,8 @@ function parseXappManifest(input, options) {
8937
9106
  for (const def of invoiceDefinitions) {
8938
9107
  const templateRef = readInvoiceTemplateRef(def);
8939
9108
  if (!templateRef) continue;
8940
- referencedInvoiceTemplateNames.add(templateRef);
8941
- if (!invoiceTemplateRegistry.has(templateRef)) {
9109
+ markInvoiceTemplateRef(templateRef);
9110
+ if (!hasInvoiceTemplateRef(templateRef)) {
8942
9111
  throw Object.assign(
8943
9112
  new Error(
8944
9113
  `invoice_definitions entry ${String(def?.name ?? "unknown")} references unknown invoice_template_ref: ${templateRef}`
@@ -8983,6 +9152,102 @@ function parseXappManifest(input, options) {
8983
9152
  );
8984
9153
  }
8985
9154
  }
9155
+ const packageOfferingBySlug = /* @__PURE__ */ new Map();
9156
+ for (const monetizationPackage of monetizationPackages) {
9157
+ const packageSlug = String(monetizationPackage.slug ?? "").trim();
9158
+ const offeringRef = String(monetizationPackage.offering_ref ?? "").trim();
9159
+ if (packageSlug && offeringRef) {
9160
+ packageOfferingBySlug.set(packageSlug, offeringRef);
9161
+ }
9162
+ }
9163
+ for (const monetizationPaywall of monetizationPaywalls) {
9164
+ const paywallSlug = String(monetizationPaywall.slug ?? "unknown").trim() || "unknown";
9165
+ const offeringRefs = Array.isArray(monetizationPaywall.offering_refs) ? monetizationPaywall.offering_refs.map((value) => String(value ?? "").trim()).filter(Boolean) : [];
9166
+ if (!offeringRefs.length) {
9167
+ throw Object.assign(
9168
+ new Error(`monetization.paywalls entry ${paywallSlug} requires at least one offering_ref`),
9169
+ { status: 400 }
9170
+ );
9171
+ }
9172
+ const offeringRefSet = /* @__PURE__ */ new Set();
9173
+ for (const offeringRef of offeringRefs) {
9174
+ if (!monetizationOfferingSlugs.has(offeringRef)) {
9175
+ throw Object.assign(
9176
+ new Error(
9177
+ `monetization.paywalls entry ${paywallSlug} references unknown offering_ref: ${offeringRef}`
9178
+ ),
9179
+ { status: 400 }
9180
+ );
9181
+ }
9182
+ if (offeringRefSet.has(offeringRef)) {
9183
+ throw Object.assign(
9184
+ new Error(
9185
+ `monetization.paywalls entry ${paywallSlug} has duplicate offering_ref: ${offeringRef}`
9186
+ ),
9187
+ { status: 400 }
9188
+ );
9189
+ }
9190
+ offeringRefSet.add(offeringRef);
9191
+ }
9192
+ const packageRefs = Array.isArray(monetizationPaywall.package_refs) ? monetizationPaywall.package_refs.map((value) => String(value ?? "").trim()).filter(Boolean) : [];
9193
+ const packageRefSet = /* @__PURE__ */ new Set();
9194
+ for (const packageRef of packageRefs) {
9195
+ if (!monetizationPackageSlugs.has(packageRef)) {
9196
+ throw Object.assign(
9197
+ new Error(
9198
+ `monetization.paywalls entry ${paywallSlug} references unknown package_ref: ${packageRef}`
9199
+ ),
9200
+ { status: 400 }
9201
+ );
9202
+ }
9203
+ if (packageRefSet.has(packageRef)) {
9204
+ throw Object.assign(
9205
+ new Error(
9206
+ `monetization.paywalls entry ${paywallSlug} has duplicate package_ref: ${packageRef}`
9207
+ ),
9208
+ { status: 400 }
9209
+ );
9210
+ }
9211
+ packageRefSet.add(packageRef);
9212
+ const packageOfferingRef = String(packageOfferingBySlug.get(packageRef) ?? "").trim();
9213
+ if (packageOfferingRef && !offeringRefSet.has(packageOfferingRef)) {
9214
+ throw Object.assign(
9215
+ new Error(
9216
+ `monetization.paywalls entry ${paywallSlug} package_ref ${packageRef} is not inside paywall offering_refs`
9217
+ ),
9218
+ { status: 400 }
9219
+ );
9220
+ }
9221
+ }
9222
+ const defaultPackageRef = String(monetizationPaywall.default_package_ref ?? "").trim();
9223
+ if (defaultPackageRef) {
9224
+ if (!monetizationPackageSlugs.has(defaultPackageRef)) {
9225
+ throw Object.assign(
9226
+ new Error(
9227
+ `monetization.paywalls entry ${paywallSlug} references unknown default_package_ref: ${defaultPackageRef}`
9228
+ ),
9229
+ { status: 400 }
9230
+ );
9231
+ }
9232
+ if (packageRefSet.size > 0 && !packageRefSet.has(defaultPackageRef)) {
9233
+ throw Object.assign(
9234
+ new Error(
9235
+ `monetization.paywalls entry ${paywallSlug} default_package_ref must also exist in package_refs when package_refs are declared`
9236
+ ),
9237
+ { status: 400 }
9238
+ );
9239
+ }
9240
+ const defaultOfferingRef = String(packageOfferingBySlug.get(defaultPackageRef) ?? "").trim();
9241
+ if (defaultOfferingRef && !offeringRefSet.has(defaultOfferingRef)) {
9242
+ throw Object.assign(
9243
+ new Error(
9244
+ `monetization.paywalls entry ${paywallSlug} default_package_ref ${defaultPackageRef} is not inside paywall offering_refs`
9245
+ ),
9246
+ { status: 400 }
9247
+ );
9248
+ }
9249
+ }
9250
+ }
8986
9251
  for (const tool of manifest.tools ?? []) {
8987
9252
  validateAdapterShape(tool);
8988
9253
  const policy = tool.dispatch_policy;
@@ -9069,8 +9334,8 @@ function parseXappManifest(input, options) {
9069
9334
  const resolvedHookFamilyConfig = resolvedNotificationConfig ?? resolvedInvoiceConfig;
9070
9335
  const templateRef = resolvedNotificationConfig && isRecord(resolvedNotificationConfig) ? readNotificationTemplateRef(resolvedNotificationConfig) : "";
9071
9336
  if (templateRef) {
9072
- referencedNotificationTemplateNames.add(templateRef);
9073
- if (!notificationTemplateRegistry.has(templateRef)) {
9337
+ markNotificationTemplateRef(templateRef);
9338
+ if (!hasNotificationTemplateRef(templateRef)) {
9074
9339
  throw Object.assign(
9075
9340
  new Error(
9076
9341
  `Guard ${String(guard?.slug || "unknown")} references unknown template_ref: ${templateRef}`
@@ -9081,8 +9346,8 @@ function parseXappManifest(input, options) {
9081
9346
  }
9082
9347
  const invoiceTemplateRef = resolvedInvoiceConfig && isRecord(resolvedInvoiceConfig) ? readInvoiceTemplateRef(resolvedInvoiceConfig) : readInvoiceTemplateRef(guardConfig);
9083
9348
  if (invoiceTemplateRef) {
9084
- referencedInvoiceTemplateNames.add(invoiceTemplateRef);
9085
- if (!invoiceTemplateRegistry.has(invoiceTemplateRef)) {
9349
+ markInvoiceTemplateRef(invoiceTemplateRef);
9350
+ if (!hasInvoiceTemplateRef(invoiceTemplateRef)) {
9086
9351
  throw Object.assign(
9087
9352
  new Error(
9088
9353
  `Guard ${String(guard?.slug || "unknown")} references unknown invoice_template_ref: ${invoiceTemplateRef}`