Refined some of the types and added needed support for webhooks and addons in the OAuthApp class
All checks were successful
Publish to Private NPM Registry / publish (push) Successful in 45s
All checks were successful
Publish to Private NPM Registry / publish (push) Successful in 45s
This commit is contained in:
parent
91f1630cc6
commit
01306bf3a3
6 changed files with 154 additions and 44 deletions
|
|
@ -11,41 +11,91 @@ import { getValueFromEnvironmentVariable } from '../utils/env-vars.js';
|
|||
|
||||
import type { BridgemanAccessibleAppClaims } from './types/BridgemanAccessibleAppClaims.js';
|
||||
import type { AppSubscriptionTier } from './types/AppSubscriptionTier.js';
|
||||
import type { Addon } from './types/addons/Addon.js';
|
||||
import type { Webhook } from './types/Webhook.js';
|
||||
|
||||
type OAuthAppOptions = {
|
||||
// ------------------
|
||||
// Basic app metadata
|
||||
// ------------------
|
||||
|
||||
/** The base URL of the app */
|
||||
baseAppUrl?: URL,
|
||||
|
||||
/** The abbreviation of the app */
|
||||
appAbbrv?: string,
|
||||
/** If a subscription is required */
|
||||
subscriptionRequired?: boolean,
|
||||
/** The subscription tiers available for the app */
|
||||
subscriptionTiers?: AppSubscriptionTier[],
|
||||
/** The name of the app */
|
||||
|
||||
/** The (potentially localized) name of the app */
|
||||
appName?: string | {
|
||||
/** Localized versions of the app name */
|
||||
[language: string]: string
|
||||
},
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Necessary interconnected details (contacts, scopes, etc...)
|
||||
// -----------------------------------------------------------
|
||||
|
||||
/** The email addresses of the contacts for the app */
|
||||
contacts?: string[],
|
||||
/** The scopes an app token COULD ask for (token scopes would have to ask for this or a subset of this list) */
|
||||
scopes?: Scopes[],
|
||||
/** The URL of the app's logo */
|
||||
logo_url?: URL,
|
||||
/** The URL of the app's terms of service */
|
||||
tos_url?: URL,
|
||||
/** The URL of the app's privacy policy */
|
||||
policy_url?: URL,
|
||||
contacts?: string[],
|
||||
|
||||
/** The "available" scopes (scopes an app token COULD ask for - token scopes would have to ask for this or a subset of this list) */
|
||||
scopes?: Scopes[],
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Optional Mechanical Details (how the OAuth app works)
|
||||
// -----------------------------------------------------
|
||||
|
||||
/** The type of vault to use for the keystore */
|
||||
vault_type?: "azure" | "hashicorp" | "file",
|
||||
|
||||
/** The default method for authentication */
|
||||
auth_default_method?: "query" | "form_post" | "PAR",
|
||||
|
||||
/** Whether to use JWT as the default authentication method */
|
||||
auth_default_use_JWT?: boolean,
|
||||
|
||||
/** The default response mode for authentication */
|
||||
auth_default_response_mode?: 'query' | 'fragment' | 'form_post'
|
||||
|
||||
// -----------------------------------------------------
|
||||
// For already registered apps (to stop re-registration)
|
||||
// -----------------------------------------------------
|
||||
|
||||
/** The client secret for the app (if this IS set registration WON'T be done. Because re-registering isn't supported) */
|
||||
client_secret?: string
|
||||
|
||||
// ----------------------------------
|
||||
// URL stuff (policies, logo, etc...)
|
||||
// ----------------------------------
|
||||
|
||||
/** The URL of the app's logo */
|
||||
logo_url?: URL,
|
||||
|
||||
/** The URL of the app's Terms of Service */
|
||||
tos_url?: URL,
|
||||
|
||||
/** The URL of the app's Privacy Policy */
|
||||
policy_url?: URL,
|
||||
|
||||
// ------------------------------
|
||||
// Webhooks (async notifications)
|
||||
// ------------------------------
|
||||
|
||||
/** The webhooks supported by the app */
|
||||
webhooks?: Webhook[],
|
||||
|
||||
// ------------------------------------------
|
||||
// Purchasable Stuff (Subscriptions + Addons)
|
||||
// ------------------------------------------
|
||||
|
||||
/** If a subscription is required */
|
||||
subscriptionRequired?: boolean,
|
||||
|
||||
/** The subscription tiers available for the app */
|
||||
subscriptionTiers?: AppSubscriptionTier[],
|
||||
|
||||
/** Addons offered by the app */
|
||||
addons?: Addon[],
|
||||
};
|
||||
|
||||
export class OAuthApp extends App {
|
||||
|
|
@ -54,19 +104,21 @@ export class OAuthApp extends App {
|
|||
|
||||
private baseAppUrl?: URL;
|
||||
private appAbbrv?: string;
|
||||
private subscriptionRequired?: boolean;
|
||||
private subscriptionTiers?: AppSubscriptionTier[];
|
||||
private appName?: string | { [language: string]: string };
|
||||
private contacts?: string[];
|
||||
private scopes?: Scopes[];
|
||||
private logo_url?: URL;
|
||||
private tos_url?: URL;
|
||||
private policy_url?: URL;
|
||||
private vault_type?: "azure" | "hashicorp" | "file";
|
||||
private auth_default_method?: "query" | "form_post" | "PAR";
|
||||
private auth_default_use_JWT?: boolean;
|
||||
private auth_default_response_mode?: 'query' | 'fragment' | 'form_post';
|
||||
private client_secret?: string;
|
||||
private logo_url?: URL;
|
||||
private tos_url?: URL;
|
||||
private policy_url?: URL;
|
||||
private webhooks?: Webhook[];
|
||||
private subscriptionRequired?: boolean;
|
||||
private subscriptionTiers?: AppSubscriptionTier[];
|
||||
private addons?: Addon[];
|
||||
|
||||
private client: Client;
|
||||
|
||||
|
|
@ -86,12 +138,12 @@ export class OAuthApp extends App {
|
|||
* | APP_ABBRV | Required if `options.appAbbrv` isn't provided | The abbreviation of the client (app) |
|
||||
* | APP_NAME | Required if `options.appName` isn't provided | The name of the client (only a single non-localized name is supported) |
|
||||
* | CONTACT_EMAIL | Required if `options.contacts` isn't provided | A comma-separated list of email addresses to list as contacts for the client |
|
||||
* | LOGO_URL | Optional (used if `options.logo_url` isn't specified) | The URL of the client's (app's) logo |
|
||||
* | TOS_URL | Optional (used if `options.tos_url` isn't specified) | The URL of the client's terms of service |
|
||||
* | POLICY_URL | Optional (used if `options.policy_url` isn't specified) | The URL of the client's privacy policy |
|
||||
* | SCOPES | Required if `options.scopes` isn't provided | A comma-separated list of scopes available to the client |
|
||||
* | VAULT_TYPE | Required if in production (`NODE_ENV` is `production`) | The type of vault to use for the keystore (one of azure, hashicorp, or file) |
|
||||
* | APP_SECRET | Optional (Determines if app should register or not) | The client secret for the app (if this IS set registration WON'T be done) |
|
||||
* | LOGO_URL | Optional (used if `options.logo_url` isn't specified) | The URL of the client's (app's) logo |
|
||||
* | TOS_URL | Optional (used if `options.tos_url` isn't specified) | The URL of the client's terms of service |
|
||||
* | POLICY_URL | Optional (used if `options.policy_url` isn't specified) | The URL of the client's privacy policy |
|
||||
*
|
||||
* @param onAuth The callback to call when a user logs in
|
||||
* @param saveSecret The callback to call to save the secret
|
||||
|
|
@ -101,16 +153,24 @@ export class OAuthApp extends App {
|
|||
* @param options.appName The name of the app
|
||||
* @param options.contacts The email addresses of the contacts for the app
|
||||
* @param options.scopes The scopes an app token COULD ask for (token scopes would have to ask for this or a subset of this list)
|
||||
* @param options.logo_url The URL of the app's logo
|
||||
* @param options.tos_url The URL of the app's terms of service
|
||||
* @param options.policy_url The URL of the app's privacy policy
|
||||
* @param options.vault_type The type of vault to use for the keystore
|
||||
* @param options.auth_default_method The default method for authentication
|
||||
* @param options.auth_default_use_JWT Whether to use JWT as the default authentication method
|
||||
* @param options.auth_default_response_mode The default response mode for authentication
|
||||
* @param options.client_secret The client secret for the app (if this IS set registration WON'T be done. Because re-registering isn't supported)
|
||||
* @param options.logo_url The URL of the app's logo
|
||||
* @param options.tos_url The URL of the app's terms of service
|
||||
* @param options.policy_url The URL of the app's privacy policy
|
||||
* @param options.webhooks The webhooks supported by the app
|
||||
* @param options.subscriptionRequired If a subscription is required
|
||||
* @param options.subscriptionTiers The subscription tiers available for the app
|
||||
* @param options.addons Addons offered by the app
|
||||
*/
|
||||
constructor(onAuth: OnAuthCallback, saveSecret: (secret: string) => void | Promise<void>, options?: OAuthAppOptions) {
|
||||
constructor(
|
||||
onAuth: OnAuthCallback,
|
||||
saveSecret: (secret: string) => void | Promise<void>,
|
||||
options?: OAuthAppOptions
|
||||
) {
|
||||
super();
|
||||
this.onAuth = onAuth;
|
||||
this.saveSecret = saveSecret;
|
||||
|
|
@ -118,19 +178,21 @@ export class OAuthApp extends App {
|
|||
if(typeof options !== 'undefined') {
|
||||
this.baseAppUrl = options.baseAppUrl;
|
||||
this.appAbbrv = options.appAbbrv;
|
||||
this.subscriptionRequired = options.subscriptionRequired;
|
||||
this.subscriptionTiers = options.subscriptionTiers;
|
||||
this.appName = options.appName;
|
||||
this.contacts = options.contacts;
|
||||
this.scopes = options.scopes;
|
||||
this.logo_url = options.logo_url;
|
||||
this.tos_url = options.tos_url;
|
||||
this.policy_url = options.policy_url;
|
||||
this.vault_type = options.vault_type;
|
||||
this.auth_default_method = options.auth_default_method;
|
||||
this.auth_default_use_JWT = options.auth_default_use_JWT;
|
||||
this.auth_default_response_mode = options.auth_default_response_mode;
|
||||
this.client_secret = options.client_secret;
|
||||
this.logo_url = options.logo_url;
|
||||
this.tos_url = options.tos_url;
|
||||
this.policy_url = options.policy_url;
|
||||
this.webhooks = options.webhooks;
|
||||
this.subscriptionRequired = options.subscriptionRequired;
|
||||
this.subscriptionTiers = options.subscriptionTiers;
|
||||
this.addons = options.addons;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +237,9 @@ export class OAuthApp extends App {
|
|||
{
|
||||
client_abbreviation: appAbbrv,
|
||||
subscription_required: this.subscriptionRequired ?? false,
|
||||
subscription_tiers: this.subscriptionTiers
|
||||
subscription_tiers: this.subscriptionTiers,
|
||||
addons: this.addons,
|
||||
webhooks: this.webhooks
|
||||
},
|
||||
this.appName,
|
||||
this.scopes,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type { Webhook } from './types/Webhook.js';
|
|||
import { WebhookPurpose } from './types/WebhookPurpose.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 { BillingCadence as AddonBillingCadence } from './types/BillingCadence.js';
|
||||
import type { Schema as AddonSchema } from './types/addons/Schema.js';
|
||||
import type { PricingStrategy } from './types/addons/PricingStrategy.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,44 @@
|
|||
/** App subscription tier (mostly for app registration) */
|
||||
import { BillingCadence } from './BillingCadence.js';
|
||||
|
||||
/** App subscription tier */
|
||||
export interface AppSubscriptionTier {
|
||||
id: string;
|
||||
name: string; // e.g., "Free", "Pro"
|
||||
cost: number; // e.g., 1000 (cents)
|
||||
currency: string; // e.g., "USD"
|
||||
description?: string;
|
||||
features?: {
|
||||
/**
|
||||
* A unique identifier for the subscription tier.
|
||||
* This is only necessary if two tiers have the same name for some reason.
|
||||
*/
|
||||
id?: string;
|
||||
|
||||
/** The (potentially localized) name of the subscription tier */
|
||||
name: string | { [locale: string]: string };
|
||||
|
||||
pricing: {
|
||||
/**
|
||||
* The cost of the subscription tier (in cents).
|
||||
* Can have multiple prices for different billing frequencies (e.g., monthly, yearly).
|
||||
*/
|
||||
value: number | { [frequency in BillingCadence]?: number };
|
||||
|
||||
/** The currency of the subscription tier */
|
||||
currency: 'CAD' | 'USD' | 'EUR' | 'GBP' | 'AUD';
|
||||
|
||||
/** If value is a singular number a billing cadence can be set this way */
|
||||
billingCadence?: BillingCadence;
|
||||
};
|
||||
|
||||
/** A (potentially localized) description of the subscription tier */
|
||||
description?: string | { [locale: string]: string };
|
||||
|
||||
/**
|
||||
* Features included in the subscription tier.
|
||||
*
|
||||
* This can be a list of feature names (ex. ["prioritySupport", "customBranding"])
|
||||
* Or a mapping of feature names to booleans indicating inclusion (ex. { "prioritySupport": true, "customBranding": false })
|
||||
*
|
||||
* The difference is in their presentation to the user.
|
||||
* - As a list each tier just has it's list below it.
|
||||
* - As a mapping, all features are listed in a comparison table format (where all included features are shown with checkmarks and crosses to indicate exclusion).
|
||||
*/
|
||||
features?: string[] | {
|
||||
[featureName: string]: boolean; // e.g., { "prioritySupport": true, "customBranding": false }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { AddonType } from './AddonType.js';
|
||||
import { BillingCadence } from './BillingCadence.js';
|
||||
import { BillingCadence } from '../BillingCadence.js';
|
||||
import { Schema } from './Schema.js';
|
||||
import { PricingStrategy } from './PricingStrategy.js';
|
||||
|
||||
|
|
@ -43,7 +43,12 @@ export type Addon = {
|
|||
// Subscription Specific Fields
|
||||
// ----------------------------
|
||||
|
||||
billingCadence: BillingCadence;
|
||||
/**
|
||||
* Billing cadence for subscription addons.
|
||||
* Note, if the pricing strategy has a `unit_amount` with multiple billing cadences,
|
||||
* this field can be omitted / is ignored to allow the purchaser to select at buy time.
|
||||
*/
|
||||
billingCadence?: BillingCadence;
|
||||
} | {
|
||||
/** Type of addon/purchase */
|
||||
type: AddonType.ONE_TIME;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { BillingCadence } from '../BillingCadence.js';
|
||||
|
||||
/** 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 */
|
||||
|
|
@ -18,8 +20,14 @@ export type PricingStrategy = {
|
|||
*/
|
||||
type: 'per_unit',
|
||||
|
||||
/** Per Unit Price (in cents) */
|
||||
unit_amount: number,
|
||||
/**
|
||||
* Per Unit Price (in cents)
|
||||
*
|
||||
* Can be:
|
||||
* - A single number (applies to all billing cadences)
|
||||
* - Or an object specifying different amounts per billing cadence
|
||||
*/
|
||||
unit_amount: number | { [frequency in BillingCadence]?: number },
|
||||
|
||||
/** Parameter to use for unit calculation */
|
||||
unit_parameter: string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue