diff --git a/package.json b/package.json index 89581ec..38ef969 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@BridgemanAccessible/ba-web-framework", - "version": "1.0.50", + "version": "1.0.51", "description": "A framework for web apps built atop Node, Express and other libraries and utilties that makes creating and maintaining Bridgeman Accessible web apps easier.", "author": "Bridgeman Accessible ", "repository": "https://git.bridgemanaccessible.ca/Bridgeman-Accessible/ba-web-framework.git", @@ -39,7 +39,7 @@ "create-ba-web-app": "node ./bin/create-project.js" }, "dependencies": { - "@BridgemanAccessible/ba-auth": "^1.0.23", + "@BridgemanAccessible/ba-auth": "^1.0.24", "@BridgemanAccessible/ba-logging": "^1.0.1", "express": "^4.19.2", "fs-extra": "^11.2.0", diff --git a/src/oauth/index.ts b/src/oauth/index.ts index a802d62..ac44624 100644 --- a/src/oauth/index.ts +++ b/src/oauth/index.ts @@ -1,9 +1,19 @@ import { OAuthApp } from './OAuthApp.js'; -import { BridgemanAccessibleAppClaims } from './types/BridgemanAccessibleAppClaims.js'; -import { AppSubscriptionTier } from './types/AppSubscriptionTier.js'; +import type { BridgemanAccessibleAppClaims } from './types/BridgemanAccessibleAppClaims.js'; +import type { AppSubscriptionTier } from './types/AppSubscriptionTier.js'; +import type { Addon } from './types/addons/Addon.js'; +import { AddonType } from './types/addons/AddonType.js'; +import { BillingCadence as AddonBillingCadence } from './types/addons/BillingCadence.js'; +import type { Schema as AddonSchema } from './types/addons/Schema.js'; +import type { PricingStrategy } from './types/addons/PricingStrategy.js'; export { OAuthApp, BridgemanAccessibleAppClaims, - AppSubscriptionTier + AppSubscriptionTier, + Addon, + AddonType, + AddonBillingCadence, + AddonSchema, + PricingStrategy, } \ No newline at end of file diff --git a/src/oauth/types/AppSubscriptionTier.ts b/src/oauth/types/AppSubscriptionTier.ts index 82ea8f2..39f29bd 100644 --- a/src/oauth/types/AppSubscriptionTier.ts +++ b/src/oauth/types/AppSubscriptionTier.ts @@ -5,5 +5,7 @@ export interface AppSubscriptionTier { cost: number; // e.g., 1000 (cents) currency: string; // e.g., "USD" description?: string; - // You can add 'features' list here if needed + features?: { + [featureName: string]: boolean; // e.g., { "prioritySupport": true, "customBranding": false } + } } \ No newline at end of file diff --git a/src/oauth/types/BridgemanAccessibleAppClaims.ts b/src/oauth/types/BridgemanAccessibleAppClaims.ts index 497302a..8aefa91 100644 --- a/src/oauth/types/BridgemanAccessibleAppClaims.ts +++ b/src/oauth/types/BridgemanAccessibleAppClaims.ts @@ -2,11 +2,14 @@ import { ClientCustomClaims } from '@BridgemanAccessible/ba-auth/server'; import { AppSubscriptionTier } from './AppSubscriptionTier.js'; +import { Addon } from './addons/Addon.js'; + /** * The custom registration claims (for Bridgeman Accessible apps) as used by this server * * This allows registering apps to specify very specific things this Authorization Server supports, such as: * - their subscription tiers + * - addons * - and client abbreviation. * * Which are useful internally to this server and clients/apps registering with it. @@ -30,4 +33,7 @@ export interface BridgemanAccessibleAppClaims extends ClientCustomClaims { /** The available subscription tiers for this client application */ subscription_tiers?: AppSubscriptionTier[]; + + /** The available addons for this client application */ + addons?: Addon[]; } \ No newline at end of file diff --git a/src/oauth/types/addons/Addon.ts b/src/oauth/types/addons/Addon.ts new file mode 100644 index 0000000..7120f3b --- /dev/null +++ b/src/oauth/types/addons/Addon.ts @@ -0,0 +1,51 @@ +import { AddonType } from './AddonType.js'; +import { BillingCadence } from './BillingCadence.js'; +import { Schema } from './Schema.js'; +import { PricingStrategy } from './PricingStrategy.js'; + +/** + * An Addon is a purchasable entity associated with a given app. + * + * Another way, this gives apps a way to define purchasable "things". + * Giving them the flexibility to define what those "things" are. + * + * This is desirable/necessary because we want to reuse our already setup infrastructure for payments etc... while not being confined by it. + * Infrastructure here being things like: + * - Renewals (if applicable), + * - Refunds, + * - Multiple payment processors, + * - 3rd party (purchaser/manager/etc...) billing/payment, + * - Etc... + * + * A few examples of addons might be: + * - Additional capacity for the AEP-E (Organizer App) + * - Funder funding goal contributions for the AEP-FP (Funders Portal) + */ +export type Addon = { + /** Product key associated with the addon */ + productKey: string; + + // ----------------- + // Addon Properties + // ----------------- + + /** Parameter Schema (buy time parameters) - JSON-Schema */ + schema: Schema; + + /** Pricing Strategy (How to calculate price at buy time) */ + pricing: PricingStrategy; +} & ( + { + /** Type of addon/purchase */ + type: AddonType.SUBSCRIPTION; + + // ---------------------------- + // Subscription Specific Fields + // ---------------------------- + + billingCadence: BillingCadence; + } | { + /** Type of addon/purchase */ + type: AddonType.ONE_TIME; + } +) \ No newline at end of file diff --git a/src/oauth/types/addons/AddonType.ts b/src/oauth/types/addons/AddonType.ts new file mode 100644 index 0000000..815373d --- /dev/null +++ b/src/oauth/types/addons/AddonType.ts @@ -0,0 +1,4 @@ +export enum AddonType { + SUBSCRIPTION = 'subscription', + ONE_TIME = 'one_time' +} \ No newline at end of file diff --git a/src/oauth/types/addons/BillingCadence.ts b/src/oauth/types/addons/BillingCadence.ts new file mode 100644 index 0000000..1eb0e12 --- /dev/null +++ b/src/oauth/types/addons/BillingCadence.ts @@ -0,0 +1,4 @@ +export enum BillingCadence { + MONTHLY = 'monthly', + YEARLY = 'yearly' +} \ No newline at end of file diff --git a/src/oauth/types/addons/PricingStrategy.ts b/src/oauth/types/addons/PricingStrategy.ts new file mode 100644 index 0000000..cd5226a --- /dev/null +++ b/src/oauth/types/addons/PricingStrategy.ts @@ -0,0 +1,44 @@ +/** The strategy/mechanism used to calculate the cost of a purchase of an addon at buy time */ +export type PricingStrategy = { + /** The currency in which the pricing is specified */ + currency: 'CAD' | 'USD' | 'EUR' | 'GBP' | 'AUD' +} & ( + { + /** + * Type of pricing used + * + * The table below describes the available pricing types. + * + * | Type | Description | + * | ----------------- | ------------------------------------------------------------------------------------ | + * | **`per_unit`** * | Price is calculated based on a per-unit basis multiplied by the configured quantity. | + * | `passthrough` | Price is determined externally and passed through without internal calculation. | + * + * \* indicates the current option + */ + type: 'per_unit', + + /** Per Unit Price (in cents) */ + unit_amount: number, + + /** Parameter to use for unit calculation */ + unit_parameter: string + } | { + /** + * Type of pricing used + * + * The table below describes the available pricing types. + * + * | Type | Description | + * | ------------------- | ------------------------------------------------------------------------------------ | + * | `per_unit` | Price is calculated based on a per-unit basis multiplied by the configured quantity. | + * | **`passthrough`** * | Price is determined externally and passed through without internal calculation. | + * + * \* indicates the current option + */ + type: 'passthrough', + + /** Parameter to use for passthrough amount */ + amount_parameter: string + } +); \ No newline at end of file diff --git a/src/oauth/types/addons/Schema.ts b/src/oauth/types/addons/Schema.ts new file mode 100644 index 0000000..75c5c78 --- /dev/null +++ b/src/oauth/types/addons/Schema.ts @@ -0,0 +1,42 @@ +/** Rough approximation of JSON-Schema property */ +type Property = { + /** Type of the property */ + type: 'string', + + /** Format of the value, if applicable */ + format?: 'date' | 'date-time' | 'email' | 'uuid', +} | { + /** Type of the property */ + type: 'number' | 'integer', + + /** Minimum value for numeric types */ + minimum?: number, +} | { + /** Type of the property */ + type: 'object', + + /** Nested properties for object types */ + properties: Properties +} | { + /** Type of the property */ + type: 'array', + + /** Format of the value, if applicable */ + items: Property[] +} | { + /** Type of the property */ + type: 'boolean' +} + +/** Rough approximation of JSON-Schema properties */ +type Properties = { + /** Named property (can have multiple) */ + [key: string]: Property +} + +/** A JSON-Schema (or rough approximation) definition for buy time parameters for addon purchase */ +export type Schema = { + type: 'object', + properties: Properties, + required?: string[] +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 47a669a..27b8584 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@BridgemanAccessible/ba-auth@^1.0.23": - version "1.0.23" - resolved "https://npm.pkg.bridgemanaccessible.ca/@BridgemanAccessible/ba-auth/-/ba-auth-1.0.23.tgz#7b83ab602fb40e1dcb8cc626be1f443449fdfad2" - integrity sha512-NBa64YAzgsrQe9u/6HiqDwJDuUlxEmdbIWg8j9MnF3dMv309VgHi8XPJ02R7qK8Pzjd32hK56AmM8LJRdztaGQ== +"@BridgemanAccessible/ba-auth@^1.0.24": + version "1.0.24" + resolved "https://npm.pkg.bridgemanaccessible.ca/@BridgemanAccessible/ba-auth/-/ba-auth-1.0.24.tgz#9e60d203bad6c721c03e2e2025d73d450a103e2d" + integrity sha512-AP6lFk+QWBIPfrVfGAe7P+m7CdpO4CWyqiE4JUmNeS3X93nnDsSvhFyfFBAMtF7XC3IuGQOwk0Y3Pj/rZmzwDw== dependencies: "@BridgemanAccessible/ba-logging" "^1.0.1" "@azure/identity" "^4.0.1"