@microsoft/feature-management 2.2.0 → 2.3.0

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.
Files changed (37) hide show
  1. package/dist/commonjs/common/targetingEvaluator.js.map +1 -1
  2. package/dist/commonjs/featureManager.js.map +1 -1
  3. package/dist/commonjs/featureProvider.js.map +1 -1
  4. package/dist/commonjs/filter/recurrence/evaluator.js.map +1 -1
  5. package/dist/commonjs/filter/recurrence/model.js.map +1 -1
  6. package/dist/commonjs/filter/recurrence/utils.js.map +1 -1
  7. package/dist/commonjs/filter/recurrence/validator.js.map +1 -1
  8. package/dist/commonjs/filter/targetingFilter.js.map +1 -1
  9. package/dist/commonjs/filter/timeWindowFilter.js.map +1 -1
  10. package/dist/commonjs/filter/utils.js.map +1 -1
  11. package/dist/commonjs/schema/model.js.map +1 -1
  12. package/dist/commonjs/schema/validator.js.map +1 -1
  13. package/dist/commonjs/telemetry/featureEvaluationEvent.js.map +1 -1
  14. package/dist/commonjs/variant/variant.js.map +1 -1
  15. package/dist/commonjs/version.js +1 -1
  16. package/dist/commonjs/version.js.map +1 -1
  17. package/dist/esm/common/targetingEvaluator.js.map +1 -1
  18. package/dist/esm/featureManager.js.map +1 -1
  19. package/dist/esm/featureProvider.js.map +1 -1
  20. package/dist/esm/filter/recurrence/evaluator.js.map +1 -1
  21. package/dist/esm/filter/recurrence/model.js.map +1 -1
  22. package/dist/esm/filter/recurrence/utils.js.map +1 -1
  23. package/dist/esm/filter/recurrence/validator.js +1 -1
  24. package/dist/esm/filter/recurrence/validator.js.map +1 -1
  25. package/dist/esm/filter/targetingFilter.js.map +1 -1
  26. package/dist/esm/filter/timeWindowFilter.js.map +1 -1
  27. package/dist/esm/filter/utils.js.map +1 -1
  28. package/dist/esm/schema/model.js.map +1 -1
  29. package/dist/esm/schema/validator.js.map +1 -1
  30. package/dist/esm/telemetry/featureEvaluationEvent.js.map +1 -1
  31. package/dist/esm/variant/variant.js.map +1 -1
  32. package/dist/esm/version.js +1 -1
  33. package/dist/esm/version.js.map +1 -1
  34. package/{types → dist/types}/index.d.ts +3 -2
  35. package/dist/umd/index.js +1 -1
  36. package/dist/umd/index.js.map +1 -1
  37. package/package.json +41 -27
