@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/README.md +18 -1
- package/dist/index.d.ts +236 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +273 -8
- package/dist/index.js.map +2 -2
- package/dist/subjectProfileRequirement.d.ts +8 -0
- package/dist/subjectProfileRequirement.d.ts.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
8928
|
-
if (!
|
|
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
|
-
|
|
8941
|
-
if (!
|
|
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
|
-
|
|
9073
|
-
if (!
|
|
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
|
-
|
|
9085
|
-
if (!
|
|
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}`
|