@@ -1 +1 @@
1
- {"version":3,"file":"targetingEvaluator.js","sources":["../../../src/common/targetingEvaluator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Determines if the user is part of the audience, based on the user id and the percentage range.\n *\n * @param userId user id from app context\n * @param hint hint string to be included in the context id\n * @param from percentage range start\n * @param to percentage range end\n * @returns true if the user is part of the audience, false otherwise\n */\nexport async function isTargetedPercentile(userId: string | undefined, hint: string, from: number, to: number): Promise<boolean> {\n if (from < 0 || from > 100) {\n throw new Error(\"The 'from' value must be between 0 and 100.\");\n }\n if (to < 0 || to > 100) {\n throw new Error(\"The 'to' value must be between 0 and 100.\");\n }\n if (from > to) {\n throw new Error(\"The 'from' value cannot be larger than the 'to' value.\");\n }\n\n const audienceContextId = constructAudienceContextId(userId, hint);\n\n // Cryptographic hashing algorithms ensure adequate entropy across hash values.\n const contextMarker = await stringToUint32(audienceContextId);\n const contextPercentage = (contextMarker / 0xFFFFFFFF) * 100;\n\n // Handle edge case of exact 100 bucket\n if (to === 100) {\n return contextPercentage >= from;\n }\n\n return contextPercentage >= from && contextPercentage < to;\n}\n\n/**\n * Determines if the user is part of the audience, based on the groups they belong to.\n *\n * @param sourceGroups user groups from app context\n * @param targetedGroups targeted groups from feature configuration\n * @returns true if the user is part of the audience, false otherwise\n */\nexport function isTargetedGroup(sourceGroups: string[] | undefined, targetedGroups: string[]): boolean {\n if (sourceGroups === undefined) {\n return false;\n }\n\n return sourceGroups.some(group => targetedGroups.includes(group));\n}\n\n/**\n * Determines if the user is part of the audience, based on the user id.\n * @param userId user id from app context\n * @param users targeted users from feature configuration\n * @returns true if the user is part of the audience, false otherwise\n */\nexport function isTargetedUser(userId: string | undefined, users: string[]): boolean {\n if (userId === undefined) {\n return false;\n }\n\n return users.includes(userId);\n}\n\n/**\n * Constructs the context id for the audience.\n * The context id is used to determine if the user is part of the audience for a feature.\n *\n * @param userId userId from app context\n * @param hint hint string to be included in the context id\n * @returns a string that represents the context id for the audience\n */\nfunction constructAudienceContextId(userId: string | undefined, hint: string): string {\n return `${userId ?? \"\"}\\n${hint}`;\n}\n\n/**\n * Converts a string to a uint32 in little-endian encoding.\n * @param str the string to convert.\n * @returns a uint32 value.\n */\nasync function stringToUint32(str: string): Promise<number> {\n let crypto;\n\n // Check for browser environment\n if (typeof window !== \"undefined\" && window.crypto && window.crypto.subtle) {\n crypto = window.crypto;\n }\n // Check for Node.js environment\n else if (typeof global !== \"undefined\" && global.crypto) {\n crypto = global.crypto;\n }\n // Fallback to native Node.js crypto module\n else {\n try {\n if (typeof module !== \"undefined\" && module.exports) {\n crypto = require(\"crypto\");\n }\n else {\n crypto = await import(\"crypto\");\n }\n } catch (error) {\n console.error(\"Failed to load the crypto module:\", error.message);\n throw error;\n }\n }\n\n // In the browser, use crypto.subtle.digest\n if (crypto.subtle) {\n const data = new TextEncoder().encode(str);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const dataView = new DataView(hashBuffer);\n const uint32 = dataView.getUint32(0, true);\n return uint32;\n }\n // In Node.js, use the crypto module's hash function\n else {\n const hash = crypto.createHash(\"sha256\").update(str).digest();\n const uint32 = hash.readUInt32LE(0);\n return uint32;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"targetingEvaluator.js","sources":["../../../src/common/targetingEvaluator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Determines if the user is part of the audience, based on the user id and the percentage range.\n *\n * @param userId user id from app context\n * @param hint hint string to be included in the context id\n * @param from percentage range start\n * @param to percentage range end\n * @returns true if the user is part of the audience, false otherwise\n */\nexport async function isTargetedPercentile(userId: string | undefined, hint: string, from: number, to: number): Promise<boolean> {\n if (from < 0 || from > 100) {\n throw new Error(\"The 'from' value must be between 0 and 100.\");\n }\n if (to < 0 || to > 100) {\n throw new Error(\"The 'to' value must be between 0 and 100.\");\n }\n if (from > to) {\n throw new Error(\"The 'from' value cannot be larger than the 'to' value.\");\n }\n\n const audienceContextId = constructAudienceContextId(userId, hint);\n\n // Cryptographic hashing algorithms ensure adequate entropy across hash values.\n const contextMarker = await stringToUint32(audienceContextId);\n const contextPercentage = (contextMarker / 0xFFFFFFFF) * 100;\n\n // Handle edge case of exact 100 bucket\n if (to === 100) {\n return contextPercentage >= from;\n }\n\n return contextPercentage >= from && contextPercentage < to;\n}\n\n/**\n * Determines if the user is part of the audience, based on the groups they belong to.\n *\n * @param sourceGroups user groups from app context\n * @param targetedGroups targeted groups from feature configuration\n * @returns true if the user is part of the audience, false otherwise\n */\nexport function isTargetedGroup(sourceGroups: string[] | undefined, targetedGroups: string[]): boolean {\n if (sourceGroups === undefined) {\n return false;\n }\n\n return sourceGroups.some(group => targetedGroups.includes(group));\n}\n\n/**\n * Determines if the user is part of the audience, based on the user id.\n * @param userId user id from app context\n * @param users targeted users from feature configuration\n * @returns true if the user is part of the audience, false otherwise\n */\nexport function isTargetedUser(userId: string | undefined, users: string[]): boolean {\n if (userId === undefined) {\n return false;\n }\n\n return users.includes(userId);\n}\n\n/**\n * Constructs the context id for the audience.\n * The context id is used to determine if the user is part of the audience for a feature.\n *\n * @param userId userId from app context\n * @param hint hint string to be included in the context id\n * @returns a string that represents the context id for the audience\n */\nfunction constructAudienceContextId(userId: string | undefined, hint: string): string {\n return `${userId ?? \"\"}\\n${hint}`;\n}\n\n/**\n * Converts a string to a uint32 in little-endian encoding.\n * @param str the string to convert.\n * @returns a uint32 value.\n */\nasync function stringToUint32(str: string): Promise<number> {\n let crypto;\n\n // Check for browser environment\n if (typeof window !== \"undefined\" && window.crypto && window.crypto.subtle) {\n crypto = window.crypto;\n }\n // Check for Node.js environment\n else if (typeof global !== \"undefined\" && global.crypto) {\n crypto = global.crypto;\n }\n // Fallback to native Node.js crypto module\n else {\n try {\n if (typeof module !== \"undefined\" && module.exports) {\n crypto = require(\"crypto\");\n }\n else {\n crypto = await import(\"crypto\");\n }\n } catch (error) {\n console.error(\"Failed to load the crypto module:\", error.message);\n throw error;\n }\n }\n\n // In the browser, use crypto.subtle.digest\n if (crypto.subtle) {\n const data = new TextEncoder().encode(str);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const dataView = new DataView(hashBuffer);\n const uint32 = dataView.getUint32(0, true);\n return uint32;\n }\n // In Node.js, use the crypto module's hash function\n else {\n const hash = crypto.createHash(\"sha256\").update(str).digest();\n const uint32 = hash.readUInt32LE(0);\n return uint32;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"featureManager.js","sources":["../../src/featureManager.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { TimeWindowFilter } from \"./filter/timeWindowFilter.js\";\nimport { IFeatureFilter } from \"./filter/featureFilter.js\";\nimport { FeatureFlag, RequirementType, VariantDefinition } from \"./schema/model.js\";\nimport { IFeatureFlagProvider, IFeatureManager } from \"./model.js\";\nimport { TargetingFilter } from \"./filter/targetingFilter.js\";\nimport { Variant } from \"./variant/variant.js\";\nimport { ITargetingContext, ITargetingContextAccessor } from \"./common/targetingContext.js\";\nimport { isTargetedGroup, isTargetedPercentile, isTargetedUser } from \"./common/targetingEvaluator.js\";\n\nexport class FeatureManager implements IFeatureManager {\n readonly #provider: IFeatureFlagProvider;\n readonly #featureFilters: Map<string, IFeatureFilter> = new Map();\n readonly #onFeatureEvaluated?: (event: EvaluationResult) => void;\n readonly #targetingContextAccessor?: ITargetingContextAccessor;\n\n constructor(provider: IFeatureFlagProvider, options?: FeatureManagerOptions) {\n this.#provider = provider;\n this.#onFeatureEvaluated = options?.onFeatureEvaluated;\n this.#targetingContextAccessor = options?.targetingContextAccessor;\n\n const builtinFilters = [new TimeWindowFilter(), new TargetingFilter(options?.targetingContextAccessor)];\n // If a custom filter shares a name with an existing filter, the custom filter overrides the existing one.\n for (const filter of [...builtinFilters, ...(options?.customFilters ?? [])]) {\n this.#featureFilters.set(filter.name, filter);\n }\n }\n\n async listFeatureNames(): Promise<string[]> {\n const features = await this.#provider.getFeatureFlags();\n const featureNameSet = new Set(features.map((feature) => feature.id));\n return Array.from(featureNameSet);\n }\n\n // If multiple feature flags are found, the first one takes precedence.\n async isEnabled(featureName: string, context?: unknown): Promise<boolean> {\n const result = await this.#evaluateFeature(featureName, context);\n return result.enabled;\n }\n\n async getVariant(featureName: string, context?: ITargetingContext): Promise<Variant | undefined> {\n const result = await this.#evaluateFeature(featureName, context);\n return result.variant;\n }\n\n async #assignVariant(featureFlag: FeatureFlag, context: ITargetingContext): Promise<VariantAssignment> {\n // user allocation\n if (featureFlag.allocation?.user !== undefined) {\n for (const userAllocation of featureFlag.allocation.user) {\n if (isTargetedUser(context.userId, userAllocation.users)) {\n return getVariantAssignment(featureFlag, userAllocation.variant, VariantAssignmentReason.User);\n }\n }\n }\n\n // group allocation\n if (featureFlag.allocation?.group !== undefined) {\n for (const groupAllocation of featureFlag.allocation.group) {\n if (isTargetedGroup(context.groups, groupAllocation.groups)) {\n return getVariantAssignment(featureFlag, groupAllocation.variant, VariantAssignmentReason.Group);\n }\n }\n }\n\n // percentile allocation\n if (featureFlag.allocation?.percentile !== undefined) {\n for (const percentileAllocation of featureFlag.allocation.percentile) {\n const hint = featureFlag.allocation.seed ?? `allocation\\n${featureFlag.id}`;\n if (await isTargetedPercentile(context.userId, hint, percentileAllocation.from, percentileAllocation.to)) {\n return getVariantAssignment(featureFlag, percentileAllocation.variant, VariantAssignmentReason.Percentile);\n }\n }\n }\n\n return { variant: undefined, reason: VariantAssignmentReason.None };\n }\n\n async #isEnabled(featureFlag: FeatureFlag, appContext?: unknown): Promise<boolean> {\n if (featureFlag.enabled !== true) {\n // If the feature is not explicitly enabled, then it is disabled by default.\n return false;\n }\n\n const clientFilters = featureFlag.conditions?.client_filters;\n if (clientFilters === undefined || clientFilters.length <= 0) {\n // If there are no client filters, then the feature is enabled.\n return true;\n }\n\n const requirementType: RequirementType = featureFlag.conditions?.requirement_type ?? \"Any\"; // default to any.\n\n /**\n * While iterating through the client filters, we short-circuit the evaluation based on the requirement type.\n * - When requirement type is \"All\", the feature is enabled if all client filters are matched. If any client filter is not matched, the feature is disabled, otherwise it is enabled. `shortCircuitEvaluationResult` is false.\n * - When requirement type is \"Any\", the feature is enabled if any client filter is matched. If any client filter is matched, the feature is enabled, otherwise it is disabled. `shortCircuitEvaluationResult` is true.\n */\n const shortCircuitEvaluationResult: boolean = requirementType === \"Any\";\n\n for (const clientFilter of clientFilters) {\n const matchedFeatureFilter = this.#featureFilters.get(clientFilter.name);\n const contextWithFeatureName = { featureName: featureFlag.id, parameters: clientFilter.parameters };\n if (matchedFeatureFilter === undefined) {\n console.warn(`Feature filter ${clientFilter.name} is not found.`);\n return false;\n }\n if (await matchedFeatureFilter.evaluate(contextWithFeatureName, appContext) === shortCircuitEvaluationResult) {\n return shortCircuitEvaluationResult;\n }\n }\n\n // If we get here, then we have not found a client filter that matches the requirement type.\n return !shortCircuitEvaluationResult;\n }\n\n async #evaluateFeature(featureName: string, appContext: unknown): Promise<EvaluationResult> {\n const featureFlag = await this.#provider.getFeatureFlag(featureName);\n const result = new EvaluationResult(featureFlag);\n\n if (featureFlag === undefined) {\n return result;\n }\n\n // Ensure that the feature flag is in the correct format. Feature providers should validate the feature flags, but we do it here as a safeguard.\n // TODO: move to the feature flag provider implementation.\n validateFeatureFlagFormat(featureFlag);\n\n // Evaluate if the feature is enabled.\n result.enabled = await this.#isEnabled(featureFlag, appContext);\n\n // Get targeting context from the app context or the targeting context accessor\n const targetingContext = this.#getTargetingContext(appContext);\n result.targetingId = targetingContext?.userId;\n\n // Determine Variant\n let variantDef: VariantDefinition | undefined;\n let reason: VariantAssignmentReason = VariantAssignmentReason.None;\n\n // featureFlag.variant not empty\n if (featureFlag.variants !== undefined && featureFlag.variants.length > 0) {\n if (!result.enabled) {\n // not enabled, assign default if specified\n if (featureFlag.allocation?.default_when_disabled !== undefined) {\n variantDef = featureFlag.variants.find(v => v.name == featureFlag.allocation?.default_when_disabled);\n reason = VariantAssignmentReason.DefaultWhenDisabled;\n } else {\n // no default specified\n variantDef = undefined;\n reason = VariantAssignmentReason.DefaultWhenDisabled;\n }\n } else {\n // enabled, assign based on allocation\n if (targetingContext !== undefined && featureFlag.allocation !== undefined) {\n const variantAndReason = await this.#assignVariant(featureFlag, targetingContext);\n variantDef = variantAndReason.variant;\n reason = variantAndReason.reason;\n }\n\n // allocation failed, assign default if specified\n if (variantDef === undefined && reason === VariantAssignmentReason.None) {\n if (featureFlag.allocation?.default_when_enabled !== undefined) {\n variantDef = featureFlag.variants.find(v => v.name == featureFlag.allocation?.default_when_enabled);\n reason = VariantAssignmentReason.DefaultWhenEnabled;\n } else {\n variantDef = undefined;\n reason = VariantAssignmentReason.DefaultWhenEnabled;\n }\n }\n }\n }\n\n result.variant = variantDef !== undefined ? new Variant(variantDef.name, variantDef.configuration_value) : undefined;\n result.variantAssignmentReason = reason;\n\n // Status override for isEnabled\n if (variantDef !== undefined && featureFlag.enabled) {\n if (variantDef.status_override === \"Enabled\") {\n result.enabled = true;\n } else if (variantDef.status_override === \"Disabled\") {\n result.enabled = false;\n }\n }\n\n // The callback will only be executed if telemetry is enabled for the feature flag\n if (featureFlag.telemetry?.enabled && this.#onFeatureEvaluated !== undefined) {\n this.#onFeatureEvaluated(result);\n }\n\n return result;\n }\n\n #getTargetingContext(context: unknown): ITargetingContext | undefined {\n let targetingContext: ITargetingContext | undefined = context as ITargetingContext;\n if (targetingContext?.userId === undefined &&\n targetingContext?.groups === undefined &&\n this.#targetingContextAccessor !== undefined) {\n targetingContext = this.#targetingContextAccessor.getTargetingContext();\n }\n return targetingContext;\n }\n}\n\nexport interface FeatureManagerOptions {\n /**\n * The custom filters to be used by the feature manager.\n */\n customFilters?: IFeatureFilter[];\n\n /**\n * The callback function that is called when a feature flag is evaluated.\n * The callback function is called only when telemetry is enabled for the feature flag.\n */\n onFeatureEvaluated?: (event: EvaluationResult) => void;\n\n /**\n * The accessor function that provides the @see ITargetingContext for targeting evaluation.\n */\n targetingContextAccessor?: ITargetingContextAccessor;\n}\n\nexport class EvaluationResult {\n constructor(\n // feature flag definition\n public readonly feature: FeatureFlag | undefined,\n\n // enabled state\n public enabled: boolean = false,\n\n // variant assignment\n public targetingId: string | undefined = undefined,\n public variant: Variant | undefined = undefined,\n public variantAssignmentReason: VariantAssignmentReason = VariantAssignmentReason.None\n ) { }\n}\n\nexport enum VariantAssignmentReason {\n /**\n * Variant allocation did not happen. No variant is assigned.\n */\n None = \"None\",\n\n /**\n * The default variant is assigned when a feature flag is disabled.\n */\n DefaultWhenDisabled = \"DefaultWhenDisabled\",\n\n /**\n * The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.\n */\n DefaultWhenEnabled = \"DefaultWhenEnabled\",\n\n /**\n * The variant is assigned because of the user allocation when a feature flag is enabled.\n */\n User = \"User\",\n\n /**\n * The variant is assigned because of the group allocation when a feature flag is enabled.\n */\n Group = \"Group\",\n\n /**\n * The variant is assigned because of the percentile allocation when a feature flag is enabled.\n */\n Percentile = \"Percentile\"\n}\n\n/**\n * Validates the format of the feature flag definition.\n *\n * FeatureFlag data objects are from IFeatureFlagProvider, depending on the implementation.\n * Thus the properties are not guaranteed to have the expected types.\n *\n * @param featureFlag The feature flag definition to validate.\n */\nfunction validateFeatureFlagFormat(featureFlag: any): void {\n if (featureFlag.enabled !== undefined && typeof featureFlag.enabled !== \"boolean\") {\n throw new Error(`Feature flag ${featureFlag.id} has an invalid 'enabled' value.`);\n }\n // TODO: add more validations.\n // TODO: should be moved to the feature flag provider.\n}\n\n/**\n * Try to get the variant assignment for the given variant name. If the variant is not found, override the reason with VariantAssignmentReason.None.\n *\n * @param featureFlag feature flag definition\n * @param variantName variant name\n * @param reason variant assignment reason\n * @returns variant assignment containing the variant definition and the reason\n */\nfunction getVariantAssignment(featureFlag: FeatureFlag, variantName: string, reason: VariantAssignmentReason): VariantAssignment {\n const variant = featureFlag.variants?.find(v => v.name == variantName);\n if (variant !== undefined) {\n return { variant, reason };\n } else {\n console.warn(`Variant ${variantName} not found for feature ${featureFlag.id}.`);\n return { variant: undefined, reason: VariantAssignmentReason.None };\n }\n}\n\ntype VariantAssignment = {\n variant: VariantDefinition | undefined;\n reason: VariantAssignmentReason;\n};\n"],"names":["TimeWindowFilter","TargetingFilter","isTargetedUser","VariantAssignmentReason","isTargetedGroup","isTargetedPercentile","Variant"],"mappings":"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"}
1
+ {"version":3,"file":"featureManager.js","sources":["../../src/featureManager.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { TimeWindowFilter } from \"./filter/timeWindowFilter.js\";\nimport { IFeatureFilter } from \"./filter/featureFilter.js\";\nimport { FeatureFlag, RequirementType, VariantDefinition } from \"./schema/model.js\";\nimport { IFeatureFlagProvider, IFeatureManager } from \"./model.js\";\nimport { TargetingFilter } from \"./filter/targetingFilter.js\";\nimport { Variant } from \"./variant/variant.js\";\nimport { ITargetingContext, ITargetingContextAccessor } from \"./common/targetingContext.js\";\nimport { isTargetedGroup, isTargetedPercentile, isTargetedUser } from \"./common/targetingEvaluator.js\";\n\nexport class FeatureManager implements IFeatureManager {\n readonly #provider: IFeatureFlagProvider;\n readonly #featureFilters: Map<string, IFeatureFilter> = new Map();\n readonly #onFeatureEvaluated?: (event: EvaluationResult) => void;\n readonly #targetingContextAccessor?: ITargetingContextAccessor;\n\n constructor(provider: IFeatureFlagProvider, options?: FeatureManagerOptions) {\n this.#provider = provider;\n this.#onFeatureEvaluated = options?.onFeatureEvaluated;\n this.#targetingContextAccessor = options?.targetingContextAccessor;\n\n const builtinFilters = [new TimeWindowFilter(), new TargetingFilter(options?.targetingContextAccessor)];\n // If a custom filter shares a name with an existing filter, the custom filter overrides the existing one.\n for (const filter of [...builtinFilters, ...(options?.customFilters ?? [])]) {\n this.#featureFilters.set(filter.name, filter);\n }\n }\n\n async listFeatureNames(): Promise<string[]> {\n const features = await this.#provider.getFeatureFlags();\n const featureNameSet = new Set(features.map((feature) => feature.id));\n return Array.from(featureNameSet);\n }\n\n // If multiple feature flags are found, the first one takes precedence.\n async isEnabled(featureName: string, context?: unknown): Promise<boolean> {\n const result = await this.#evaluateFeature(featureName, context);\n return result.enabled;\n }\n\n async getVariant(featureName: string, context?: ITargetingContext): Promise<Variant | undefined> {\n const result = await this.#evaluateFeature(featureName, context);\n return result.variant;\n }\n\n async #assignVariant(featureFlag: FeatureFlag, context: ITargetingContext): Promise<VariantAssignment> {\n // user allocation\n if (featureFlag.allocation?.user !== undefined) {\n for (const userAllocation of featureFlag.allocation.user) {\n if (isTargetedUser(context.userId, userAllocation.users)) {\n return getVariantAssignment(featureFlag, userAllocation.variant, VariantAssignmentReason.User);\n }\n }\n }\n\n // group allocation\n if (featureFlag.allocation?.group !== undefined) {\n for (const groupAllocation of featureFlag.allocation.group) {\n if (isTargetedGroup(context.groups, groupAllocation.groups)) {\n return getVariantAssignment(featureFlag, groupAllocation.variant, VariantAssignmentReason.Group);\n }\n }\n }\n\n // percentile allocation\n if (featureFlag.allocation?.percentile !== undefined) {\n for (const percentileAllocation of featureFlag.allocation.percentile) {\n const hint = featureFlag.allocation.seed ?? `allocation\\n${featureFlag.id}`;\n if (await isTargetedPercentile(context.userId, hint, percentileAllocation.from, percentileAllocation.to)) {\n return getVariantAssignment(featureFlag, percentileAllocation.variant, VariantAssignmentReason.Percentile);\n }\n }\n }\n\n return { variant: undefined, reason: VariantAssignmentReason.None };\n }\n\n async #isEnabled(featureFlag: FeatureFlag, appContext?: unknown): Promise<boolean> {\n if (featureFlag.enabled !== true) {\n // If the feature is not explicitly enabled, then it is disabled by default.\n return false;\n }\n\n const clientFilters = featureFlag.conditions?.client_filters;\n if (clientFilters === undefined || clientFilters.length <= 0) {\n // If there are no client filters, then the feature is enabled.\n return true;\n }\n\n const requirementType: RequirementType = featureFlag.conditions?.requirement_type ?? \"Any\"; // default to any.\n\n /**\n * While iterating through the client filters, we short-circuit the evaluation based on the requirement type.\n * - When requirement type is \"All\", the feature is enabled if all client filters are matched. If any client filter is not matched, the feature is disabled, otherwise it is enabled. `shortCircuitEvaluationResult` is false.\n * - When requirement type is \"Any\", the feature is enabled if any client filter is matched. If any client filter is matched, the feature is enabled, otherwise it is disabled. `shortCircuitEvaluationResult` is true.\n */\n const shortCircuitEvaluationResult: boolean = requirementType === \"Any\";\n\n for (const clientFilter of clientFilters) {\n const matchedFeatureFilter = this.#featureFilters.get(clientFilter.name);\n const contextWithFeatureName = { featureName: featureFlag.id, parameters: clientFilter.parameters };\n if (matchedFeatureFilter === undefined) {\n console.warn(`Feature filter ${clientFilter.name} is not found.`);\n return false;\n }\n if (await matchedFeatureFilter.evaluate(contextWithFeatureName, appContext) === shortCircuitEvaluationResult) {\n return shortCircuitEvaluationResult;\n }\n }\n\n // If we get here, then we have not found a client filter that matches the requirement type.\n return !shortCircuitEvaluationResult;\n }\n\n async #evaluateFeature(featureName: string, appContext: unknown): Promise<EvaluationResult> {\n const featureFlag = await this.#provider.getFeatureFlag(featureName);\n const result = new EvaluationResult(featureFlag);\n\n if (featureFlag === undefined) {\n return result;\n }\n\n // Ensure that the feature flag is in the correct format. Feature providers should validate the feature flags, but we do it here as a safeguard.\n // TODO: move to the feature flag provider implementation.\n validateFeatureFlagFormat(featureFlag);\n\n // Evaluate if the feature is enabled.\n result.enabled = await this.#isEnabled(featureFlag, appContext);\n\n // Get targeting context from the app context or the targeting context accessor\n const targetingContext = this.#getTargetingContext(appContext);\n result.targetingId = targetingContext?.userId;\n\n // Determine Variant\n let variantDef: VariantDefinition | undefined;\n let reason: VariantAssignmentReason = VariantAssignmentReason.None;\n\n // featureFlag.variant not empty\n if (featureFlag.variants !== undefined && featureFlag.variants.length > 0) {\n if (!result.enabled) {\n // not enabled, assign default if specified\n if (featureFlag.allocation?.default_when_disabled !== undefined) {\n variantDef = featureFlag.variants.find(v => v.name == featureFlag.allocation?.default_when_disabled);\n reason = VariantAssignmentReason.DefaultWhenDisabled;\n } else {\n // no default specified\n variantDef = undefined;\n reason = VariantAssignmentReason.DefaultWhenDisabled;\n }\n } else {\n // enabled, assign based on allocation\n if (targetingContext !== undefined && featureFlag.allocation !== undefined) {\n const variantAndReason = await this.#assignVariant(featureFlag, targetingContext);\n variantDef = variantAndReason.variant;\n reason = variantAndReason.reason;\n }\n\n // allocation failed, assign default if specified\n if (variantDef === undefined && reason === VariantAssignmentReason.None) {\n if (featureFlag.allocation?.default_when_enabled !== undefined) {\n variantDef = featureFlag.variants.find(v => v.name == featureFlag.allocation?.default_when_enabled);\n reason = VariantAssignmentReason.DefaultWhenEnabled;\n } else {\n variantDef = undefined;\n reason = VariantAssignmentReason.DefaultWhenEnabled;\n }\n }\n }\n }\n\n result.variant = variantDef !== undefined ? new Variant(variantDef.name, variantDef.configuration_value) : undefined;\n result.variantAssignmentReason = reason;\n\n // Status override for isEnabled\n if (variantDef !== undefined && featureFlag.enabled) {\n if (variantDef.status_override === \"Enabled\") {\n result.enabled = true;\n } else if (variantDef.status_override === \"Disabled\") {\n result.enabled = false;\n }\n }\n\n // The callback will only be executed if telemetry is enabled for the feature flag\n if (featureFlag.telemetry?.enabled && this.#onFeatureEvaluated !== undefined) {\n this.#onFeatureEvaluated(result);\n }\n\n return result;\n }\n\n #getTargetingContext(context: unknown): ITargetingContext | undefined {\n let targetingContext: ITargetingContext | undefined = context as ITargetingContext;\n if (targetingContext?.userId === undefined &&\n targetingContext?.groups === undefined &&\n this.#targetingContextAccessor !== undefined) {\n targetingContext = this.#targetingContextAccessor.getTargetingContext();\n }\n return targetingContext;\n }\n}\n\nexport interface FeatureManagerOptions {\n /**\n * The custom filters to be used by the feature manager.\n */\n customFilters?: IFeatureFilter[];\n\n /**\n * The callback function that is called when a feature flag is evaluated.\n * The callback function is called only when telemetry is enabled for the feature flag.\n */\n onFeatureEvaluated?: (event: EvaluationResult) => void;\n\n /**\n * The accessor function that provides the @see ITargetingContext for targeting evaluation.\n */\n targetingContextAccessor?: ITargetingContextAccessor;\n}\n\nexport class EvaluationResult {\n constructor(\n // feature flag definition\n public readonly feature: FeatureFlag | undefined,\n\n // enabled state\n public enabled: boolean = false,\n\n // variant assignment\n public targetingId: string | undefined = undefined,\n public variant: Variant | undefined = undefined,\n public variantAssignmentReason: VariantAssignmentReason = VariantAssignmentReason.None\n ) { }\n}\n\nexport enum VariantAssignmentReason {\n /**\n * Variant allocation did not happen. No variant is assigned.\n */\n None = \"None\",\n\n /**\n * The default variant is assigned when a feature flag is disabled.\n */\n DefaultWhenDisabled = \"DefaultWhenDisabled\",\n\n /**\n * The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.\n */\n DefaultWhenEnabled = \"DefaultWhenEnabled\",\n\n /**\n * The variant is assigned because of the user allocation when a feature flag is enabled.\n */\n User = \"User\",\n\n /**\n * The variant is assigned because of the group allocation when a feature flag is enabled.\n */\n Group = \"Group\",\n\n /**\n * The variant is assigned because of the percentile allocation when a feature flag is enabled.\n */\n Percentile = \"Percentile\"\n}\n\n/**\n * Validates the format of the feature flag definition.\n *\n * FeatureFlag data objects are from IFeatureFlagProvider, depending on the implementation.\n * Thus the properties are not guaranteed to have the expected types.\n *\n * @param featureFlag The feature flag definition to validate.\n */\nfunction validateFeatureFlagFormat(featureFlag: any): void {\n if (featureFlag.enabled !== undefined && typeof featureFlag.enabled !== \"boolean\") {\n throw new Error(`Feature flag ${featureFlag.id} has an invalid 'enabled' value.`);\n }\n // TODO: add more validations.\n // TODO: should be moved to the feature flag provider.\n}\n\n/**\n * Try to get the variant assignment for the given variant name. If the variant is not found, override the reason with VariantAssignmentReason.None.\n *\n * @param featureFlag feature flag definition\n * @param variantName variant name\n * @param reason variant assignment reason\n * @returns variant assignment containing the variant definition and the reason\n */\nfunction getVariantAssignment(featureFlag: FeatureFlag, variantName: string, reason: VariantAssignmentReason): VariantAssignment {\n const variant = featureFlag.variants?.find(v => v.name == variantName);\n if (variant !== undefined) {\n return { variant, reason };\n } else {\n console.warn(`Variant ${variantName} not found for feature ${featureFlag.id}.`);\n return { variant: undefined, reason: VariantAssignmentReason.None };\n }\n}\n\ntype VariantAssignment = {\n variant: VariantDefinition | undefined;\n reason: VariantAssignmentReason;\n};\n"],"names":["TimeWindowFilter","TargetingFilter","isTargetedUser","VariantAssignmentReason","isTargetedGroup","isTargetedPercentile","Variant"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"featureProvider.js","sources":["../../src/featureProvider.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { IGettable } from \"./gettable.js\";\nimport { FeatureFlag, FeatureManagementConfiguration, FEATURE_MANAGEMENT_KEY, FEATURE_FLAGS_KEY } from \"./schema/model.js\";\nimport { IFeatureFlagProvider } from \"./model.js\";\nimport { validateFeatureFlag } from \"./schema/validator.js\";\n\n/**\n * A feature flag provider that uses a map-like configuration to provide feature flags.\n */\nexport class ConfigurationMapFeatureFlagProvider implements IFeatureFlagProvider {\n #configuration: IGettable;\n\n constructor(configuration: IGettable) {\n this.#configuration = configuration;\n }\n async getFeatureFlag(featureName: string): Promise<FeatureFlag | undefined> {\n const featureConfig = this.#configuration.get<FeatureManagementConfiguration>(FEATURE_MANAGEMENT_KEY);\n const featureFlag = featureConfig?.[FEATURE_FLAGS_KEY]?.findLast((feature) => feature.id === featureName);\n validateFeatureFlag(featureFlag);\n return featureFlag;\n }\n\n async getFeatureFlags(): Promise<FeatureFlag[]> {\n const featureConfig = this.#configuration.get<FeatureManagementConfiguration>(FEATURE_MANAGEMENT_KEY);\n const featureFlags = featureConfig?.[FEATURE_FLAGS_KEY] ?? [];\n featureFlags.forEach(featureFlag => {\n validateFeatureFlag(featureFlag);\n });\n return featureFlags;\n }\n}\n\n/**\n * A feature flag provider that uses an object-like configuration to provide feature flags.\n */\nexport class ConfigurationObjectFeatureFlagProvider implements IFeatureFlagProvider {\n #configuration: Record<string, unknown>;\n\n constructor(configuration: Record<string, unknown>) {\n this.#configuration = configuration;\n }\n\n async getFeatureFlag(featureName: string): Promise<FeatureFlag | undefined> {\n const featureFlags = this.#configuration[FEATURE_MANAGEMENT_KEY]?.[FEATURE_FLAGS_KEY];\n const featureFlag = featureFlags?.findLast((feature: FeatureFlag) => feature.id === featureName);\n validateFeatureFlag(featureFlag);\n return featureFlag;\n }\n\n async getFeatureFlags(): Promise<FeatureFlag[]> {\n const featureFlags = this.#configuration[FEATURE_MANAGEMENT_KEY]?.[FEATURE_FLAGS_KEY] ?? [];\n featureFlags.forEach(featureFlag => {\n validateFeatureFlag(featureFlag);\n });\n return featureFlags;\n }\n}\n"],"names":["FEATURE_MANAGEMENT_KEY","FEATURE_FLAGS_KEY","validateFeatureFlag"],"mappings":";;;;;AAAA;AACA;AAOA;;AAEG;MACU,mCAAmC,CAAA;AAC5C,IAAA,cAAc,CAAY;AAE1B,IAAA,WAAA,CAAY,aAAwB,EAAA;AAChC,QAAA,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;KACvC;IACD,MAAM,cAAc,CAAC,WAAmB,EAAA;QACpC,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAiCA,4BAAsB,CAAC,CAAC;QACtG,MAAM,WAAW,GAAG,aAAa,GAAGC,uBAAiB,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,KAAK,WAAW,CAAC,CAAC;QAC1GC,6BAAmB,CAAC,WAAW,CAAC,CAAC;AACjC,QAAA,OAAO,WAAW,CAAC;KACtB;AAED,IAAA,MAAM,eAAe,GAAA;QACjB,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAiCF,4BAAsB,CAAC,CAAC;QACtG,MAAM,YAAY,GAAG,aAAa,GAAGC,uBAAiB,CAAC,IAAI,EAAE,CAAC;AAC9D,QAAA,YAAY,CAAC,OAAO,CAAC,WAAW,IAAG;YAC/BC,6BAAmB,CAAC,WAAW,CAAC,CAAC;AACrC,SAAC,CAAC,CAAC;AACH,QAAA,OAAO,YAAY,CAAC;KACvB;AACJ,CAAA;AAED;;AAEG;MACU,sCAAsC,CAAA;AAC/C,IAAA,cAAc,CAA0B;AAExC,IAAA,WAAA,CAAY,aAAsC,EAAA;AAC9C,QAAA,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;KACvC;IAED,MAAM,cAAc,CAAC,WAAmB,EAAA;AACpC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAACF,4BAAsB,CAAC,GAAGC,uBAAiB,CAAC,CAAC;AACtF,QAAA,MAAM,WAAW,GAAG,YAAY,EAAE,QAAQ,CAAC,CAAC,OAAoB,KAAK,OAAO,CAAC,EAAE,KAAK,WAAW,CAAC,CAAC;QACjGC,6BAAmB,CAAC,WAAW,CAAC,CAAC;AACjC,QAAA,OAAO,WAAW,CAAC;KACtB;AAED,IAAA,MAAM,eAAe,GAAA;AACjB,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAACF,4BAAsB,CAAC,GAAGC,uBAAiB,CAAC,IAAI,EAAE,CAAC;AAC5F,QAAA,YAAY,CAAC,OAAO,CAAC,WAAW,IAAG;YAC/BC,6BAAmB,CAAC,WAAW,CAAC,CAAC;AACrC,SAAC,CAAC,CAAC;AACH,QAAA,OAAO,YAAY,CAAC;KACvB;AACJ;;;;;"}
1
+ {"version":3,"file":"featureProvider.js","sources":["../../src/featureProvider.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { IGettable } from \"./gettable.js\";\nimport { FeatureFlag, FeatureManagementConfiguration, FEATURE_MANAGEMENT_KEY, FEATURE_FLAGS_KEY } from \"./schema/model.js\";\nimport { IFeatureFlagProvider } from \"./model.js\";\nimport { validateFeatureFlag } from \"./schema/validator.js\";\n\n/**\n * A feature flag provider that uses a map-like configuration to provide feature flags.\n */\nexport class ConfigurationMapFeatureFlagProvider implements IFeatureFlagProvider {\n #configuration: IGettable;\n\n constructor(configuration: IGettable) {\n this.#configuration = configuration;\n }\n async getFeatureFlag(featureName: string): Promise<FeatureFlag | undefined> {\n const featureConfig = this.#configuration.get<FeatureManagementConfiguration>(FEATURE_MANAGEMENT_KEY);\n const featureFlag = featureConfig?.[FEATURE_FLAGS_KEY]?.findLast((feature) => feature.id === featureName);\n validateFeatureFlag(featureFlag);\n return featureFlag;\n }\n\n async getFeatureFlags(): Promise<FeatureFlag[]> {\n const featureConfig = this.#configuration.get<FeatureManagementConfiguration>(FEATURE_MANAGEMENT_KEY);\n const featureFlags = featureConfig?.[FEATURE_FLAGS_KEY] ?? [];\n featureFlags.forEach(featureFlag => {\n validateFeatureFlag(featureFlag);\n });\n return featureFlags;\n }\n}\n\n/**\n * A feature flag provider that uses an object-like configuration to provide feature flags.\n */\nexport class ConfigurationObjectFeatureFlagProvider implements IFeatureFlagProvider {\n #configuration: Record<string, unknown>;\n\n constructor(configuration: Record<string, unknown>) {\n this.#configuration = configuration;\n }\n\n async getFeatureFlag(featureName: string): Promise<FeatureFlag | undefined> {\n const featureFlags = this.#configuration[FEATURE_MANAGEMENT_KEY]?.[FEATURE_FLAGS_KEY];\n const featureFlag = featureFlags?.findLast((feature: FeatureFlag) => feature.id === featureName);\n validateFeatureFlag(featureFlag);\n return featureFlag;\n }\n\n async getFeatureFlags(): Promise<FeatureFlag[]> {\n const featureFlags = this.#configuration[FEATURE_MANAGEMENT_KEY]?.[FEATURE_FLAGS_KEY] ?? [];\n featureFlags.forEach(featureFlag => {\n validateFeatureFlag(featureFlag);\n });\n return featureFlags;\n }\n}\n"],"names":["FEATURE_MANAGEMENT_KEY","FEATURE_FLAGS_KEY","validateFeatureFlag"],"mappings":";;;;;AAAA;AACA;AAOA;;AAEG;MACU,mCAAmC,CAAA;AAC5C,IAAA,cAAc;AAEd,IAAA,WAAA,CAAY,aAAwB,EAAA;AAChC,QAAA,IAAI,CAAC,cAAc,GAAG,aAAa;IACvC;IACA,MAAM,cAAc,CAAC,WAAmB,EAAA;QACpC,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAiCA,4BAAsB,CAAC;QACrG,MAAM,WAAW,GAAG,aAAa,GAAGC,uBAAiB,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,KAAK,WAAW,CAAC;QACzGC,6BAAmB,CAAC,WAAW,CAAC;AAChC,QAAA,OAAO,WAAW;IACtB;AAEA,IAAA,MAAM,eAAe,GAAA;QACjB,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAiCF,4BAAsB,CAAC;QACrG,MAAM,YAAY,GAAG,aAAa,GAAGC,uBAAiB,CAAC,IAAI,EAAE;AAC7D,QAAA,YAAY,CAAC,OAAO,CAAC,WAAW,IAAG;YAC/BC,6BAAmB,CAAC,WAAW,CAAC;AACpC,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,YAAY;IACvB;AACH;AAED;;AAEG;MACU,sCAAsC,CAAA;AAC/C,IAAA,cAAc;AAEd,IAAA,WAAA,CAAY,aAAsC,EAAA;AAC9C,QAAA,IAAI,CAAC,cAAc,GAAG,aAAa;IACvC;IAEA,MAAM,cAAc,CAAC,WAAmB,EAAA;AACpC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAACF,4BAAsB,CAAC,GAAGC,uBAAiB,CAAC;AACrF,QAAA,MAAM,WAAW,GAAG,YAAY,EAAE,QAAQ,CAAC,CAAC,OAAoB,KAAK,OAAO,CAAC,EAAE,KAAK,WAAW,CAAC;QAChGC,6BAAmB,CAAC,WAAW,CAAC;AAChC,QAAA,OAAO,WAAW;IACtB;AAEA,IAAA,MAAM,eAAe,GAAA;AACjB,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAACF,4BAAsB,CAAC,GAAGC,uBAAiB,CAAC,IAAI,EAAE;AAC3F,QAAA,YAAY,CAAC,OAAO,CAAC,WAAW,IAAG;YAC/BC,6BAAmB,CAAC,WAAW,CAAC;AACpC,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,YAAY;IACvB;AACH;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"evaluator.js","sources":["../../../../src/filter/recurrence/evaluator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { RecurrenceSpec, RecurrencePatternType, RecurrenceRangeType, DAYS_PER_WEEK, ONE_DAY_IN_MILLISECONDS } from \"./model.js\";\nimport { calculateWeeklyDayOffset, sortDaysOfWeek, getDayOfWeek, addDays } from \"./utils.js\";\n\ntype RecurrenceState = {\n previousOccurrence: Date;\n numberOfOccurrences: number;\n}\n\n/**\n * Checks if a provided datetime is within any recurring time window specified by the recurrence information\n * @param time A datetime\n * @param recurrenceSpec The recurrence spcification\n * @returns True if the given time is within any recurring time window; otherwise, false\n */\nexport function matchRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): boolean {\n const recurrenceState = findPreviousRecurrence(time, recurrenceSpec);\n if (recurrenceState) {\n return time.getTime() < recurrenceState.previousOccurrence.getTime() + recurrenceSpec.duration;\n }\n return false;\n}\n\n/**\n * Finds the closest previous recurrence occurrence before the given time according to the recurrence information\n * @param time A datetime\n * @param recurrenceSpec The recurrence specification\n * @returns The recurrence state if any previous occurrence is found; otherwise, undefined\n */\nfunction findPreviousRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): RecurrenceState | undefined {\n if (time < recurrenceSpec.startTime) {\n return undefined;\n }\n let result: RecurrenceState;\n const pattern = recurrenceSpec.pattern;\n if (pattern.type === RecurrencePatternType.Daily) {\n result = findPreviousDailyRecurrence(time, recurrenceSpec);\n } else if (pattern.type === RecurrencePatternType.Weekly) {\n result = findPreviousWeeklyRecurrence(time, recurrenceSpec);\n } else {\n throw new Error(\"Unsupported recurrence pattern type.\");\n }\n const { previousOccurrence, numberOfOccurrences } = result;\n\n const range = recurrenceSpec.range;\n if (range.type === RecurrenceRangeType.EndDate) {\n if (previousOccurrence > range.endDate!) {\n return undefined;\n }\n } else if (range.type === RecurrenceRangeType.Numbered) {\n if (numberOfOccurrences > range.numberOfOccurrences!) {\n return undefined;\n }\n }\n return result;\n}\n\nfunction findPreviousDailyRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): RecurrenceState {\n const startTime = recurrenceSpec.startTime;\n const timeGap = time.getTime() - startTime.getTime();\n const pattern = recurrenceSpec.pattern;\n const numberOfIntervals = Math.floor(timeGap / (pattern.interval * ONE_DAY_IN_MILLISECONDS));\n return {\n previousOccurrence: addDays(startTime, numberOfIntervals * pattern.interval),\n numberOfOccurrences: numberOfIntervals + 1\n };\n}\n\nfunction findPreviousWeeklyRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): RecurrenceState {\n /*\n * Algorithm:\n * 1. first find day 0 (d0), it's the day representing the start day on the week of `Start`.\n * 2. find start day of the most recent occurring week d0 + floor((time - d0) / (interval * 7)) * (interval * 7)\n * 3. if that's over 7 days ago, then previous occurence is the day with the max offset of the last occurring week\n * 4. if gotten this far, then the current week is the most recent occurring week:\n i. if time > day with min offset, then previous occurence is the day with max offset less than current\n ii. if time < day with min offset, then previous occurence is the day with the max offset of previous occurring week\n */\n const startTime = recurrenceSpec.startTime;\n const startDay = getDayOfWeek(startTime, recurrenceSpec.timezoneOffset);\n const pattern = recurrenceSpec.pattern;\n const sortedDaysOfWeek = sortDaysOfWeek(pattern.daysOfWeek!, pattern.firstDayOfWeek!);\n\n /*\n * Example:\n * startTime = 2024-12-11 (Tue)\n * pattern.interval = 2 pattern.firstDayOfWeek = Sun pattern.daysOfWeek = [Wed, Sun]\n * sortedDaysOfWeek = [Sun, Wed]\n * firstDayofStartWeek = 2024-12-08 (Sun)\n *\n * time = 2024-12-23 (Mon) timeGap = 15 days\n * the most recent occurring week: 2024-12-22 ~ 2024-12-28\n * number of intervals before the most recent occurring week = 15 / (2 * 7) = 1 (2024-12-08 ~ 2023-12-21)\n * number of occurrences before the most recent occurring week = 1 * 2 - 1 = 1 (2024-12-11)\n * firstDayOfLastOccurringWeek = 2024-12-22\n */\n const firstDayofStartWeek = addDays(startTime, -calculateWeeklyDayOffset(startDay, pattern.firstDayOfWeek!));\n const timeGap = time.getTime() - firstDayofStartWeek.getTime();\n // number of intervals before the most recent occurring week\n const numberOfIntervals = Math.floor(timeGap / (pattern.interval * DAYS_PER_WEEK * ONE_DAY_IN_MILLISECONDS));\n // number of occurrences before the most recent occurring week, it is possible to be negative\n let numberOfOccurrences = numberOfIntervals * sortedDaysOfWeek.length - sortedDaysOfWeek.indexOf(startDay);\n const firstDayOfLatestOccurringWeek = addDays(firstDayofStartWeek, numberOfIntervals * pattern.interval * DAYS_PER_WEEK);\n\n // the current time is out of the last occurring week\n if (time > addDays(firstDayOfLatestOccurringWeek, DAYS_PER_WEEK)) {\n numberOfOccurrences += sortDaysOfWeek.length;\n // day with max offset in the last occurring week\n const previousOccurrence = addDays(firstDayOfLatestOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek.at(-1)!, pattern.firstDayOfWeek!));\n return {\n previousOccurrence: previousOccurrence,\n numberOfOccurrences: numberOfOccurrences\n };\n }\n\n let dayWithMinOffset = addDays(firstDayOfLatestOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek[0], pattern.firstDayOfWeek!));\n if (dayWithMinOffset < startTime) {\n numberOfOccurrences = 0;\n dayWithMinOffset = startTime;\n }\n let previousOccurrence;\n if (time >= dayWithMinOffset) {\n // the previous occurence is the day with max offset less than current\n previousOccurrence = dayWithMinOffset;\n numberOfOccurrences += 1;\n const dayWithMinOffsetIndex = sortedDaysOfWeek.indexOf(getDayOfWeek(dayWithMinOffset, recurrenceSpec.timezoneOffset));\n for (let i = dayWithMinOffsetIndex + 1; i < sortedDaysOfWeek.length; i++) {\n const day = addDays(firstDayOfLatestOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek[i], pattern.firstDayOfWeek!));\n if (time < day) {\n break;\n }\n previousOccurrence = day;\n numberOfOccurrences += 1;\n }\n } else {\n const firstDayOfPreviousOccurringWeek = addDays(firstDayOfLatestOccurringWeek, -pattern.interval * DAYS_PER_WEEK);\n // the previous occurence is the day with the max offset of previous occurring week\n previousOccurrence = addDays(firstDayOfPreviousOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek.at(-1)!, pattern.firstDayOfWeek!));\n }\n return {\n previousOccurrence: previousOccurrence,\n numberOfOccurrences: numberOfOccurrences\n };\n}\n"],"names":["RecurrencePatternType","RecurrenceRangeType","ONE_DAY_IN_MILLISECONDS","addDays","getDayOfWeek","sortDaysOfWeek","calculateWeeklyDayOffset","DAYS_PER_WEEK"],"mappings":"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"}
1
+ {"version":3,"file":"evaluator.js","sources":["../../../../src/filter/recurrence/evaluator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { RecurrenceSpec, RecurrencePatternType, RecurrenceRangeType, DAYS_PER_WEEK, ONE_DAY_IN_MILLISECONDS } from \"./model.js\";\nimport { calculateWeeklyDayOffset, sortDaysOfWeek, getDayOfWeek, addDays } from \"./utils.js\";\n\ntype RecurrenceState = {\n previousOccurrence: Date;\n numberOfOccurrences: number;\n}\n\n/**\n * Checks if a provided datetime is within any recurring time window specified by the recurrence information\n * @param time A datetime\n * @param recurrenceSpec The recurrence spcification\n * @returns True if the given time is within any recurring time window; otherwise, false\n */\nexport function matchRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): boolean {\n const recurrenceState = findPreviousRecurrence(time, recurrenceSpec);\n if (recurrenceState) {\n return time.getTime() < recurrenceState.previousOccurrence.getTime() + recurrenceSpec.duration;\n }\n return false;\n}\n\n/**\n * Finds the closest previous recurrence occurrence before the given time according to the recurrence information\n * @param time A datetime\n * @param recurrenceSpec The recurrence specification\n * @returns The recurrence state if any previous occurrence is found; otherwise, undefined\n */\nfunction findPreviousRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): RecurrenceState | undefined {\n if (time < recurrenceSpec.startTime) {\n return undefined;\n }\n let result: RecurrenceState;\n const pattern = recurrenceSpec.pattern;\n if (pattern.type === RecurrencePatternType.Daily) {\n result = findPreviousDailyRecurrence(time, recurrenceSpec);\n } else if (pattern.type === RecurrencePatternType.Weekly) {\n result = findPreviousWeeklyRecurrence(time, recurrenceSpec);\n } else {\n throw new Error(\"Unsupported recurrence pattern type.\");\n }\n const { previousOccurrence, numberOfOccurrences } = result;\n\n const range = recurrenceSpec.range;\n if (range.type === RecurrenceRangeType.EndDate) {\n if (previousOccurrence > range.endDate!) {\n return undefined;\n }\n } else if (range.type === RecurrenceRangeType.Numbered) {\n if (numberOfOccurrences > range.numberOfOccurrences!) {\n return undefined;\n }\n }\n return result;\n}\n\nfunction findPreviousDailyRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): RecurrenceState {\n const startTime = recurrenceSpec.startTime;\n const timeGap = time.getTime() - startTime.getTime();\n const pattern = recurrenceSpec.pattern;\n const numberOfIntervals = Math.floor(timeGap / (pattern.interval * ONE_DAY_IN_MILLISECONDS));\n return {\n previousOccurrence: addDays(startTime, numberOfIntervals * pattern.interval),\n numberOfOccurrences: numberOfIntervals + 1\n };\n}\n\nfunction findPreviousWeeklyRecurrence(time: Date, recurrenceSpec: RecurrenceSpec): RecurrenceState {\n /*\n * Algorithm:\n * 1. first find day 0 (d0), it's the day representing the start day on the week of `Start`.\n * 2. find start day of the most recent occurring week d0 + floor((time - d0) / (interval * 7)) * (interval * 7)\n * 3. if that's over 7 days ago, then previous occurence is the day with the max offset of the last occurring week\n * 4. if gotten this far, then the current week is the most recent occurring week:\n i. if time > day with min offset, then previous occurence is the day with max offset less than current\n ii. if time < day with min offset, then previous occurence is the day with the max offset of previous occurring week\n */\n const startTime = recurrenceSpec.startTime;\n const startDay = getDayOfWeek(startTime, recurrenceSpec.timezoneOffset);\n const pattern = recurrenceSpec.pattern;\n const sortedDaysOfWeek = sortDaysOfWeek(pattern.daysOfWeek!, pattern.firstDayOfWeek!);\n\n /*\n * Example:\n * startTime = 2024-12-11 (Tue)\n * pattern.interval = 2 pattern.firstDayOfWeek = Sun pattern.daysOfWeek = [Wed, Sun]\n * sortedDaysOfWeek = [Sun, Wed]\n * firstDayofStartWeek = 2024-12-08 (Sun)\n *\n * time = 2024-12-23 (Mon) timeGap = 15 days\n * the most recent occurring week: 2024-12-22 ~ 2024-12-28\n * number of intervals before the most recent occurring week = 15 / (2 * 7) = 1 (2024-12-08 ~ 2023-12-21)\n * number of occurrences before the most recent occurring week = 1 * 2 - 1 = 1 (2024-12-11)\n * firstDayOfLastOccurringWeek = 2024-12-22\n */\n const firstDayofStartWeek = addDays(startTime, -calculateWeeklyDayOffset(startDay, pattern.firstDayOfWeek!));\n const timeGap = time.getTime() - firstDayofStartWeek.getTime();\n // number of intervals before the most recent occurring week\n const numberOfIntervals = Math.floor(timeGap / (pattern.interval * DAYS_PER_WEEK * ONE_DAY_IN_MILLISECONDS));\n // number of occurrences before the most recent occurring week, it is possible to be negative\n let numberOfOccurrences = numberOfIntervals * sortedDaysOfWeek.length - sortedDaysOfWeek.indexOf(startDay);\n const firstDayOfLatestOccurringWeek = addDays(firstDayofStartWeek, numberOfIntervals * pattern.interval * DAYS_PER_WEEK);\n\n // the current time is out of the last occurring week\n if (time > addDays(firstDayOfLatestOccurringWeek, DAYS_PER_WEEK)) {\n numberOfOccurrences += sortDaysOfWeek.length;\n // day with max offset in the last occurring week\n const previousOccurrence = addDays(firstDayOfLatestOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek.at(-1)!, pattern.firstDayOfWeek!));\n return {\n previousOccurrence: previousOccurrence,\n numberOfOccurrences: numberOfOccurrences\n };\n }\n\n let dayWithMinOffset = addDays(firstDayOfLatestOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek[0], pattern.firstDayOfWeek!));\n if (dayWithMinOffset < startTime) {\n numberOfOccurrences = 0;\n dayWithMinOffset = startTime;\n }\n let previousOccurrence;\n if (time >= dayWithMinOffset) {\n // the previous occurence is the day with max offset less than current\n previousOccurrence = dayWithMinOffset;\n numberOfOccurrences += 1;\n const dayWithMinOffsetIndex = sortedDaysOfWeek.indexOf(getDayOfWeek(dayWithMinOffset, recurrenceSpec.timezoneOffset));\n for (let i = dayWithMinOffsetIndex + 1; i < sortedDaysOfWeek.length; i++) {\n const day = addDays(firstDayOfLatestOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek[i], pattern.firstDayOfWeek!));\n if (time < day) {\n break;\n }\n previousOccurrence = day;\n numberOfOccurrences += 1;\n }\n } else {\n const firstDayOfPreviousOccurringWeek = addDays(firstDayOfLatestOccurringWeek, -pattern.interval * DAYS_PER_WEEK);\n // the previous occurence is the day with the max offset of previous occurring week\n previousOccurrence = addDays(firstDayOfPreviousOccurringWeek, calculateWeeklyDayOffset(sortedDaysOfWeek.at(-1)!, pattern.firstDayOfWeek!));\n }\n return {\n previousOccurrence: previousOccurrence,\n numberOfOccurrences: numberOfOccurrences\n };\n}\n"],"names":["RecurrencePatternType","RecurrenceRangeType","ONE_DAY_IN_MILLISECONDS","addDays","getDayOfWeek","sortDaysOfWeek","calculateWeeklyDayOffset","DAYS_PER_WEEK"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sources":["../../../../src/filter/recurrence/model.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nexport const DAYS_PER_WEEK = 7;\nexport const ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;\n\nexport enum DayOfWeek {\n Sunday = 0,\n Monday = 1,\n Tuesday = 2,\n Wednesday = 3,\n Thursday = 4,\n Friday = 5,\n Saturday = 6\n}\n\n/**\n * The recurrence pattern describes the frequency by which the time window repeats\n */\nexport enum RecurrencePatternType {\n /**\n * The pattern where the time window will repeat based on the number of days specified by interval between occurrences\n */\n Daily,\n /**\n * The pattern where the time window will repeat on the same day or days of the week, based on the number of weeks between each set of occurrences\n */\n Weekly\n}\n\n/**\n * The recurrence range specifies the date range over which the time window repeats\n */\nexport enum RecurrenceRangeType {\n /**\n * The recurrence has no end and repeats on all the days that fit the corresponding pattern\n */\n NoEnd,\n /**\n * The recurrence repeats on all the days that fit the corresponding pattern until or on the specified end date\n */\n EndDate,\n /**\n * The recurrence repeats for the specified number of occurrences that match the pattern\n */\n Numbered\n}\n\n/**\n * The recurrence pattern describes the frequency by which the time window repeats\n */\nexport type RecurrencePattern = {\n /**\n * The type of the recurrence pattern\n */\n type: RecurrencePatternType;\n /**\n * The number of units between occurrences, where units can be in days or weeks, depending on the pattern type\n */\n interval: number;\n /**\n * The days of the week when the time window occurs, which is only applicable for 'Weekly' pattern\n */\n daysOfWeek?: DayOfWeek[];\n /**\n * The first day of the week, which is only applicable for 'Weekly' pattern\n */\n firstDayOfWeek?: DayOfWeek;\n};\n\n/**\n * The recurrence range describes a date range over which the time window repeats\n */\nexport type RecurrenceRange = {\n /**\n * The type of the recurrence range\n */\n type: RecurrenceRangeType;\n /**\n * The date to stop applying the recurrence pattern, which is only applicable for 'EndDate' range\n */\n endDate?: Date;\n /**\n * The number of times to repeat the time window, which is only applicable for 'Numbered' range\n */\n numberOfOccurrences?: number;\n};\n\n/**\n * Specification defines the recurring time window\n */\nexport type RecurrenceSpec = {\n /**\n * The start time of the first/base time window\n */\n startTime: Date;\n /**\n * The duration of each time window in milliseconds\n */\n duration: number;\n /**\n * The recurrence pattern\n */\n pattern: RecurrencePattern;\n /**\n * The recurrence range\n */\n range: RecurrenceRange;\n /**\n * The timezone offset in milliseconds, which helps to determine the day of week of a given date\n */\n timezoneOffset: number;\n};\n"],"names":["DayOfWeek","RecurrencePatternType","RecurrenceRangeType"],"mappings":";;AAAA;AACA;AAEO,MAAM,aAAa,GAAG,EAAE;AAClB,MAAA,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK;AAE/CA,2BAQX;AARD,CAAA,UAAY,SAAS,EAAA;AACjB,IAAA,SAAA,CAAA,SAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAU,CAAA;AACV,IAAA,SAAA,CAAA,SAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAU,CAAA;AACV,IAAA,SAAA,CAAA,SAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAW,CAAA;AACX,IAAA,SAAA,CAAA,SAAA,CAAA,WAAA,CAAA,GAAA,CAAA,CAAA,GAAA,WAAa,CAAA;AACb,IAAA,SAAA,CAAA,SAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAY,CAAA;AACZ,IAAA,SAAA,CAAA,SAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAU,CAAA;AACV,IAAA,SAAA,CAAA,SAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAY,CAAA;AAChB,CAAC,EARWA,iBAAS,KAATA,iBAAS,GAQpB,EAAA,CAAA,CAAA,CAAA;AAED;;AAEG;AACSC,uCASX;AATD,CAAA,UAAY,qBAAqB,EAAA;AAC7B;;AAEG;AACH,IAAA,qBAAA,CAAA,qBAAA,CAAA,OAAA,CAAA,GAAA,CAAA,CAAA,GAAA,OAAK,CAAA;AACL;;AAEG;AACH,IAAA,qBAAA,CAAA,qBAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAM,CAAA;AACV,CAAC,EATWA,6BAAqB,KAArBA,6BAAqB,GAShC,EAAA,CAAA,CAAA,CAAA;AAED;;AAEG;AACSC,qCAaX;AAbD,CAAA,UAAY,mBAAmB,EAAA;AAC3B;;AAEG;AACH,IAAA,mBAAA,CAAA,mBAAA,CAAA,OAAA,CAAA,GAAA,CAAA,CAAA,GAAA,OAAK,CAAA;AACL;;AAEG;AACH,IAAA,mBAAA,CAAA,mBAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAO,CAAA;AACP;;AAEG;AACH,IAAA,mBAAA,CAAA,mBAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAQ,CAAA;AACZ,CAAC,EAbWA,2BAAmB,KAAnBA,2BAAmB,GAa9B,EAAA,CAAA,CAAA;;;;;"}
1
+ {"version":3,"file":"model.js","sources":["../../../../src/filter/recurrence/model.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nexport const DAYS_PER_WEEK = 7;\nexport const ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;\n\nexport enum DayOfWeek {\n Sunday = 0,\n Monday = 1,\n Tuesday = 2,\n Wednesday = 3,\n Thursday = 4,\n Friday = 5,\n Saturday = 6\n}\n\n/**\n * The recurrence pattern describes the frequency by which the time window repeats\n */\nexport enum RecurrencePatternType {\n /**\n * The pattern where the time window will repeat based on the number of days specified by interval between occurrences\n */\n Daily,\n /**\n * The pattern where the time window will repeat on the same day or days of the week, based on the number of weeks between each set of occurrences\n */\n Weekly\n}\n\n/**\n * The recurrence range specifies the date range over which the time window repeats\n */\nexport enum RecurrenceRangeType {\n /**\n * The recurrence has no end and repeats on all the days that fit the corresponding pattern\n */\n NoEnd,\n /**\n * The recurrence repeats on all the days that fit the corresponding pattern until or on the specified end date\n */\n EndDate,\n /**\n * The recurrence repeats for the specified number of occurrences that match the pattern\n */\n Numbered\n}\n\n/**\n * The recurrence pattern describes the frequency by which the time window repeats\n */\nexport type RecurrencePattern = {\n /**\n * The type of the recurrence pattern\n */\n type: RecurrencePatternType;\n /**\n * The number of units between occurrences, where units can be in days or weeks, depending on the pattern type\n */\n interval: number;\n /**\n * The days of the week when the time window occurs, which is only applicable for 'Weekly' pattern\n */\n daysOfWeek?: DayOfWeek[];\n /**\n * The first day of the week, which is only applicable for 'Weekly' pattern\n */\n firstDayOfWeek?: DayOfWeek;\n};\n\n/**\n * The recurrence range describes a date range over which the time window repeats\n */\nexport type RecurrenceRange = {\n /**\n * The type of the recurrence range\n */\n type: RecurrenceRangeType;\n /**\n * The date to stop applying the recurrence pattern, which is only applicable for 'EndDate' range\n */\n endDate?: Date;\n /**\n * The number of times to repeat the time window, which is only applicable for 'Numbered' range\n */\n numberOfOccurrences?: number;\n};\n\n/**\n * Specification defines the recurring time window\n */\nexport type RecurrenceSpec = {\n /**\n * The start time of the first/base time window\n */\n startTime: Date;\n /**\n * The duration of each time window in milliseconds\n */\n duration: number;\n /**\n * The recurrence pattern\n */\n pattern: RecurrencePattern;\n /**\n * The recurrence range\n */\n range: RecurrenceRange;\n /**\n * The timezone offset in milliseconds, which helps to determine the day of week of a given date\n */\n timezoneOffset: number;\n};\n"],"names":["DayOfWeek","RecurrencePatternType","RecurrenceRangeType"],"mappings":";;AAAA;AACA;AAEO,MAAM,aAAa,GAAG;AACtB,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;AAE1CA;AAAZ,CAAA,UAAY,SAAS,EAAA;AACjB,IAAA,SAAA,CAAA,SAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAU;AACV,IAAA,SAAA,CAAA,SAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAU;AACV,IAAA,SAAA,CAAA,SAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAW;AACX,IAAA,SAAA,CAAA,SAAA,CAAA,WAAA,CAAA,GAAA,CAAA,CAAA,GAAA,WAAa;AACb,IAAA,SAAA,CAAA,SAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAY;AACZ,IAAA,SAAA,CAAA,SAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAU;AACV,IAAA,SAAA,CAAA,SAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAY;AAChB,CAAC,EARWA,iBAAS,KAATA,iBAAS,GAAA,EAAA,CAAA,CAAA;AAUrB;;AAEG;AACSC;AAAZ,CAAA,UAAY,qBAAqB,EAAA;AAC7B;;AAEG;AACH,IAAA,qBAAA,CAAA,qBAAA,CAAA,OAAA,CAAA,GAAA,CAAA,CAAA,GAAA,OAAK;AACL;;AAEG;AACH,IAAA,qBAAA,CAAA,qBAAA,CAAA,QAAA,CAAA,GAAA,CAAA,CAAA,GAAA,QAAM;AACV,CAAC,EATWA,6BAAqB,KAArBA,6BAAqB,GAAA,EAAA,CAAA,CAAA;AAWjC;;AAEG;AACSC;AAAZ,CAAA,UAAY,mBAAmB,EAAA;AAC3B;;AAEG;AACH,IAAA,mBAAA,CAAA,mBAAA,CAAA,OAAA,CAAA,GAAA,CAAA,CAAA,GAAA,OAAK;AACL;;AAEG;AACH,IAAA,mBAAA,CAAA,mBAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAO;AACP;;AAEG;AACH,IAAA,mBAAA,CAAA,mBAAA,CAAA,UAAA,CAAA,GAAA,CAAA,CAAA,GAAA,UAAQ;AACZ,CAAC,EAbWA,2BAAmB,KAAnBA,2BAAmB,GAAA,EAAA,CAAA,CAAA;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../src/filter/recurrence/utils.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { DayOfWeek, DAYS_PER_WEEK } from \"./model.js\";\n\n/**\n * Calculates the offset in days between two given days of the week.\n * @param day1 A day of week\n * @param day2 A day of week\n * @returns The number of days to be added to day2 to reach day1\n */\nexport function calculateWeeklyDayOffset(day1: DayOfWeek, day2: DayOfWeek): number {\n return (day1 - day2 + DAYS_PER_WEEK) % DAYS_PER_WEEK;\n}\n\n/**\n * Sorts a collection of days of week based on their offsets from a specified first day of week.\n * @param daysOfWeek A collection of days of week\n * @param firstDayOfWeek The first day of week which will be the first element in the sorted result\n * @returns The sorted days of week\n */\nexport function sortDaysOfWeek(daysOfWeek: DayOfWeek[], firstDayOfWeek: DayOfWeek): DayOfWeek[] {\n const sortedDaysOfWeek = daysOfWeek.slice();\n sortedDaysOfWeek.sort((x, y) => calculateWeeklyDayOffset(x, firstDayOfWeek) - calculateWeeklyDayOffset(y, firstDayOfWeek));\n return sortedDaysOfWeek;\n}\n\n/**\n * Gets the day of week of a given date based on the timezone offset.\n * @param date A UTC date\n * @param timezoneOffsetInMs The timezone offset in milliseconds\n * @returns The day of week (0 for Sunday, 1 for Monday, ..., 6 for Saturday)\n */\nexport function getDayOfWeek(date: Date, timezoneOffsetInMs: number): number {\n const alignedDate = new Date(date.getTime() + timezoneOffsetInMs);\n return alignedDate.getUTCDay();\n}\n\n/**\n * Adds a specified number of days to a given date.\n * @param date The date to add days to\n * @param days The number of days to add\n * @returns The new date\n */\nexport function addDays(date: Date, days: number): Date {\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n"],"names":["DAYS_PER_WEEK"],"mappings":";;;;AAAA;AACA;AAIA;;;;;AAKG;AACa,SAAA,wBAAwB,CAAC,IAAe,EAAE,IAAe,EAAA;IACrE,OAAO,CAAC,IAAI,GAAG,IAAI,GAAGA,mBAAa,IAAIA,mBAAa,CAAC;AACzD,CAAC;AAED;;;;;AAKG;AACa,SAAA,cAAc,CAAC,UAAuB,EAAE,cAAyB,EAAA;AAC7E,IAAA,MAAM,gBAAgB,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC;IAC5C,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,wBAAwB,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,wBAAwB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;AAC3H,IAAA,OAAO,gBAAgB,CAAC;AAC5B,CAAC;AAED;;;;;AAKG;AACa,SAAA,YAAY,CAAC,IAAU,EAAE,kBAA0B,EAAA;AAC/D,IAAA,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,kBAAkB,CAAC,CAAC;AAClE,IAAA,OAAO,WAAW,CAAC,SAAS,EAAE,CAAC;AACnC,CAAC;AAED;;;;;AAKG;AACa,SAAA,OAAO,CAAC,IAAU,EAAE,IAAY,EAAA;AAC5C,IAAA,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;AACxC,IAAA,OAAO,MAAM,CAAC;AAClB;;;;;;;"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../src/filter/recurrence/utils.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { DayOfWeek, DAYS_PER_WEEK } from \"./model.js\";\n\n/**\n * Calculates the offset in days between two given days of the week.\n * @param day1 A day of week\n * @param day2 A day of week\n * @returns The number of days to be added to day2 to reach day1\n */\nexport function calculateWeeklyDayOffset(day1: DayOfWeek, day2: DayOfWeek): number {\n return (day1 - day2 + DAYS_PER_WEEK) % DAYS_PER_WEEK;\n}\n\n/**\n * Sorts a collection of days of week based on their offsets from a specified first day of week.\n * @param daysOfWeek A collection of days of week\n * @param firstDayOfWeek The first day of week which will be the first element in the sorted result\n * @returns The sorted days of week\n */\nexport function sortDaysOfWeek(daysOfWeek: DayOfWeek[], firstDayOfWeek: DayOfWeek): DayOfWeek[] {\n const sortedDaysOfWeek = daysOfWeek.slice();\n sortedDaysOfWeek.sort((x, y) => calculateWeeklyDayOffset(x, firstDayOfWeek) - calculateWeeklyDayOffset(y, firstDayOfWeek));\n return sortedDaysOfWeek;\n}\n\n/**\n * Gets the day of week of a given date based on the timezone offset.\n * @param date A UTC date\n * @param timezoneOffsetInMs The timezone offset in milliseconds\n * @returns The day of week (0 for Sunday, 1 for Monday, ..., 6 for Saturday)\n */\nexport function getDayOfWeek(date: Date, timezoneOffsetInMs: number): number {\n const alignedDate = new Date(date.getTime() + timezoneOffsetInMs);\n return alignedDate.getUTCDay();\n}\n\n/**\n * Adds a specified number of days to a given date.\n * @param date The date to add days to\n * @param days The number of days to add\n * @returns The new date\n */\nexport function addDays(date: Date, days: number): Date {\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n"],"names":["DAYS_PER_WEEK"],"mappings":";;;;AAAA;AACA;AAIA;;;;;AAKG;AACG,SAAU,wBAAwB,CAAC,IAAe,EAAE,IAAe,EAAA;IACrE,OAAO,CAAC,IAAI,GAAG,IAAI,GAAGA,mBAAa,IAAIA,mBAAa;AACxD;AAEA;;;;;AAKG;AACG,SAAU,cAAc,CAAC,UAAuB,EAAE,cAAyB,EAAA;AAC7E,IAAA,MAAM,gBAAgB,GAAG,UAAU,CAAC,KAAK,EAAE;IAC3C,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,wBAAwB,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,wBAAwB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AAC1H,IAAA,OAAO,gBAAgB;AAC3B;AAEA;;;;;AAKG;AACG,SAAU,YAAY,CAAC,IAAU,EAAE,kBAA0B,EAAA;AAC/D,IAAA,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,kBAAkB,CAAC;AACjE,IAAA,OAAO,WAAW,CAAC,SAAS,EAAE;AAClC;AAEA;;;;;AAKG;AACG,SAAU,OAAO,CAAC,IAAU,EAAE,IAAY,EAAA;AAC5C,IAAA,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC;IAC7B,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;AACvC,IAAA,OAAO,MAAM;AACjB;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"validator.js","sources":["../../../../src/filter/recurrence/validator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { RecurrenceParameters } from \"../timeWindowFilter.js\";\nimport { VALUE_OUT_OF_RANGE_ERROR_MESSAGE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE, buildInvalidParameterErrorMessage } from \"../utils.js\";\nimport { DayOfWeek, RecurrenceSpec, RecurrencePattern, RecurrenceRange, RecurrencePatternType, RecurrenceRangeType, DAYS_PER_WEEK, ONE_DAY_IN_MILLISECONDS } from \"./model.js\";\nimport { calculateWeeklyDayOffset, sortDaysOfWeek, getDayOfWeek } from \"./utils.js\";\n\nexport const START_NOT_MATCHED_ERROR_MESSAGE = \"Start date is not a valid first occurrence.\";\nexport const TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE = \"Time window duration cannot be longer than how frequently it occurs or be longer than 10 years.\";\nexport const PATTERN = \"Recurrence.Pattern\";\nexport const PATTERN_TYPE = \"Recurrence.Pattern.Type\";\nexport const INTERVAL = \"Recurrence.Pattern.Interval\";\nexport const DAYS_OF_WEEK = \"Recurrence.Pattern.DaysOfWeek\";\nexport const FIRST_DAY_OF_WEEK = \"Recurrence.Pattern.FirstDayOfWeek\";\nexport const RANGE = \"Recurrence.Range\";\nexport const RANGE_TYPE = \"Recurrence.Range.Type\";\nexport const END_DATE = \"Recurrence.Range.EndDate\";\nexport const NUMBER_OF_OCCURRENCES = \"Recurrence.Range.NumberOfOccurrences\";\n\n/**\n * Parses @see RecurrenceParameters into a @see RecurrenceSpec object. If the parameter is invalid, an error will be thrown.\n * @param startTime The start time of the base time window\n * @param day2 The end time of the base time window\n * @param recurrenceParameters The @see RecurrenceParameters to parse\n * @param TimeZoneOffset The time zone offset in milliseconds, by default 0\n * @returns A @see RecurrenceSpec object\n */\nexport function parseRecurrenceParameter(startTime: Date | undefined, endTime: Date | undefined, recurrenceParameters: RecurrenceParameters, TimeZoneOffset: number = 0): RecurrenceSpec {\n if (startTime === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(\"Start\", REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (endTime === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (startTime >= endTime) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n const timeWindowDuration = endTime.getTime() - startTime.getTime();\n if (timeWindowDuration > 10 * 365 * ONE_DAY_IN_MILLISECONDS) { // time window duration cannot be longer than 10 years\n throw new Error(buildInvalidParameterErrorMessage(\"End\", TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n\n return {\n startTime: startTime,\n duration: timeWindowDuration,\n pattern: parseRecurrencePattern(startTime, endTime, recurrenceParameters, TimeZoneOffset),\n range: parseRecurrenceRange(startTime, recurrenceParameters),\n timezoneOffset: TimeZoneOffset\n };\n}\n\nfunction parseRecurrencePattern(startTime: Date, endTime: Date, recurrenceParameters: RecurrenceParameters, timeZoneOffset: number): RecurrencePattern {\n const rawPattern = recurrenceParameters.Pattern;\n if (rawPattern === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(PATTERN, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (rawPattern.Type === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(PATTERN_TYPE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n const patternType = RecurrencePatternType[rawPattern.Type];\n if (patternType === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(PATTERN_TYPE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n let interval = rawPattern.Interval;\n if (interval !== undefined) {\n if (typeof interval !== \"number\") {\n throw new Error(buildInvalidParameterErrorMessage(INTERVAL, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n } else if (interval <= 0 || !Number.isInteger(interval)) {\n throw new Error(buildInvalidParameterErrorMessage(INTERVAL, VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else {\n interval = 1;\n }\n const parsedPattern: RecurrencePattern = {\n type: patternType,\n interval: interval\n };\n const timeWindowDuration = endTime.getTime() - startTime.getTime();\n if (patternType === RecurrencePatternType.Daily) {\n if (timeWindowDuration > interval * ONE_DAY_IN_MILLISECONDS) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else if (patternType === RecurrencePatternType.Weekly) {\n let firstDayOfWeek: DayOfWeek;\n if (rawPattern.FirstDayOfWeek !== undefined) {\n firstDayOfWeek = DayOfWeek[rawPattern.FirstDayOfWeek];\n if (firstDayOfWeek === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(FIRST_DAY_OF_WEEK, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n }\n else {\n firstDayOfWeek = DayOfWeek.Sunday;\n }\n parsedPattern.firstDayOfWeek = firstDayOfWeek;\n\n if (rawPattern.DaysOfWeek === undefined || rawPattern.DaysOfWeek.length === 0) {\n throw new Error(buildInvalidParameterErrorMessage(DAYS_OF_WEEK, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (!Array.isArray(rawPattern.DaysOfWeek)) {\n throw new Error(buildInvalidParameterErrorMessage(DAYS_OF_WEEK, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n const daysOfWeek = [...new Set(rawPattern.DaysOfWeek.map(day => DayOfWeek[day]))]; // dedup array\n if (daysOfWeek.some(day => day === undefined)) {\n throw new Error(buildInvalidParameterErrorMessage(DAYS_OF_WEEK, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n if (timeWindowDuration > interval * DAYS_PER_WEEK * ONE_DAY_IN_MILLISECONDS ||\n !isDurationCompliantWithDaysOfWeek(timeWindowDuration, interval, daysOfWeek, firstDayOfWeek)) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n parsedPattern.daysOfWeek = daysOfWeek;\n\n // check whether \"Start\" is a valid first occurrence\n const alignedStartDay = getDayOfWeek(startTime, timeZoneOffset);\n if (!daysOfWeek.find(day => day === alignedStartDay)) {\n throw new Error(buildInvalidParameterErrorMessage(\"Start\", START_NOT_MATCHED_ERROR_MESSAGE));\n }\n }\n return parsedPattern;\n}\n\nfunction parseRecurrenceRange(startTime: Date, recurrenceParameters: RecurrenceParameters): RecurrenceRange {\n const rawRange = recurrenceParameters.Range;\n if (rawRange === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(RANGE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (rawRange.Type === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(RANGE_TYPE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n const rangeType = RecurrenceRangeType[rawRange.Type];\n if (rangeType === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(RANGE_TYPE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n const parsedRange: RecurrenceRange = { type: rangeType };\n if (rangeType === RecurrenceRangeType.EndDate) {\n let endDate: Date;\n if (rawRange.EndDate !== undefined) {\n endDate = new Date(rawRange.EndDate);\n if (isNaN(endDate.getTime())) {\n throw new Error(buildInvalidParameterErrorMessage(END_DATE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n if (endDate < startTime) {\n throw new Error(buildInvalidParameterErrorMessage(END_DATE, VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else {\n endDate = new Date(8.64e15); // the maximum date in ECMAScript: https://262.ecma-international.org/5.1/#sec-15.9.1.1\n }\n parsedRange.endDate = endDate;\n } else if (rangeType === RecurrenceRangeType.Numbered) {\n let numberOfOccurrences = rawRange.NumberOfOccurrences;\n if (numberOfOccurrences !== undefined) {\n if (typeof numberOfOccurrences !== \"number\") {\n throw new Error(buildInvalidParameterErrorMessage(NUMBER_OF_OCCURRENCES, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n } else if (numberOfOccurrences <= 0 || !Number.isInteger(numberOfOccurrences)) {\n throw new Error(buildInvalidParameterErrorMessage(NUMBER_OF_OCCURRENCES, VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else {\n numberOfOccurrences = Number.MAX_SAFE_INTEGER;\n }\n parsedRange.numberOfOccurrences = numberOfOccurrences;\n }\n return parsedRange;\n}\n\nfunction isDurationCompliantWithDaysOfWeek(duration: number, interval: number, daysOfWeek: DayOfWeek[], firstDayOfWeek: DayOfWeek): boolean {\n if (daysOfWeek.length === 1) {\n return true;\n }\n const sortedDaysOfWeek = sortDaysOfWeek(daysOfWeek, firstDayOfWeek);\n let prev = sortedDaysOfWeek[0]; // the closest occurrence day to the first day of week\n let minGap = DAYS_PER_WEEK * ONE_DAY_IN_MILLISECONDS;\n for (let i = 1; i < sortedDaysOfWeek.length; i++) { // skip the first day\n const gap = calculateWeeklyDayOffset(sortedDaysOfWeek[i], prev) * ONE_DAY_IN_MILLISECONDS;\n minGap = gap < minGap ? gap : minGap;\n prev = sortedDaysOfWeek[i];\n }\n // It may across weeks. Check the next week if the interval is one week.\n if (interval == 1) {\n const gap = calculateWeeklyDayOffset(sortedDaysOfWeek[0], prev) * ONE_DAY_IN_MILLISECONDS;\n minGap = gap < minGap ? gap : minGap;\n }\n return minGap >= duration;\n}\n"],"names":["buildInvalidParameterErrorMessage","REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE","VALUE_OUT_OF_RANGE_ERROR_MESSAGE","ONE_DAY_IN_MILLISECONDS","RecurrencePatternType","UNRECOGNIZABLE_VALUE_ERROR_MESSAGE","DayOfWeek","DAYS_PER_WEEK","getDayOfWeek","RecurrenceRangeType","sortDaysOfWeek","calculateWeeklyDayOffset"],"mappings":"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"}
1
+ {"version":3,"file":"validator.js","sources":["../../../../src/filter/recurrence/validator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { RecurrenceParameters } from \"../timeWindowFilter.js\";\nimport { VALUE_OUT_OF_RANGE_ERROR_MESSAGE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE, buildInvalidParameterErrorMessage } from \"../utils.js\";\nimport { DayOfWeek, RecurrenceSpec, RecurrencePattern, RecurrenceRange, RecurrencePatternType, RecurrenceRangeType, DAYS_PER_WEEK, ONE_DAY_IN_MILLISECONDS } from \"./model.js\";\nimport { calculateWeeklyDayOffset, sortDaysOfWeek, getDayOfWeek } from \"./utils.js\";\n\nexport const START_NOT_MATCHED_ERROR_MESSAGE = \"Start date is not a valid first occurrence.\";\nexport const TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE = \"Time window duration cannot be longer than how frequently it occurs or be longer than 10 years.\";\nexport const PATTERN = \"Recurrence.Pattern\";\nexport const PATTERN_TYPE = \"Recurrence.Pattern.Type\";\nexport const INTERVAL = \"Recurrence.Pattern.Interval\";\nexport const DAYS_OF_WEEK = \"Recurrence.Pattern.DaysOfWeek\";\nexport const FIRST_DAY_OF_WEEK = \"Recurrence.Pattern.FirstDayOfWeek\";\nexport const RANGE = \"Recurrence.Range\";\nexport const RANGE_TYPE = \"Recurrence.Range.Type\";\nexport const END_DATE = \"Recurrence.Range.EndDate\";\nexport const NUMBER_OF_OCCURRENCES = \"Recurrence.Range.NumberOfOccurrences\";\n\n/**\n * Parses @see RecurrenceParameters into a @see RecurrenceSpec object. If the parameter is invalid, an error will be thrown.\n * @param startTime The start time of the base time window\n * @param day2 The end time of the base time window\n * @param recurrenceParameters The @see RecurrenceParameters to parse\n * @param TimeZoneOffset The time zone offset in milliseconds, by default 0\n * @returns A @see RecurrenceSpec object\n */\nexport function parseRecurrenceParameter(startTime: Date | undefined, endTime: Date | undefined, recurrenceParameters: RecurrenceParameters, TimeZoneOffset: number = 0): RecurrenceSpec {\n if (startTime === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(\"Start\", REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (endTime === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (startTime >= endTime) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n const timeWindowDuration = endTime.getTime() - startTime.getTime();\n if (timeWindowDuration > 10 * 365 * ONE_DAY_IN_MILLISECONDS) { // time window duration cannot be longer than 10 years\n throw new Error(buildInvalidParameterErrorMessage(\"End\", TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n\n return {\n startTime: startTime,\n duration: timeWindowDuration,\n pattern: parseRecurrencePattern(startTime, endTime, recurrenceParameters, TimeZoneOffset),\n range: parseRecurrenceRange(startTime, recurrenceParameters),\n timezoneOffset: TimeZoneOffset\n };\n}\n\nfunction parseRecurrencePattern(startTime: Date, endTime: Date, recurrenceParameters: RecurrenceParameters, timeZoneOffset: number): RecurrencePattern {\n const rawPattern = recurrenceParameters.Pattern;\n if (rawPattern === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(PATTERN, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (rawPattern.Type === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(PATTERN_TYPE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n const patternType = RecurrencePatternType[rawPattern.Type];\n if (patternType === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(PATTERN_TYPE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n let interval = rawPattern.Interval;\n if (interval !== undefined) {\n if (typeof interval !== \"number\") {\n throw new Error(buildInvalidParameterErrorMessage(INTERVAL, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n } else if (interval <= 0 || !Number.isInteger(interval)) {\n throw new Error(buildInvalidParameterErrorMessage(INTERVAL, VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else {\n interval = 1;\n }\n const parsedPattern: RecurrencePattern = {\n type: patternType,\n interval: interval\n };\n const timeWindowDuration = endTime.getTime() - startTime.getTime();\n if (patternType === RecurrencePatternType.Daily) {\n if (timeWindowDuration > interval * ONE_DAY_IN_MILLISECONDS) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else if (patternType === RecurrencePatternType.Weekly) {\n let firstDayOfWeek: DayOfWeek;\n if (rawPattern.FirstDayOfWeek !== undefined) {\n firstDayOfWeek = DayOfWeek[rawPattern.FirstDayOfWeek];\n if (firstDayOfWeek === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(FIRST_DAY_OF_WEEK, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n }\n else {\n firstDayOfWeek = DayOfWeek.Sunday;\n }\n parsedPattern.firstDayOfWeek = firstDayOfWeek;\n\n if (rawPattern.DaysOfWeek === undefined || rawPattern.DaysOfWeek.length === 0) {\n throw new Error(buildInvalidParameterErrorMessage(DAYS_OF_WEEK, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (!Array.isArray(rawPattern.DaysOfWeek)) {\n throw new Error(buildInvalidParameterErrorMessage(DAYS_OF_WEEK, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n const daysOfWeek = [...new Set(rawPattern.DaysOfWeek.map(day => DayOfWeek[day]))]; // dedup array\n if (daysOfWeek.some(day => day === undefined)) {\n throw new Error(buildInvalidParameterErrorMessage(DAYS_OF_WEEK, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n if (timeWindowDuration > interval * DAYS_PER_WEEK * ONE_DAY_IN_MILLISECONDS ||\n !isDurationCompliantWithDaysOfWeek(timeWindowDuration, interval, daysOfWeek, firstDayOfWeek)) {\n throw new Error(buildInvalidParameterErrorMessage(\"End\", TIME_WINDOW_DURATION_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n parsedPattern.daysOfWeek = daysOfWeek;\n\n // check whether \"Start\" is a valid first occurrence\n const alignedStartDay = getDayOfWeek(startTime, timeZoneOffset);\n if (!daysOfWeek.find(day => day === alignedStartDay)) {\n throw new Error(buildInvalidParameterErrorMessage(\"Start\", START_NOT_MATCHED_ERROR_MESSAGE));\n }\n }\n return parsedPattern;\n}\n\nfunction parseRecurrenceRange(startTime: Date, recurrenceParameters: RecurrenceParameters): RecurrenceRange {\n const rawRange = recurrenceParameters.Range;\n if (rawRange === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(RANGE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n if (rawRange.Type === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(RANGE_TYPE, REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE));\n }\n const rangeType = RecurrenceRangeType[rawRange.Type];\n if (rangeType === undefined) {\n throw new Error(buildInvalidParameterErrorMessage(RANGE_TYPE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n const parsedRange: RecurrenceRange = { type: rangeType };\n if (rangeType === RecurrenceRangeType.EndDate) {\n let endDate: Date;\n if (rawRange.EndDate !== undefined) {\n endDate = new Date(rawRange.EndDate);\n if (isNaN(endDate.getTime())) {\n throw new Error(buildInvalidParameterErrorMessage(END_DATE, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n }\n if (endDate < startTime) {\n throw new Error(buildInvalidParameterErrorMessage(END_DATE, VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else {\n endDate = new Date(8.64e15); // the maximum date in ECMAScript: https://262.ecma-international.org/5.1/#sec-15.9.1.1\n }\n parsedRange.endDate = endDate;\n } else if (rangeType === RecurrenceRangeType.Numbered) {\n let numberOfOccurrences = rawRange.NumberOfOccurrences;\n if (numberOfOccurrences !== undefined) {\n if (typeof numberOfOccurrences !== \"number\") {\n throw new Error(buildInvalidParameterErrorMessage(NUMBER_OF_OCCURRENCES, UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n } else if (numberOfOccurrences <= 0 || !Number.isInteger(numberOfOccurrences)) {\n throw new Error(buildInvalidParameterErrorMessage(NUMBER_OF_OCCURRENCES, VALUE_OUT_OF_RANGE_ERROR_MESSAGE));\n }\n } else {\n numberOfOccurrences = Number.MAX_SAFE_INTEGER;\n }\n parsedRange.numberOfOccurrences = numberOfOccurrences;\n }\n return parsedRange;\n}\n\nfunction isDurationCompliantWithDaysOfWeek(duration: number, interval: number, daysOfWeek: DayOfWeek[], firstDayOfWeek: DayOfWeek): boolean {\n if (daysOfWeek.length === 1) {\n return true;\n }\n const sortedDaysOfWeek = sortDaysOfWeek(daysOfWeek, firstDayOfWeek);\n let prev = sortedDaysOfWeek[0]; // the closest occurrence day to the first day of week\n let minGap = DAYS_PER_WEEK * ONE_DAY_IN_MILLISECONDS;\n for (let i = 1; i < sortedDaysOfWeek.length; i++) { // skip the first day\n const gap = calculateWeeklyDayOffset(sortedDaysOfWeek[i], prev) * ONE_DAY_IN_MILLISECONDS;\n minGap = gap < minGap ? gap : minGap;\n prev = sortedDaysOfWeek[i];\n }\n // It may across weeks. Check the next week if the interval is one week.\n if (interval == 1) {\n const gap = calculateWeeklyDayOffset(sortedDaysOfWeek[0], prev) * ONE_DAY_IN_MILLISECONDS;\n minGap = gap < minGap ? gap : minGap;\n }\n return minGap >= duration;\n}\n"],"names":["buildInvalidParameterErrorMessage","REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE","VALUE_OUT_OF_RANGE_ERROR_MESSAGE","ONE_DAY_IN_MILLISECONDS","RecurrencePatternType","UNRECOGNIZABLE_VALUE_ERROR_MESSAGE","DayOfWeek","DAYS_PER_WEEK","getDayOfWeek","RecurrenceRangeType","sortDaysOfWeek","calculateWeeklyDayOffset"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"targetingFilter.js","sources":["../../../src/filter/targetingFilter.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { IFeatureFilter } from \"./featureFilter.js\";\nimport { isTargetedPercentile } from \"../common/targetingEvaluator.js\";\nimport { ITargetingContext, ITargetingContextAccessor } from \"../common/targetingContext.js\";\n\ntype TargetingFilterParameters = {\n Audience: {\n DefaultRolloutPercentage: number;\n Users?: string[];\n Groups?: {\n Name: string;\n RolloutPercentage: number;\n }[];\n Exclusion?: {\n Users?: string[];\n Groups?: string[];\n };\n }\n}\n\ntype TargetingFilterEvaluationContext = {\n featureName: string;\n parameters: TargetingFilterParameters;\n}\n\nexport class TargetingFilter implements IFeatureFilter {\n readonly name: string = \"Microsoft.Targeting\";\n readonly #targetingContextAccessor?: ITargetingContextAccessor;\n\n constructor(targetingContextAccessor?: ITargetingContextAccessor) {\n this.#targetingContextAccessor = targetingContextAccessor;\n }\n\n async evaluate(context: TargetingFilterEvaluationContext, appContext?: ITargetingContext): Promise<boolean> {\n const { featureName, parameters } = context;\n TargetingFilter.#validateParameters(featureName, parameters);\n\n let targetingContext: ITargetingContext | undefined;\n if (appContext?.userId !== undefined || appContext?.groups !== undefined) {\n targetingContext = appContext;\n } else if (this.#targetingContextAccessor !== undefined) {\n targetingContext = this.#targetingContextAccessor.getTargetingContext();\n }\n\n if (parameters.Audience.Exclusion !== undefined) {\n // check if the user is in the exclusion list\n if (targetingContext?.userId !== undefined &&\n parameters.Audience.Exclusion.Users !== undefined &&\n parameters.Audience.Exclusion.Users.includes(targetingContext.userId)) {\n return false;\n }\n // check if the user is in a group within exclusion list\n if (targetingContext?.groups !== undefined &&\n parameters.Audience.Exclusion.Groups !== undefined) {\n for (const excludedGroup of parameters.Audience.Exclusion.Groups) {\n if (targetingContext.groups.includes(excludedGroup)) {\n return false;\n }\n }\n }\n }\n\n // check if the user is being targeted directly\n if (targetingContext?.userId !== undefined &&\n parameters.Audience.Users !== undefined &&\n parameters.Audience.Users.includes(targetingContext.userId)) {\n return true;\n }\n\n // check if the user is in a group that is being targeted\n if (targetingContext?.groups !== undefined &&\n parameters.Audience.Groups !== undefined) {\n for (const group of parameters.Audience.Groups) {\n if (targetingContext.groups.includes(group.Name)) {\n const hint = `${featureName}\\n${group.Name}`;\n if (await isTargetedPercentile(targetingContext.userId, hint, 0, group.RolloutPercentage)) {\n return true;\n }\n }\n }\n }\n\n // check if the user is being targeted by a default rollout percentage\n const hint = featureName;\n return isTargetedPercentile(targetingContext?.userId, hint, 0, parameters.Audience.DefaultRolloutPercentage);\n }\n\n static #validateParameters(featureName: string, parameters: TargetingFilterParameters): void {\n if (parameters.Audience.DefaultRolloutPercentage < 0 || parameters.Audience.DefaultRolloutPercentage > 100) {\n throw new Error(`Invalid feature flag: ${featureName}. Audience.DefaultRolloutPercentage must be a number between 0 and 100.`);\n }\n // validate RolloutPercentage for each group\n if (parameters.Audience.Groups !== undefined) {\n for (const group of parameters.Audience.Groups) {\n if (group.RolloutPercentage < 0 || group.RolloutPercentage > 100) {\n throw new Error(`Invalid feature flag: ${featureName}. RolloutPercentage of group ${group.Name} must be a number between 0 and 100.`);\n }\n }\n }\n }\n}\n"],"names":["isTargetedPercentile"],"mappings":"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"}
1
+ {"version":3,"file":"targetingFilter.js","sources":["../../../src/filter/targetingFilter.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { IFeatureFilter } from \"./featureFilter.js\";\nimport { isTargetedPercentile } from \"../common/targetingEvaluator.js\";\nimport { ITargetingContext, ITargetingContextAccessor } from \"../common/targetingContext.js\";\n\ntype TargetingFilterParameters = {\n Audience: {\n DefaultRolloutPercentage: number;\n Users?: string[];\n Groups?: {\n Name: string;\n RolloutPercentage: number;\n }[];\n Exclusion?: {\n Users?: string[];\n Groups?: string[];\n };\n }\n}\n\ntype TargetingFilterEvaluationContext = {\n featureName: string;\n parameters: TargetingFilterParameters;\n}\n\nexport class TargetingFilter implements IFeatureFilter {\n readonly name: string = \"Microsoft.Targeting\";\n readonly #targetingContextAccessor?: ITargetingContextAccessor;\n\n constructor(targetingContextAccessor?: ITargetingContextAccessor) {\n this.#targetingContextAccessor = targetingContextAccessor;\n }\n\n async evaluate(context: TargetingFilterEvaluationContext, appContext?: ITargetingContext): Promise<boolean> {\n const { featureName, parameters } = context;\n TargetingFilter.#validateParameters(featureName, parameters);\n\n let targetingContext: ITargetingContext | undefined;\n if (appContext?.userId !== undefined || appContext?.groups !== undefined) {\n targetingContext = appContext;\n } else if (this.#targetingContextAccessor !== undefined) {\n targetingContext = this.#targetingContextAccessor.getTargetingContext();\n }\n\n if (parameters.Audience.Exclusion !== undefined) {\n // check if the user is in the exclusion list\n if (targetingContext?.userId !== undefined &&\n parameters.Audience.Exclusion.Users !== undefined &&\n parameters.Audience.Exclusion.Users.includes(targetingContext.userId)) {\n return false;\n }\n // check if the user is in a group within exclusion list\n if (targetingContext?.groups !== undefined &&\n parameters.Audience.Exclusion.Groups !== undefined) {\n for (const excludedGroup of parameters.Audience.Exclusion.Groups) {\n if (targetingContext.groups.includes(excludedGroup)) {\n return false;\n }\n }\n }\n }\n\n // check if the user is being targeted directly\n if (targetingContext?.userId !== undefined &&\n parameters.Audience.Users !== undefined &&\n parameters.Audience.Users.includes(targetingContext.userId)) {\n return true;\n }\n\n // check if the user is in a group that is being targeted\n if (targetingContext?.groups !== undefined &&\n parameters.Audience.Groups !== undefined) {\n for (const group of parameters.Audience.Groups) {\n if (targetingContext.groups.includes(group.Name)) {\n const hint = `${featureName}\\n${group.Name}`;\n if (await isTargetedPercentile(targetingContext.userId, hint, 0, group.RolloutPercentage)) {\n return true;\n }\n }\n }\n }\n\n // check if the user is being targeted by a default rollout percentage\n const hint = featureName;\n return isTargetedPercentile(targetingContext?.userId, hint, 0, parameters.Audience.DefaultRolloutPercentage);\n }\n\n static #validateParameters(featureName: string, parameters: TargetingFilterParameters): void {\n if (parameters.Audience.DefaultRolloutPercentage < 0 || parameters.Audience.DefaultRolloutPercentage > 100) {\n throw new Error(`Invalid feature flag: ${featureName}. Audience.DefaultRolloutPercentage must be a number between 0 and 100.`);\n }\n // validate RolloutPercentage for each group\n if (parameters.Audience.Groups !== undefined) {\n for (const group of parameters.Audience.Groups) {\n if (group.RolloutPercentage < 0 || group.RolloutPercentage > 100) {\n throw new Error(`Invalid feature flag: ${featureName}. RolloutPercentage of group ${group.Name} must be a number between 0 and 100.`);\n }\n }\n }\n }\n}\n"],"names":["isTargetedPercentile"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"timeWindowFilter.js","sources":["../../../src/filter/timeWindowFilter.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { IFeatureFilter } from \"./featureFilter.js\";\nimport { RecurrenceSpec } from \"./recurrence/model.js\";\nimport { parseRecurrenceParameter } from \"./recurrence/validator.js\";\nimport { matchRecurrence } from \"./recurrence/evaluator.js\";\nimport { UNRECOGNIZABLE_VALUE_ERROR_MESSAGE, buildInvalidParameterErrorMessage } from \"./utils.js\";\n\ntype TimeWindowFilterEvaluationContext = {\n featureName: string;\n parameters: TimeWindowParameters;\n};\n\ntype TimeWindowParameters = {\n Start?: string;\n End?: string;\n Recurrence?: RecurrenceParameters;\n};\n\nexport type RecurrenceParameters = {\n Pattern: {\n Type: string;\n Interval?: number;\n DaysOfWeek?: string[];\n FirstDayOfWeek?: string;\n },\n Range: {\n Type: string;\n EndDate?: string;\n NumberOfOccurrences?: number;\n }\n};\n\nexport class TimeWindowFilter implements IFeatureFilter {\n readonly name: string = \"Microsoft.TimeWindow\";\n\n evaluate(context: TimeWindowFilterEvaluationContext): boolean {\n const {featureName, parameters} = context;\n const startTime = parameters.Start !== undefined ? new Date(parameters.Start) : undefined;\n const endTime = parameters.End !== undefined ? new Date(parameters.End) : undefined;\n\n const baseErrorMessage = `The ${this.name} feature filter is not valid for feature ${featureName}. `;\n\n if (startTime === undefined && endTime === undefined) {\n // If neither start nor end time is specified, then the filter is not applicable.\n console.warn(baseErrorMessage + \"It must specify either 'Start', 'End', or both.\");\n return false;\n }\n\n if (startTime !== undefined && isNaN(startTime.getTime())) {\n console.warn(baseErrorMessage + buildInvalidParameterErrorMessage(\"Start\", UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n return false;\n }\n\n if (endTime !== undefined && isNaN(endTime.getTime())) {\n console.warn(baseErrorMessage + buildInvalidParameterErrorMessage(\"End\", UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n return false;\n }\n\n const now = new Date();\n\n if ((startTime === undefined || startTime <= now) && (endTime === undefined || now < endTime)) {\n return true;\n }\n\n if (parameters.Recurrence !== undefined) {\n let recurrence: RecurrenceSpec;\n try {\n recurrence = parseRecurrenceParameter(startTime, endTime, parameters.Recurrence);\n } catch (error) {\n console.warn(baseErrorMessage + error.message);\n return false;\n }\n return matchRecurrence(now, recurrence);\n }\n\n return false;\n }\n}\n"],"names":["buildInvalidParameterErrorMessage","UNRECOGNIZABLE_VALUE_ERROR_MESSAGE","parseRecurrenceParameter","matchRecurrence"],"mappings":";;;;;;AAAA;AACA;MAiCa,gBAAgB,CAAA;IAChB,IAAI,GAAW,sBAAsB,CAAC;AAE/C,IAAA,QAAQ,CAAC,OAA0C,EAAA;AAC/C,QAAA,MAAM,EAAC,WAAW,EAAE,UAAU,EAAC,GAAG,OAAO,CAAC;QAC1C,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,KAAK,SAAS,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;QAC1F,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,KAAK,SAAS,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;QAEpF,MAAM,gBAAgB,GAAG,CAAO,IAAA,EAAA,IAAI,CAAC,IAAI,CAAA,yCAAA,EAA4C,WAAW,CAAA,EAAA,CAAI,CAAC;QAErG,IAAI,SAAS,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE;;AAElD,YAAA,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,iDAAiD,CAAC,CAAC;AACnF,YAAA,OAAO,KAAK,CAAC;SAChB;AAED,QAAA,IAAI,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE;AACvD,YAAA,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAGA,uCAAiC,CAAC,OAAO,EAAEC,wCAAkC,CAAC,CAAC,CAAC;AAChH,YAAA,OAAO,KAAK,CAAC;SAChB;AAED,QAAA,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE;AACnD,YAAA,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAGD,uCAAiC,CAAC,KAAK,EAAEC,wCAAkC,CAAC,CAAC,CAAC;AAC9G,YAAA,OAAO,KAAK,CAAC;SAChB;AAED,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QAEvB,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,IAAI,GAAG,MAAM,OAAO,KAAK,SAAS,IAAI,GAAG,GAAG,OAAO,CAAC,EAAE;AAC3F,YAAA,OAAO,IAAI,CAAC;SACf;AAED,QAAA,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS,EAAE;AACrC,YAAA,IAAI,UAA0B,CAAC;AAC/B,YAAA,IAAI;gBACA,UAAU,GAAGC,kCAAwB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;aACpF;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;AAC/C,gBAAA,OAAO,KAAK,CAAC;aAChB;AACD,YAAA,OAAOC,yBAAe,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;SAC3C;AAED,QAAA,OAAO,KAAK,CAAC;KAChB;AACJ;;;;"}
1
+ {"version":3,"file":"timeWindowFilter.js","sources":["../../../src/filter/timeWindowFilter.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { IFeatureFilter } from \"./featureFilter.js\";\nimport { RecurrenceSpec } from \"./recurrence/model.js\";\nimport { parseRecurrenceParameter } from \"./recurrence/validator.js\";\nimport { matchRecurrence } from \"./recurrence/evaluator.js\";\nimport { UNRECOGNIZABLE_VALUE_ERROR_MESSAGE, buildInvalidParameterErrorMessage } from \"./utils.js\";\n\ntype TimeWindowFilterEvaluationContext = {\n featureName: string;\n parameters: TimeWindowParameters;\n};\n\ntype TimeWindowParameters = {\n Start?: string;\n End?: string;\n Recurrence?: RecurrenceParameters;\n};\n\nexport type RecurrenceParameters = {\n Pattern: {\n Type: string;\n Interval?: number;\n DaysOfWeek?: string[];\n FirstDayOfWeek?: string;\n },\n Range: {\n Type: string;\n EndDate?: string;\n NumberOfOccurrences?: number;\n }\n};\n\nexport class TimeWindowFilter implements IFeatureFilter {\n readonly name: string = \"Microsoft.TimeWindow\";\n\n evaluate(context: TimeWindowFilterEvaluationContext): boolean {\n const {featureName, parameters} = context;\n const startTime = parameters.Start !== undefined ? new Date(parameters.Start) : undefined;\n const endTime = parameters.End !== undefined ? new Date(parameters.End) : undefined;\n\n const baseErrorMessage = `The ${this.name} feature filter is not valid for feature ${featureName}. `;\n\n if (startTime === undefined && endTime === undefined) {\n // If neither start nor end time is specified, then the filter is not applicable.\n console.warn(baseErrorMessage + \"It must specify either 'Start', 'End', or both.\");\n return false;\n }\n\n if (startTime !== undefined && isNaN(startTime.getTime())) {\n console.warn(baseErrorMessage + buildInvalidParameterErrorMessage(\"Start\", UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n return false;\n }\n\n if (endTime !== undefined && isNaN(endTime.getTime())) {\n console.warn(baseErrorMessage + buildInvalidParameterErrorMessage(\"End\", UNRECOGNIZABLE_VALUE_ERROR_MESSAGE));\n return false;\n }\n\n const now = new Date();\n\n if ((startTime === undefined || startTime <= now) && (endTime === undefined || now < endTime)) {\n return true;\n }\n\n if (parameters.Recurrence !== undefined) {\n let recurrence: RecurrenceSpec;\n try {\n recurrence = parseRecurrenceParameter(startTime, endTime, parameters.Recurrence);\n } catch (error) {\n console.warn(baseErrorMessage + error.message);\n return false;\n }\n return matchRecurrence(now, recurrence);\n }\n\n return false;\n }\n}\n"],"names":["buildInvalidParameterErrorMessage","UNRECOGNIZABLE_VALUE_ERROR_MESSAGE","parseRecurrenceParameter","matchRecurrence"],"mappings":";;;;;;AAAA;AACA;MAiCa,gBAAgB,CAAA;IAChB,IAAI,GAAW,sBAAsB;AAE9C,IAAA,QAAQ,CAAC,OAA0C,EAAA;AAC/C,QAAA,MAAM,EAAC,WAAW,EAAE,UAAU,EAAC,GAAG,OAAO;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,KAAK,SAAS,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,SAAS;QACzF,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,KAAK,SAAS,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,SAAS;QAEnF,MAAM,gBAAgB,GAAG,CAAA,IAAA,EAAO,IAAI,CAAC,IAAI,CAAA,yCAAA,EAA4C,WAAW,CAAA,EAAA,CAAI;QAEpG,IAAI,SAAS,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE;;AAElD,YAAA,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,iDAAiD,CAAC;AAClF,YAAA,OAAO,KAAK;QAChB;AAEA,QAAA,IAAI,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE;AACvD,YAAA,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAGA,uCAAiC,CAAC,OAAO,EAAEC,wCAAkC,CAAC,CAAC;AAC/G,YAAA,OAAO,KAAK;QAChB;AAEA,QAAA,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE;AACnD,YAAA,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAGD,uCAAiC,CAAC,KAAK,EAAEC,wCAAkC,CAAC,CAAC;AAC7G,YAAA,OAAO,KAAK;QAChB;AAEA,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE;QAEtB,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,IAAI,GAAG,MAAM,OAAO,KAAK,SAAS,IAAI,GAAG,GAAG,OAAO,CAAC,EAAE;AAC3F,YAAA,OAAO,IAAI;QACf;AAEA,QAAA,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS,EAAE;AACrC,YAAA,IAAI,UAA0B;AAC9B,YAAA,IAAI;gBACA,UAAU,GAAGC,kCAAwB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU,CAAC;YACpF;YAAE,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAC;AAC9C,gBAAA,OAAO,KAAK;YAChB;AACA,YAAA,OAAOC,yBAAe,CAAC,GAAG,EAAE,UAAU,CAAC;QAC3C;AAEA,QAAA,OAAO,KAAK;IAChB;AACH;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../src/filter/utils.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nexport const VALUE_OUT_OF_RANGE_ERROR_MESSAGE = \"The value is out of the accepted range.\";\nexport const UNRECOGNIZABLE_VALUE_ERROR_MESSAGE = \"The value is unrecognizable.\";\nexport const REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE = \"Value cannot be undefined or empty.\";\n\nexport function buildInvalidParameterErrorMessage(parameterName: string, additionalInfo?: string): string {\n return `The ${parameterName} parameter is not valid. ` + (additionalInfo ?? \"\");\n}\n"],"names":[],"mappings":";;AAAA;AACA;AAEO,MAAM,gCAAgC,GAAG,0CAA0C;AACnF,MAAM,kCAAkC,GAAG,+BAA+B;AAC1E,MAAM,wCAAwC,GAAG,sCAAsC;AAE9E,SAAA,iCAAiC,CAAC,aAAqB,EAAE,cAAuB,EAAA;IAC5F,OAAO,CAAA,IAAA,EAAO,aAAa,CAA2B,yBAAA,CAAA,IAAI,cAAc,IAAI,EAAE,CAAC,CAAC;AACpF;;;;;;;"}
1
+ {"version":3,"file":"utils.js","sources":["../../../src/filter/utils.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nexport const VALUE_OUT_OF_RANGE_ERROR_MESSAGE = \"The value is out of the accepted range.\";\nexport const UNRECOGNIZABLE_VALUE_ERROR_MESSAGE = \"The value is unrecognizable.\";\nexport const REQUIRED_PARAMETER_MISSING_ERROR_MESSAGE = \"Value cannot be undefined or empty.\";\n\nexport function buildInvalidParameterErrorMessage(parameterName: string, additionalInfo?: string): string {\n return `The ${parameterName} parameter is not valid. ` + (additionalInfo ?? \"\");\n}\n"],"names":[],"mappings":";;AAAA;AACA;AAEO,MAAM,gCAAgC,GAAG;AACzC,MAAM,kCAAkC,GAAG;AAC3C,MAAM,wCAAwC,GAAG;AAElD,SAAU,iCAAiC,CAAC,aAAqB,EAAE,cAAuB,EAAA;IAC5F,OAAO,CAAA,IAAA,EAAO,aAAa,CAAA,yBAAA,CAA2B,IAAI,cAAc,IAAI,EAAE,CAAC;AACnF;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sources":["../../../src/schema/model.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n// Converted from:\n// https://github.com/Azure/AppConfiguration/blob/6e544296a5607f922a423df165f60801717c7800/docs/FeatureManagement/FeatureFlag.v2.0.0.schema.json\n\n/**\n * A feature flag is a named property that can be toggled to enable or disable some feature of an application.\n */\nexport interface FeatureFlag {\n /**\n * An ID used to uniquely identify and reference the feature.\n */\n id: string;\n /**\n * A feature is OFF if enabled is false. If enabled is true, then the feature is ON if there are no conditions (null or empty) or if the conditions are satisfied.\n */\n enabled?: boolean;\n /**\n * The declaration of conditions used to dynamically enable the feature.\n */\n conditions?: FeatureEnablementConditions;\n /**\n * The list of variants defined for this feature. A variant represents a configuration value of a feature flag that can be a string, a number, a boolean, or a JSON object.\n */\n variants?: VariantDefinition[];\n /**\n * Determines how variants should be allocated for the feature to various users.\n */\n allocation?: VariantAllocation;\n /**\n * The declaration of options used to configure telemetry for this feature.\n */\n telemetry?: TelemetryOptions\n }\n\n /**\n * The declaration of conditions used to dynamically enable the feature\n */\n interface FeatureEnablementConditions {\n /**\n * Determines whether any or all registered client filters must be evaluated as true for the feature to be considered enabled.\n */\n requirement_type?: RequirementType;\n /**\n * Filters that must run on the client and be evaluated as true for the feature to be considered enabled.\n */\n client_filters?: ClientFilter[];\n }\n\n export type RequirementType = \"Any\" | \"All\";\n\n interface ClientFilter {\n /**\n * The name used to refer to a client filter.\n */\n name: string;\n /**\n * Parameters for a given client filter. A client filter can require any set of parameters of any type.\n */\n parameters?: Record<string, unknown>;\n }\n\n export interface VariantDefinition {\n /**\n * The name used to refer to a feature variant.\n */\n name: string;\n /**\n * The configuration value for this feature variant.\n */\n configuration_value?: unknown;\n /**\n * Overrides the enabled state of the feature if the given variant is assigned. Does not override the state if value is None.\n */\n status_override?: \"None\" | \"Enabled\" | \"Disabled\";\n }\n\n /**\n * Determines how variants should be allocated for the feature to various users.\n */\n interface VariantAllocation {\n /**\n * Specifies which variant should be used when the feature is considered disabled.\n */\n default_when_disabled?: string;\n /**\n * Specifies which variant should be used when the feature is considered enabled and no other allocation rules are applicable.\n */\n default_when_enabled?: string;\n /**\n * A list of objects, each containing a variant name and list of users for whom that variant should be used.\n */\n user?: UserAllocation[];\n /**\n * A list of objects, each containing a variant name and list of groups for which that variant should be used.\n */\n group?: GroupAllocation[];\n /**\n * A list of objects, each containing a variant name and percentage range for which that variant should be used.\n */\n percentile?: PercentileAllocation[]\n /**\n * The value percentile calculations are based on. The calculated percentile is consistent across features for a given user if the same nonempty seed is used.\n */\n seed?: string;\n }\n\n interface UserAllocation {\n /**\n * The name of the variant to use if the user allocation matches the current user.\n */\n variant: string;\n /**\n * Collection of users where if any match the current user, the variant specified in the user allocation is used.\n */\n users: string[];\n }\n\n interface GroupAllocation {\n /**\n * The name of the variant to use if the group allocation matches a group the current user is in.\n */\n variant: string;\n /**\n * Collection of groups where if the current user is in any of these groups, the variant specified in the group allocation is used.\n */\n groups: string[];\n }\n\n interface PercentileAllocation {\n /**\n * The name of the variant to use if the calculated percentile for the current user falls in the provided range.\n */\n variant: string;\n /**\n * The lower end of the percentage range for which this variant will be used.\n */\n from: number;\n /**\n * The upper end of the percentage range for which this variant will be used.\n */\n to: number;\n }\n\n /**\n * The declaration of options used to configure telemetry for this feature.\n */\n interface TelemetryOptions {\n /**\n * Indicates if telemetry is enabled.\n */\n enabled?: boolean;\n /**\n * A container for metadata that should be bundled with flag telemetry.\n */\n metadata?: Record<string, string>;\n }\n\n // Feature Management Section fed into feature manager.\n // Converted from https://github.com/Azure/AppConfiguration/blob/main/docs/FeatureManagement/FeatureManagement.v1.0.0.schema.json\n\n export const FEATURE_MANAGEMENT_KEY = \"feature_management\";\n export const FEATURE_FLAGS_KEY = \"feature_flags\";\n\n export interface FeatureManagementConfiguration {\n feature_management: FeatureManagement\n }\n\n /**\n * Declares feature management configuration.\n */\n export interface FeatureManagement {\n feature_flags: FeatureFlag[];\n }\n"],"names":[],"mappings":";;AAAA;AACA;AA8JE;AACA;AAEO,MAAM,sBAAsB,GAAG,qBAAqB;AACpD,MAAM,iBAAiB,GAAG;;;;;"}
1
+ {"version":3,"file":"model.js","sources":["../../../src/schema/model.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n// Converted from:\n// https://github.com/Azure/AppConfiguration/blob/6e544296a5607f922a423df165f60801717c7800/docs/FeatureManagement/FeatureFlag.v2.0.0.schema.json\n\n/**\n * A feature flag is a named property that can be toggled to enable or disable some feature of an application.\n */\nexport interface FeatureFlag {\n /**\n * An ID used to uniquely identify and reference the feature.\n */\n id: string;\n /**\n * A feature is OFF if enabled is false. If enabled is true, then the feature is ON if there are no conditions (null or empty) or if the conditions are satisfied.\n */\n enabled?: boolean;\n /**\n * The declaration of conditions used to dynamically enable the feature.\n */\n conditions?: FeatureEnablementConditions;\n /**\n * The list of variants defined for this feature. A variant represents a configuration value of a feature flag that can be a string, a number, a boolean, or a JSON object.\n */\n variants?: VariantDefinition[];\n /**\n * Determines how variants should be allocated for the feature to various users.\n */\n allocation?: VariantAllocation;\n /**\n * The declaration of options used to configure telemetry for this feature.\n */\n telemetry?: TelemetryOptions\n }\n\n /**\n * The declaration of conditions used to dynamically enable the feature\n */\n interface FeatureEnablementConditions {\n /**\n * Determines whether any or all registered client filters must be evaluated as true for the feature to be considered enabled.\n */\n requirement_type?: RequirementType;\n /**\n * Filters that must run on the client and be evaluated as true for the feature to be considered enabled.\n */\n client_filters?: ClientFilter[];\n }\n\n export type RequirementType = \"Any\" | \"All\";\n\n interface ClientFilter {\n /**\n * The name used to refer to a client filter.\n */\n name: string;\n /**\n * Parameters for a given client filter. A client filter can require any set of parameters of any type.\n */\n parameters?: Record<string, unknown>;\n }\n\n export interface VariantDefinition {\n /**\n * The name used to refer to a feature variant.\n */\n name: string;\n /**\n * The configuration value for this feature variant.\n */\n configuration_value?: unknown;\n /**\n * Overrides the enabled state of the feature if the given variant is assigned. Does not override the state if value is None.\n */\n status_override?: \"None\" | \"Enabled\" | \"Disabled\";\n }\n\n /**\n * Determines how variants should be allocated for the feature to various users.\n */\n interface VariantAllocation {\n /**\n * Specifies which variant should be used when the feature is considered disabled.\n */\n default_when_disabled?: string;\n /**\n * Specifies which variant should be used when the feature is considered enabled and no other allocation rules are applicable.\n */\n default_when_enabled?: string;\n /**\n * A list of objects, each containing a variant name and list of users for whom that variant should be used.\n */\n user?: UserAllocation[];\n /**\n * A list of objects, each containing a variant name and list of groups for which that variant should be used.\n */\n group?: GroupAllocation[];\n /**\n * A list of objects, each containing a variant name and percentage range for which that variant should be used.\n */\n percentile?: PercentileAllocation[]\n /**\n * The value percentile calculations are based on. The calculated percentile is consistent across features for a given user if the same nonempty seed is used.\n */\n seed?: string;\n }\n\n interface UserAllocation {\n /**\n * The name of the variant to use if the user allocation matches the current user.\n */\n variant: string;\n /**\n * Collection of users where if any match the current user, the variant specified in the user allocation is used.\n */\n users: string[];\n }\n\n interface GroupAllocation {\n /**\n * The name of the variant to use if the group allocation matches a group the current user is in.\n */\n variant: string;\n /**\n * Collection of groups where if the current user is in any of these groups, the variant specified in the group allocation is used.\n */\n groups: string[];\n }\n\n interface PercentileAllocation {\n /**\n * The name of the variant to use if the calculated percentile for the current user falls in the provided range.\n */\n variant: string;\n /**\n * The lower end of the percentage range for which this variant will be used.\n */\n from: number;\n /**\n * The upper end of the percentage range for which this variant will be used.\n */\n to: number;\n }\n\n /**\n * The declaration of options used to configure telemetry for this feature.\n */\n interface TelemetryOptions {\n /**\n * Indicates if telemetry is enabled.\n */\n enabled?: boolean;\n /**\n * A container for metadata that should be bundled with flag telemetry.\n */\n metadata?: Record<string, string>;\n }\n\n // Feature Management Section fed into feature manager.\n // Converted from https://github.com/Azure/AppConfiguration/blob/main/docs/FeatureManagement/FeatureManagement.v1.0.0.schema.json\n\n export const FEATURE_MANAGEMENT_KEY = \"feature_management\";\n export const FEATURE_FLAGS_KEY = \"feature_flags\";\n\n export interface FeatureManagementConfiguration {\n feature_management: FeatureManagement\n }\n\n /**\n * Declares feature management configuration.\n */\n export interface FeatureManagement {\n feature_flags: FeatureFlag[];\n }\n"],"names":[],"mappings":";;AAAA;AACA;AA8JE;AACA;AAEO,MAAM,sBAAsB,GAAG;AAC/B,MAAM,iBAAiB,GAAG;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"validator.js","sources":["../../../src/schema/validator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Validates a feature flag object, checking if it conforms to the schema.\n * @param featureFlag The feature flag object to validate.\n */\nexport function validateFeatureFlag(featureFlag: any): void {\n if (featureFlag === undefined) {\n return; // no-op if feature flag is undefined, indicating that the feature flag is not found\n }\n if (featureFlag === null || typeof featureFlag !== \"object\") { // Note: typeof null = \"object\"\n throw new TypeError(\"Feature flag must be an object.\");\n }\n if (typeof featureFlag.id !== \"string\") {\n throw new TypeError(\"Feature flag 'id' must be a string.\");\n }\n\n if (featureFlag.enabled !== undefined && typeof featureFlag.enabled !== \"boolean\") {\n throw new TypeError(`Invalid feature flag: ${featureFlag.id}. Feature flag 'enabled' must be a boolean.`);\n }\n if (featureFlag.conditions !== undefined) {\n validateFeatureEnablementConditions(featureFlag.id, featureFlag.conditions);\n }\n if (featureFlag.variants !== undefined) {\n validateVariants(featureFlag.id, featureFlag.variants);\n }\n if (featureFlag.allocation !== undefined) {\n validateVariantAllocation(featureFlag.id, featureFlag.allocation);\n }\n if (featureFlag.telemetry !== undefined) {\n validateTelemetryOptions(featureFlag.id, featureFlag.telemetry);\n }\n}\n\nfunction validateFeatureEnablementConditions(id: string, conditions: any) {\n if (typeof conditions !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag 'conditions' must be an object.`);\n }\n if (conditions.requirement_type !== undefined && conditions.requirement_type !== \"Any\" && conditions.requirement_type !== \"All\") {\n throw new TypeError(`Invalid feature flag: ${id}. 'requirement_type' must be 'Any' or 'All'.`);\n }\n if (conditions.client_filters !== undefined) {\n validateClientFilters(id, conditions.client_filters);\n }\n}\n\nfunction validateClientFilters(id: string, client_filters: any) {\n if (!Array.isArray(client_filters)) {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag conditions 'client_filters' must be an array.`);\n }\n\n for (const filter of client_filters) {\n if (typeof filter.name !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Client filter 'name' must be a string.`);\n }\n if (filter.parameters !== undefined && typeof filter.parameters !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Client filter 'parameters' must be an object.`);\n }\n }\n}\n\nfunction validateVariants(id: string, variants: any) {\n if (!Array.isArray(variants)) {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag 'variants' must be an array.`);\n }\n\n for (const variant of variants) {\n if (typeof variant.name !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'name' must be a string.`);\n }\n // skip configuration_value validation as it accepts any type\n if (variant.status_override !== undefined && typeof variant.status_override !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'status_override' must be a string.`);\n }\n if (variant.status_override !== undefined && variant.status_override !== \"None\" && variant.status_override !== \"Enabled\" && variant.status_override !== \"Disabled\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'status_override' must be 'None', 'Enabled', or 'Disabled'.`);\n }\n }\n}\n\nfunction validateVariantAllocation(id: string, allocation: any) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'allocation' must be an object.`);\n }\n\n if (allocation.default_when_disabled !== undefined && typeof allocation.default_when_disabled !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant allocation 'default_when_disabled' must be a string.`);\n }\n if (allocation.default_when_enabled !== undefined && typeof allocation.default_when_enabled !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant allocation 'default_when_enabled' must be a string.`);\n }\n if (allocation.user !== undefined) {\n validateUserVariantAllocation(id, allocation.user);\n }\n if (allocation.group !== undefined) {\n validateGroupVariantAllocation(id, allocation.group);\n }\n if (allocation.percentile !== undefined) {\n validatePercentileVariantAllocation(id, allocation.percentile);\n }\n if (allocation.seed !== undefined && typeof allocation.seed !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant allocation 'seed' must be a string.`);\n }\n}\n\nfunction validateUserVariantAllocation(id: string, UserAllocations: any) {\n if (!Array.isArray(UserAllocations)) {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'user' allocation must be an array.`);\n }\n\n for (const allocation of UserAllocations) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in variant 'user' allocation must be an object.`);\n }\n if (typeof allocation.variant !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. User allocation 'variant' must be a string.`);\n }\n if (!Array.isArray(allocation.users)) {\n throw new TypeError(`Invalid feature flag: ${id}. User allocation 'users' must be an array.`);\n }\n for (const user of allocation.users) {\n if (typeof user !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in user allocation 'users' must be strings.`);\n }\n }\n }\n}\n\nfunction validateGroupVariantAllocation(id: string, groupAllocations: any) {\n if (!Array.isArray(groupAllocations)) {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'group' allocation must be an array.`);\n }\n\n for (const allocation of groupAllocations) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in variant 'group' allocation must be an object.`);\n }\n if (typeof allocation.variant !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Group allocation 'variant' must be a string.`);\n }\n if (!Array.isArray(allocation.groups)) {\n throw new TypeError(`Invalid feature flag: ${id}. Group allocation 'groups' must be an array.`);\n }\n for (const group of allocation.groups) {\n if (typeof group !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in group allocation 'groups' must be strings.`);\n }\n }\n }\n}\n\nfunction validatePercentileVariantAllocation(id: string, percentileAllocations: any) {\n if (!Array.isArray(percentileAllocations)) {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'percentile' allocation must be an array.`);\n }\n\n for (const allocation of percentileAllocations) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in variant 'percentile' allocation must be an object.`);\n }\n if (typeof allocation.variant !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Percentile allocation 'variant' must be a string.`);\n }\n if (typeof allocation.from !== \"number\" || allocation.from < 0 || allocation.from > 100) {\n throw new TypeError(`Invalid feature flag: ${id}. Percentile allocation 'from' must be a number between 0 and 100.`);\n }\n if (typeof allocation.to !== \"number\" || allocation.to < 0 || allocation.to > 100) {\n throw new TypeError(`Invalid feature flag: ${id}. Percentile allocation 'to' must be a number between 0 and 100.`);\n }\n }\n}\n// #endregion\n\n// #region Telemetry\nfunction validateTelemetryOptions(id: string, telemetry: any) {\n if (typeof telemetry !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag 'telemetry' must be an object.`);\n }\n if (telemetry.enabled !== undefined && typeof telemetry.enabled !== \"boolean\") {\n throw new TypeError(`Invalid feature flag: ${id}. Telemetry 'enabled' must be a boolean.`);\n }\n if (telemetry.metadata !== undefined && typeof telemetry.metadata !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Telemetry 'metadata' must be an object.`);\n }\n}\n// #endregion\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validator.js","sources":["../../../src/schema/validator.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Validates a feature flag object, checking if it conforms to the schema.\n * @param featureFlag The feature flag object to validate.\n */\nexport function validateFeatureFlag(featureFlag: any): void {\n if (featureFlag === undefined) {\n return; // no-op if feature flag is undefined, indicating that the feature flag is not found\n }\n if (featureFlag === null || typeof featureFlag !== \"object\") { // Note: typeof null = \"object\"\n throw new TypeError(\"Feature flag must be an object.\");\n }\n if (typeof featureFlag.id !== \"string\") {\n throw new TypeError(\"Feature flag 'id' must be a string.\");\n }\n\n if (featureFlag.enabled !== undefined && typeof featureFlag.enabled !== \"boolean\") {\n throw new TypeError(`Invalid feature flag: ${featureFlag.id}. Feature flag 'enabled' must be a boolean.`);\n }\n if (featureFlag.conditions !== undefined) {\n validateFeatureEnablementConditions(featureFlag.id, featureFlag.conditions);\n }\n if (featureFlag.variants !== undefined) {\n validateVariants(featureFlag.id, featureFlag.variants);\n }\n if (featureFlag.allocation !== undefined) {\n validateVariantAllocation(featureFlag.id, featureFlag.allocation);\n }\n if (featureFlag.telemetry !== undefined) {\n validateTelemetryOptions(featureFlag.id, featureFlag.telemetry);\n }\n}\n\nfunction validateFeatureEnablementConditions(id: string, conditions: any) {\n if (typeof conditions !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag 'conditions' must be an object.`);\n }\n if (conditions.requirement_type !== undefined && conditions.requirement_type !== \"Any\" && conditions.requirement_type !== \"All\") {\n throw new TypeError(`Invalid feature flag: ${id}. 'requirement_type' must be 'Any' or 'All'.`);\n }\n if (conditions.client_filters !== undefined) {\n validateClientFilters(id, conditions.client_filters);\n }\n}\n\nfunction validateClientFilters(id: string, client_filters: any) {\n if (!Array.isArray(client_filters)) {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag conditions 'client_filters' must be an array.`);\n }\n\n for (const filter of client_filters) {\n if (typeof filter.name !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Client filter 'name' must be a string.`);\n }\n if (filter.parameters !== undefined && typeof filter.parameters !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Client filter 'parameters' must be an object.`);\n }\n }\n}\n\nfunction validateVariants(id: string, variants: any) {\n if (!Array.isArray(variants)) {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag 'variants' must be an array.`);\n }\n\n for (const variant of variants) {\n if (typeof variant.name !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'name' must be a string.`);\n }\n // skip configuration_value validation as it accepts any type\n if (variant.status_override !== undefined && typeof variant.status_override !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'status_override' must be a string.`);\n }\n if (variant.status_override !== undefined && variant.status_override !== \"None\" && variant.status_override !== \"Enabled\" && variant.status_override !== \"Disabled\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'status_override' must be 'None', 'Enabled', or 'Disabled'.`);\n }\n }\n}\n\nfunction validateVariantAllocation(id: string, allocation: any) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'allocation' must be an object.`);\n }\n\n if (allocation.default_when_disabled !== undefined && typeof allocation.default_when_disabled !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant allocation 'default_when_disabled' must be a string.`);\n }\n if (allocation.default_when_enabled !== undefined && typeof allocation.default_when_enabled !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant allocation 'default_when_enabled' must be a string.`);\n }\n if (allocation.user !== undefined) {\n validateUserVariantAllocation(id, allocation.user);\n }\n if (allocation.group !== undefined) {\n validateGroupVariantAllocation(id, allocation.group);\n }\n if (allocation.percentile !== undefined) {\n validatePercentileVariantAllocation(id, allocation.percentile);\n }\n if (allocation.seed !== undefined && typeof allocation.seed !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Variant allocation 'seed' must be a string.`);\n }\n}\n\nfunction validateUserVariantAllocation(id: string, UserAllocations: any) {\n if (!Array.isArray(UserAllocations)) {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'user' allocation must be an array.`);\n }\n\n for (const allocation of UserAllocations) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in variant 'user' allocation must be an object.`);\n }\n if (typeof allocation.variant !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. User allocation 'variant' must be a string.`);\n }\n if (!Array.isArray(allocation.users)) {\n throw new TypeError(`Invalid feature flag: ${id}. User allocation 'users' must be an array.`);\n }\n for (const user of allocation.users) {\n if (typeof user !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in user allocation 'users' must be strings.`);\n }\n }\n }\n}\n\nfunction validateGroupVariantAllocation(id: string, groupAllocations: any) {\n if (!Array.isArray(groupAllocations)) {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'group' allocation must be an array.`);\n }\n\n for (const allocation of groupAllocations) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in variant 'group' allocation must be an object.`);\n }\n if (typeof allocation.variant !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Group allocation 'variant' must be a string.`);\n }\n if (!Array.isArray(allocation.groups)) {\n throw new TypeError(`Invalid feature flag: ${id}. Group allocation 'groups' must be an array.`);\n }\n for (const group of allocation.groups) {\n if (typeof group !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in group allocation 'groups' must be strings.`);\n }\n }\n }\n}\n\nfunction validatePercentileVariantAllocation(id: string, percentileAllocations: any) {\n if (!Array.isArray(percentileAllocations)) {\n throw new TypeError(`Invalid feature flag: ${id}. Variant 'percentile' allocation must be an array.`);\n }\n\n for (const allocation of percentileAllocations) {\n if (typeof allocation !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Elements in variant 'percentile' allocation must be an object.`);\n }\n if (typeof allocation.variant !== \"string\") {\n throw new TypeError(`Invalid feature flag: ${id}. Percentile allocation 'variant' must be a string.`);\n }\n if (typeof allocation.from !== \"number\" || allocation.from < 0 || allocation.from > 100) {\n throw new TypeError(`Invalid feature flag: ${id}. Percentile allocation 'from' must be a number between 0 and 100.`);\n }\n if (typeof allocation.to !== \"number\" || allocation.to < 0 || allocation.to > 100) {\n throw new TypeError(`Invalid feature flag: ${id}. Percentile allocation 'to' must be a number between 0 and 100.`);\n }\n }\n}\n// #endregion\n\n// #region Telemetry\nfunction validateTelemetryOptions(id: string, telemetry: any) {\n if (typeof telemetry !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Feature flag 'telemetry' must be an object.`);\n }\n if (telemetry.enabled !== undefined && typeof telemetry.enabled !== \"boolean\") {\n throw new TypeError(`Invalid feature flag: ${id}. Telemetry 'enabled' must be a boolean.`);\n }\n if (telemetry.metadata !== undefined && typeof telemetry.metadata !== \"object\") {\n throw new TypeError(`Invalid feature flag: ${id}. Telemetry 'metadata' must be an object.`);\n }\n}\n// #endregion\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"featureEvaluationEvent.js","sources":["../../../src/telemetry/featureEvaluationEvent.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { EvaluationResult, VariantAssignmentReason } from \"../featureManager\";\nimport { EVALUATION_EVENT_VERSION } from \"../version.js\";\n\nconst VERSION = \"Version\";\nconst FEATURE_NAME = \"FeatureName\";\nconst ENABLED = \"Enabled\";\nconst TARGETING_ID = \"TargetingId\";\nconst VARIANT = \"Variant\";\nconst VARIANT_ASSIGNMENT_REASON = \"VariantAssignmentReason\";\nconst DEFAULT_WHEN_ENABLED = \"DefaultWhenEnabled\";\nconst VARIANT_ASSIGNMENT_PERCENTAGE = \"VariantAssignmentPercentage\";\n\nexport function createFeatureEvaluationEventProperties(result: EvaluationResult): any {\n if (result.feature === undefined) {\n return undefined;\n }\n\n const eventProperties = {\n [VERSION]: EVALUATION_EVENT_VERSION,\n [FEATURE_NAME]: result.feature ? result.feature.id : \"\",\n [ENABLED]: result.enabled ? \"True\" : \"False\",\n // Ensure targetingId is string so that it will be placed in customDimensions\n [TARGETING_ID]: result.targetingId ? result.targetingId.toString() : \"\",\n [VARIANT]: result.variant ? result.variant.name : \"\",\n [VARIANT_ASSIGNMENT_REASON]: result.variantAssignmentReason,\n };\n\n if (result.feature.allocation?.default_when_enabled) {\n eventProperties[DEFAULT_WHEN_ENABLED] = result.feature.allocation.default_when_enabled;\n }\n\n if (result.variantAssignmentReason === VariantAssignmentReason.DefaultWhenEnabled) {\n let percentileAllocationPercentage = 0;\n if (result.variant !== undefined && result.feature.allocation !== undefined && result.feature.allocation.percentile !== undefined) {\n for (const percentile of result.feature.allocation.percentile) {\n percentileAllocationPercentage += percentile.to - percentile.from;\n }\n }\n eventProperties[VARIANT_ASSIGNMENT_PERCENTAGE] = (100 - percentileAllocationPercentage).toString();\n }\n else if (result.variantAssignmentReason === VariantAssignmentReason.Percentile) {\n let percentileAllocationPercentage = 0;\n if (result.variant !== undefined && result.feature.allocation !== undefined && result.feature.allocation.percentile !== undefined) {\n for (const percentile of result.feature.allocation.percentile) {\n if (percentile.variant === result.variant.name) {\n percentileAllocationPercentage += percentile.to - percentile.from;\n }\n }\n }\n eventProperties[VARIANT_ASSIGNMENT_PERCENTAGE] = percentileAllocationPercentage.toString();\n }\n\n const metadata = result.feature.telemetry?.metadata;\n if (metadata) {\n for (const key in metadata) {\n if (!(key in eventProperties)) {\n eventProperties[key] = metadata[key];\n }\n }\n }\n\n return eventProperties;\n}\n"],"names":["EVALUATION_EVENT_VERSION","VariantAssignmentReason"],"mappings":"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"}
1
+ {"version":3,"file":"featureEvaluationEvent.js","sources":["../../../src/telemetry/featureEvaluationEvent.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { EvaluationResult, VariantAssignmentReason } from \"../featureManager.js\";\nimport { EVALUATION_EVENT_VERSION } from \"../version.js\";\n\nconst VERSION = \"Version\";\nconst FEATURE_NAME = \"FeatureName\";\nconst ENABLED = \"Enabled\";\nconst TARGETING_ID = \"TargetingId\";\nconst VARIANT = \"Variant\";\nconst VARIANT_ASSIGNMENT_REASON = \"VariantAssignmentReason\";\nconst DEFAULT_WHEN_ENABLED = \"DefaultWhenEnabled\";\nconst VARIANT_ASSIGNMENT_PERCENTAGE = \"VariantAssignmentPercentage\";\n\nexport function createFeatureEvaluationEventProperties(result: EvaluationResult): any {\n if (result.feature === undefined) {\n return undefined;\n }\n\n const eventProperties = {\n [VERSION]: EVALUATION_EVENT_VERSION,\n [FEATURE_NAME]: result.feature ? result.feature.id : \"\",\n [ENABLED]: result.enabled ? \"True\" : \"False\",\n // Ensure targetingId is string so that it will be placed in customDimensions\n [TARGETING_ID]: result.targetingId ? result.targetingId.toString() : \"\",\n [VARIANT]: result.variant ? result.variant.name : \"\",\n [VARIANT_ASSIGNMENT_REASON]: result.variantAssignmentReason,\n };\n\n if (result.feature.allocation?.default_when_enabled) {\n eventProperties[DEFAULT_WHEN_ENABLED] = result.feature.allocation.default_when_enabled;\n }\n\n if (result.variantAssignmentReason === VariantAssignmentReason.DefaultWhenEnabled) {\n let percentileAllocationPercentage = 0;\n if (result.variant !== undefined && result.feature.allocation !== undefined && result.feature.allocation.percentile !== undefined) {\n for (const percentile of result.feature.allocation.percentile) {\n percentileAllocationPercentage += percentile.to - percentile.from;\n }\n }\n eventProperties[VARIANT_ASSIGNMENT_PERCENTAGE] = (100 - percentileAllocationPercentage).toString();\n }\n else if (result.variantAssignmentReason === VariantAssignmentReason.Percentile) {\n let percentileAllocationPercentage = 0;\n if (result.variant !== undefined && result.feature.allocation !== undefined && result.feature.allocation.percentile !== undefined) {\n for (const percentile of result.feature.allocation.percentile) {\n if (percentile.variant === result.variant.name) {\n percentileAllocationPercentage += percentile.to - percentile.from;\n }\n }\n }\n eventProperties[VARIANT_ASSIGNMENT_PERCENTAGE] = percentileAllocationPercentage.toString();\n }\n\n const metadata = result.feature.telemetry?.metadata;\n if (metadata) {\n for (const key in metadata) {\n if (!(key in eventProperties)) {\n eventProperties[key] = metadata[key];\n }\n }\n }\n\n return eventProperties;\n}\n"],"names":["EVALUATION_EVENT_VERSION","VariantAssignmentReason"],"mappings":"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"}